1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Provides a work around for various adb commands on android gce instances.
7 Some adb commands don't work well when the device is a cloud vm, namely
8 'push' and 'pull'. With gce instances, moving files through adb can be
9 painfully slow and hit timeouts, so the methods here just use scp instead.
11 # pylint: disable=unused-argument
17 from devil
.android
import device_errors
18 from devil
.android
.sdk
import adb_wrapper
19 from devil
.utils
import cmd_helper
21 logger
= logging
.getLogger(__name__
)
24 class GceAdbWrapper(adb_wrapper
.AdbWrapper
):
26 def __init__(self
, device_serial
):
27 super(GceAdbWrapper
, self
).__init
__(device_serial
)
30 self
._instance
_ip
= self
.Shell('getprop net.gce.ip').strip()
32 def _Connect(self
, timeout
=adb_wrapper
.DEFAULT_TIMEOUT
,
33 retries
=adb_wrapper
.DEFAULT_RETRIES
):
34 """Connects ADB to the android gce instance."""
35 cmd
= ['connect', self
._device
_serial
]
36 output
= self
._RunAdbCmd
(cmd
, timeout
=timeout
, retries
=retries
)
37 if 'unable to connect' in output
:
38 raise device_errors
.AdbCommandFailedError(cmd
, output
)
42 def Root(self
, **kwargs
):
43 super(GceAdbWrapper
, self
).Root()
47 def Push(self
, local
, remote
, **kwargs
):
48 """Pushes an object from the host to the gce instance.
51 local: Path on the host filesystem.
52 remote: Path on the instance filesystem.
54 adb_wrapper
.VerifyLocalFileExists(local
)
55 if os
.path
.isdir(local
):
56 self
.Shell('mkdir -p %s' % cmd_helper
.SingleQuote(remote
))
58 # When the object to be pushed is a directory, adb merges the source dir
59 # with the destination dir. So if local is a dir, just scp its contents.
60 for f
in os
.listdir(local
):
61 self
._PushObject
(os
.path
.join(local
, f
), os
.path
.join(remote
, f
))
62 self
.Shell('chmod 777 %s' %
63 cmd_helper
.SingleQuote(os
.path
.join(remote
, f
)))
65 parent_dir
= remote
[0:remote
.rfind('/')]
67 self
.Shell('mkdir -p %s' % cmd_helper
.SingleQuote(parent_dir
))
68 self
._PushObject
(local
, remote
)
69 self
.Shell('chmod 777 %s' % cmd_helper
.SingleQuote(remote
))
71 def _PushObject(self
, local
, remote
):
72 """Copies an object from the host to the gce instance using scp.
75 local: Path on the host filesystem.
76 remote: Path on the instance filesystem.
81 '-o', 'UserKnownHostsFile=/dev/null',
82 '-o', 'StrictHostKeyChecking=no',
84 'root@%s:%s' % (self
._instance
_ip
, remote
)
86 status
, _
= cmd_helper
.GetCmdStatusAndOutput(cmd
)
88 raise device_errors
.AdbCommandFailedError(
89 cmd
, 'File not reachable on host: %s' % local
,
90 device_serial
=str(self
))
93 def Pull(self
, remote
, local
, **kwargs
):
94 """Pulls a file from the gce instance to the host.
97 remote: Path on the instance filesystem.
98 local: Path on the host filesystem.
104 '-o', 'UserKnownHostsFile=/dev/null',
105 '-o', 'StrictHostKeyChecking=no',
106 'root@%s:%s' % (self
._instance
_ip
, remote
),
109 status
, _
= cmd_helper
.GetCmdStatusAndOutput(cmd
)
111 raise device_errors
.AdbCommandFailedError(
112 cmd
, 'File not reachable on host: %s' % local
,
113 device_serial
=str(self
))
116 adb_wrapper
.VerifyLocalFileExists(local
)
117 except (subprocess
.CalledProcessError
, IOError):
118 logger
.exception('Error when pulling files from android instance.')
119 raise device_errors
.AdbCommandFailedError(
120 cmd
, 'File not reachable on host: %s' % local
,
121 device_serial
=str(self
))
124 def Install(self
, apk_path
, forward_lock
=False, reinstall
=False,
125 sd_card
=False, **kwargs
):
126 """Installs an apk on the gce instance
129 apk_path: Host path to the APK file.
130 forward_lock: (optional) If set forward-locks the app.
131 reinstall: (optional) If set reinstalls the app, keeping its data.
132 sd_card: (optional) If set installs on the SD card.
134 adb_wrapper
.VerifyLocalFileExists(apk_path
)
142 self
.Push(apk_path
, '/data/local/tmp/tmp.apk')
144 cmd
.append('/data/local/tmp/tmp.apk')
145 output
= self
.Shell(' '.join(cmd
))
146 self
.Shell('rm /data/local/tmp/tmp.apk')
147 if 'Success' not in output
:
148 raise device_errors
.AdbCommandFailedError(
149 cmd
, output
, device_serial
=self
._device
_serial
)
153 def is_emulator(self
):