xref: /aosp_15_r20/external/chromium-trace/catapult/devil/devil/android/device_utils_test.py (revision 1fa4b3da657c0e9ad43c0220bacf9731820715a5)
1#!/usr/bin/env python
2# Copyright 2014 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5"""
6Unit tests for the contents of device_utils.py (mostly DeviceUtils).
7"""
8
9# pylint: disable=protected-access
10# pylint: disable=unused-argument
11
12import collections
13import contextlib
14import io
15import json
16import logging
17import os
18import posixpath
19import stat
20import sys
21import unittest
22
23import six
24
25from devil import devil_env
26from devil.android import device_errors
27from devil.android import device_signal
28from devil.android import device_utils
29from devil.android.ndk import abis
30from devil.android.sdk import adb_wrapper
31from devil.android.sdk import intent
32from devil.android.sdk import keyevent
33from devil.android.sdk import version_codes
34from devil.utils import cmd_helper
35from devil.utils import mock_calls
36
37with devil_env.SysPath(os.path.join(devil_env.PY_UTILS_PATH)):
38  from py_utils import tempfile_ext
39
40with devil_env.SysPath(devil_env.PYMOCK_PATH):
41  import mock  # pylint: disable=import-error
42
43TEST_APK_PATH = '/fake/test/app.apk'
44TEST_PACKAGE = 'test.package'
45
46
47def Process(name, pid, ppid='1'):
48  return device_utils.ProcessInfo(name=name, pid=pid, ppid=ppid)
49
50
51def Processes(*args):
52  return [Process(*arg) for arg in args]
53
54
55class AnyStringWith(object):
56  def __init__(self, value):
57    self._value = value
58
59  def __eq__(self, other):
60    return self._value in other
61
62  def __repr__(self):
63    return '<AnyStringWith: %s>' % self._value
64
65
66class _FakeContextManager(object):
67  def __init__(self, obj):
68    self._obj = obj
69
70  def __enter__(self):
71    return self._obj
72
73  def __exit__(self, type_, value, traceback):
74    pass
75
76
77class _MockApkHelper(object):
78  def __init__(self, path, package_name, perms=None, splits=None):
79    self.path = path
80    self.is_bundle = path.endswith('_bundle')
81    self.package_name = package_name
82    self.perms = perms
83    self.splits = splits if splits else []
84    self.abis = [abis.ARM]
85    self.version_code = None
86
87  def GetPackageName(self):
88    return self.package_name
89
90  def GetPermissions(self):
91    return self.perms
92
93  def GetVersionCode(self):
94    return self.version_code
95
96  def GetAbis(self):
97    return self.abis
98
99  def GetApkPaths(self,
100                  device,
101                  modules=None,
102                  allow_cached_props=False,
103                  additional_locales=None):
104    return _FakeContextManager([self.path] + self.splits)
105
106  #override
107  @staticmethod
108  def SupportsSplits():
109    return True
110
111
112class _MockMultipleDevicesError(Exception):
113  pass
114
115
116class DeviceUtilsInitTest(unittest.TestCase):
117  def testInitWithStr(self):
118    serial_as_str = str('0123456789abcdef')
119    d = device_utils.DeviceUtils('0123456789abcdef')
120    self.assertEqual(serial_as_str, d.adb.GetDeviceSerial())
121
122  def testInitWithUnicode(self):
123    if six.PY2:
124      serial_as_unicode = unicode('fedcba9876543210')
125      d = device_utils.DeviceUtils(serial_as_unicode)
126      self.assertEqual(serial_as_unicode, d.adb.GetDeviceSerial())
127
128  def testInitWithAdbWrapper(self):
129    serial = '123456789abcdef0'
130    a = adb_wrapper.AdbWrapper(serial)
131    d = device_utils.DeviceUtils(a)
132    self.assertEqual(serial, d.adb.GetDeviceSerial())
133
134  def testInitWithMissing_fails(self):
135    with self.assertRaises(ValueError):
136      device_utils.DeviceUtils(None)
137    with self.assertRaises(ValueError):
138      device_utils.DeviceUtils('')
139
140
141class DeviceUtilsGetAVDsTest(mock_calls.TestCase):
142  def testGetAVDs(self):
143    mocked_attrs = {'android_sdk': '/my/sdk/path'}
144    with mock.patch('devil.devil_env._Environment.LocalPath',
145                    mock.Mock(side_effect=lambda a: mocked_attrs[a])):
146      with self.assertCall(
147          mock.call.devil.utils.cmd_helper.GetCmdOutput(
148              [mock.ANY, 'list', 'avd']), 'Available Android Virtual Devices:\n'
149          '    Name: my_android5.0\n'
150          '    Path: /some/path/to/.android/avd/my_android5.0.avd\n'
151          '  Target: Android 5.0 (API level 21)\n'
152          ' Tag/ABI: default/x86\n'
153          '    Skin: WVGA800\n'):
154        self.assertEquals(['my_android5.0'], device_utils.GetAVDs())
155
156
157class DeviceUtilsRestartServerTest(mock_calls.TestCase):
158  @mock.patch('time.sleep', mock.Mock())
159  def testRestartServer_succeeds(self):
160    with self.assertCalls(
161        mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.KillServer(),
162        (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutput(
163            ['pgrep', 'adb']), (1, '')),
164        mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.StartServer(),
165        (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutput(
166            ['pgrep', 'adb']),
167         (1, '')), (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutput(
168             ['pgrep', 'adb']), (0, '123\n'))):
169      adb_wrapper.RestartServer()
170
171
172class MockTempFile(object):
173  def __init__(self, name='/tmp/some/file'):
174    self.file = mock.MagicMock(spec=io.BufferedIOBase)
175    self.file.name = name
176    self.file.name_quoted = cmd_helper.SingleQuote(name)
177
178  def __enter__(self):
179    return self.file
180
181  def __exit__(self, exc_type, exc_val, exc_tb):
182    pass
183
184  @property
185  def name(self):
186    return self.file.name
187
188
189class MockLogger(mock.Mock):
190  def __init__(self, *args, **kwargs):
191    super(MockLogger, self).__init__(*args, **kwargs)
192    self.warnings = []
193
194  def warning(self, message, *args):
195    self.warnings.append(message % args)
196
197
198def PatchLogger():
199  return mock.patch(
200      'devil.android.device_utils.logger', new_callable=MockLogger)
201
202
203class _PatchedFunction(object):
204  def __init__(self, patched=None, mocked=None):
205    self.patched = patched
206    self.mocked = mocked
207
208
209def _AdbWrapperMock(test_serial, is_ready=True):
210  adb = mock.Mock(spec=adb_wrapper.AdbWrapper)
211  adb.__str__ = mock.Mock(return_value=test_serial)
212  adb.GetDeviceSerial.return_value = test_serial
213  adb.is_ready = is_ready
214  return adb
215
216
217class DeviceUtilsTest(mock_calls.TestCase):
218  def setUp(self):
219    self.adb = _AdbWrapperMock('0123456789abcdef')
220    self.device = device_utils.DeviceUtils(
221        self.adb, default_timeout=10, default_retries=0)
222    self.watchMethodCalls(self.call.adb, ignore=['GetDeviceSerial'])
223
224  def safeAssertItemsEqual(self, expected, actual):
225    if six.PY2:
226      self.assertItemsEqual(expected, actual)
227    else:
228      self.assertCountEqual(expected, actual) # pylint: disable=no-member
229
230  def AdbCommandError(self, args=None, output=None, status=None, msg=None):
231    if args is None:
232      args = ['[unspecified]']
233    return mock.Mock(
234        side_effect=device_errors.AdbCommandFailedError(args, output, status,
235                                                        msg, str(self.device)))
236
237  def CommandError(self, msg=None):
238    if msg is None:
239      msg = 'Command failed'
240    return mock.Mock(
241        side_effect=device_errors.CommandFailedError(msg, str(self.device)))
242
243  def ShellError(self, output=None, status=1):
244    def action(cmd, *args, **kwargs):
245      raise device_errors.AdbShellCommandFailedError(cmd, output, status,
246                                                     str(self.device))
247
248    if output is None:
249      output = 'Permission denied\n'
250    return action
251
252  def TimeoutError(self, msg=None):
253    if msg is None:
254      msg = 'Operation timed out'
255    return mock.Mock(
256        side_effect=device_errors.CommandTimeoutError(msg, str(self.device)))
257
258  def EnsureCacheInitialized(self, props=None, sdcard='/sdcard'):
259    props = props or []
260    ret = [sdcard, 'TOKEN'] + props
261    return (self.call.device.RunShellCommand(
262        AnyStringWith('getprop'),
263        shell=True,
264        check_return=True,
265        large_output=True), ret)
266
267
268class DeviceUtilsEqTest(DeviceUtilsTest):
269  def testEq_equal_deviceUtils(self):
270    other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdef'))
271    self.assertTrue(self.device == other)
272    self.assertTrue(other == self.device)
273
274  def testEq_equal_adbWrapper(self):
275    other = adb_wrapper.AdbWrapper('0123456789abcdef')
276    self.assertTrue(self.device == other)
277    self.assertTrue(other == self.device)
278
279  def testEq_equal_string(self):
280    other = '0123456789abcdef'
281    self.assertTrue(self.device == other)
282    self.assertTrue(other == self.device)
283
284  def testEq_devicesNotEqual(self):
285    other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdee'))
286    self.assertFalse(self.device == other)
287    self.assertFalse(other == self.device)
288
289  def testEq_identity(self):
290    self.assertTrue(self.device == self.device)
291
292  def testEq_serialInList(self):
293    devices = [self.device]
294    self.assertTrue('0123456789abcdef' in devices)
295
296
297class DeviceUtilsLtTest(DeviceUtilsTest):
298  def testLt_lessThan(self):
299    other = device_utils.DeviceUtils(_AdbWrapperMock('ffffffffffffffff'))
300    self.assertTrue(self.device < other)
301    self.assertTrue(other > self.device)
302
303  def testLt_greaterThan_lhs(self):
304    other = device_utils.DeviceUtils(_AdbWrapperMock('0000000000000000'))
305    self.assertFalse(self.device < other)
306    self.assertFalse(other > self.device)
307
308  def testLt_equal(self):
309    other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdef'))
310    self.assertFalse(self.device < other)
311    self.assertFalse(other > self.device)
312
313  def testLt_sorted(self):
314    devices = [
315        device_utils.DeviceUtils(_AdbWrapperMock('ffffffffffffffff')),
316        device_utils.DeviceUtils(_AdbWrapperMock('0000000000000000')),
317    ]
318    sorted_devices = sorted(devices)
319    self.assertEquals('0000000000000000',
320                      sorted_devices[0].adb.GetDeviceSerial())
321    self.assertEquals('ffffffffffffffff',
322                      sorted_devices[1].adb.GetDeviceSerial())
323
324
325class DeviceUtilsStrTest(DeviceUtilsTest):
326  def testStr_returnsSerial(self):
327    with self.assertCalls((self.call.adb.GetDeviceSerial(),
328                           '0123456789abcdef')):
329      self.assertEqual('0123456789abcdef', str(self.device))
330
331
332class DeviceUtilsIsOnlineTest(DeviceUtilsTest):
333  def testIsOnline_true(self):
334    with self.assertCall(self.call.adb.GetState(), 'device'):
335      self.assertTrue(self.device.IsOnline())
336
337  def testIsOnline_false(self):
338    with self.assertCall(self.call.adb.GetState(), 'offline'):
339      self.assertFalse(self.device.IsOnline())
340
341  def testIsOnline_error(self):
342    with self.assertCall(self.call.adb.GetState(), self.CommandError()):
343      self.assertFalse(self.device.IsOnline())
344
345
346class DeviceUtilsHasRootTest(DeviceUtilsTest):
347  def testHasRoot_true(self):
348    with self.patch_call(self.call.device.build_type,
349                         return_value='userdebug'), (self.assertCall(
350                             self.call.adb.Shell('id'), 'uid=0(root)\n')):
351      self.assertTrue(self.device.HasRoot())
352
353  def testHasRootEngBuild_true(self):
354    with self.patch_call(self.call.device.build_type, return_value='eng'):
355      self.assertTrue(self.device.HasRoot())
356
357  def testHasRoot_false(self):
358    with self.patch_call(self.call.device.build_type,
359                         return_value='userdebug'), (self.assertCall(
360                             self.call.adb.Shell('id'), 'uid=2000(shell)\n')):
361      self.assertFalse(self.device.HasRoot())
362
363
364class DeviceUtilsEnableRootTest(DeviceUtilsTest):
365  def testEnableRoot_succeeds(self):
366    with self.assertCalls(self.call.adb.Root(), self.call.adb.WaitForDevice(),
367                          (self.call.device.HasRoot(), True)):
368      self.device.EnableRoot()
369
370  def testEnableRoot_userBuild(self):
371    with self.assertCalls((self.call.adb.Root(), self.AdbCommandError()),
372                          (self.call.device.IsUserBuild(), True)):
373      with self.assertRaises(device_errors.CommandFailedError):
374        self.device.EnableRoot()
375
376  def testEnableRoot_rootFails(self):
377    with self.assertCalls((self.call.adb.Root(), self.AdbCommandError()),
378                          (self.call.device.IsUserBuild(), False)):
379      with self.assertRaises(device_errors.AdbCommandFailedError):
380        self.device.EnableRoot()
381
382  def testEnableRoot_timeoutInWaitForDevice(self):
383    with self.assertCalls(
384        (self.call.adb.Root(),
385         self.AdbCommandError(
386             output='timeout expired while waiting for device')),
387        (self.call.device.IsUserBuild(), False), self.call.adb.WaitForDevice(),
388        (self.call.device.HasRoot(), True)):
389      self.device.EnableRoot()
390
391
392class DeviceUtilsIsUserBuildTest(DeviceUtilsTest):
393  def testIsUserBuild_yes(self):
394    with self.assertCall(
395        self.call.device.GetProp('ro.build.type', cache=True), 'user'):
396      self.assertTrue(self.device.IsUserBuild())
397
398  def testIsUserBuild_no(self):
399    with self.assertCall(
400        self.call.device.GetProp('ro.build.type', cache=True), 'userdebug'):
401      self.assertFalse(self.device.IsUserBuild())
402
403
404class DeviceUtilsGetExternalStoragePathTest(DeviceUtilsTest):
405  def testGetExternalStoragePath_succeeds(self):
406    with self.assertCalls(
407        self.EnsureCacheInitialized(sdcard='/fake/storage/path')):
408      self.assertEquals('/fake/storage/path',
409                        self.device.GetExternalStoragePath())
410
411  def testGetExternalStoragePath_fails(self):
412    with self.assertCalls(self.EnsureCacheInitialized(sdcard='')):
413      with self.assertRaises(device_errors.CommandFailedError):
414        self.device.GetExternalStoragePath()
415
416
417class DeviceUtilsGetAppWritablePathTest(DeviceUtilsTest):
418  def testGetAppWritablePath_succeeds_sdk_pre_q(self):
419    with self.assertCalls(
420        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '28'),
421        self.EnsureCacheInitialized(sdcard='/fake/storage/path')):
422      self.assertEquals('/fake/storage/path',
423                        self.device.GetAppWritablePath())
424
425  def testGetAppWritablePath_succeeds_sdk_q(self):
426    with self.assertCalls(
427        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '29'),
428        self.EnsureCacheInitialized(sdcard='/fake/storage/path')):
429      self.assertEquals('/fake/storage/path/Download',
430                        self.device.GetAppWritablePath())
431
432  def testGetAppWritablePath_fails(self):
433    with self.assertCalls(
434        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '29'),
435        self.EnsureCacheInitialized(sdcard='')):
436      with self.assertRaises(device_errors.CommandFailedError):
437        self.device.GetAppWritablePath()
438
439
440class DeviceUtilsIsApplicationInstalledTest(DeviceUtilsTest):
441  def testIsApplicationInstalled_installed(self):
442    with self.assertCalls((self.call.device.RunShellCommand(
443        ['pm', 'list', 'packages', 'some.installed.app'], check_return=True),
444                           ['package:some.installed.app'])):
445      self.assertTrue(self.device.IsApplicationInstalled('some.installed.app'))
446
447  def testIsApplicationInstalled_notInstalled(self):
448    with self.assertCalls(
449        (self.call.device.RunShellCommand(
450            ['pm', 'list', 'packages', 'not.installed.app'], check_return=True),
451         ''),
452        (self.call.device.RunShellCommand(
453            ['dumpsys', 'package'], check_return=True, large_output=True), [])):
454      self.assertFalse(self.device.IsApplicationInstalled('not.installed.app'))
455
456  def testIsApplicationInstalled_substringMatch(self):
457    with self.assertCalls(
458        (self.call.device.RunShellCommand(
459            ['pm', 'list', 'packages', 'substring.of.package'],
460            check_return=True),
461         [
462             'package:first.substring.of.package',
463             'package:second.substring.of.package',
464         ]),
465        (self.call.device.RunShellCommand(
466            ['dumpsys', 'package'], check_return=True, large_output=True), [])):
467      self.assertFalse(
468          self.device.IsApplicationInstalled('substring.of.package'))
469
470  def testIsApplicationInstalled_dumpsysFallback(self):
471    with self.assertCalls(
472        (self.call.device.RunShellCommand(
473            ['pm', 'list', 'packages', 'some.installed.app'],
474            check_return=True), []),
475        (self.call.device.RunShellCommand(
476            ['dumpsys', 'package'], check_return=True, large_output=True),
477         ['Package [some.installed.app] (a12345):'])):
478      self.assertTrue(self.device.IsApplicationInstalled('some.installed.app'))
479
480  def testIsApplicationInstalled_dumpsysFallbackVersioned(self):
481    with self.assertCalls(
482        (self.call.device.RunShellCommand(
483            ['dumpsys', 'package'], check_return=True, large_output=True),
484         ['Package [some.installed.app_1234] (a12345):'])):
485      self.assertTrue(
486          self.device.IsApplicationInstalled('some.installed.app', 1234))
487
488  def testIsApplicationInstalled_dumpsysFallbackVersionNotNeeded(self):
489    with self.assertCalls(
490        (self.call.device.RunShellCommand(
491            ['dumpsys', 'package'], check_return=True, large_output=True),
492         ['Package [some.installed.app] (a12345):'])):
493      self.assertTrue(
494          self.device.IsApplicationInstalled('some.installed.app', 1234))
495
496
497class DeviceUtilsGetApplicationPathsInternalTest(DeviceUtilsTest):
498  def testGetApplicationPathsInternal_exists(self):
499    with self.assertCalls(
500        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
501        (self.call.device.RunShellCommand(['pm', 'path', 'android'],
502                                          check_return=True),
503         ['package:/path/to/android.apk'])):
504      self.assertEquals(['/path/to/android.apk'],
505                        self.device._GetApplicationPathsInternal('android'))
506
507  def testGetApplicationPathsInternal_notExists(self):
508    with self.assertCalls(
509        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
510        (self.call.device.RunShellCommand(['pm', 'path', 'not.installed.app'],
511                                          check_return=True), '')):
512      self.assertEquals(
513          [], self.device._GetApplicationPathsInternal('not.installed.app'))
514
515  def testGetApplicationPathsInternal_garbageOutputRaises(self):
516    with self.assertCalls(
517        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
518        (self.call.device.RunShellCommand(['pm', 'path', 'android'],
519                                          check_return=True),
520         ['garbage first line'])):
521      with self.assertRaises(device_errors.CommandFailedError):
522        self.device._GetApplicationPathsInternal('android')
523
524  def testGetApplicationPathsInternal_outputWarningsIgnored(self):
525    with self.assertCalls(
526        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
527        (self.call.device.RunShellCommand(['pm', 'path', 'not.installed.app'],
528                                          check_return=True),
529         ['WARNING: some warning message from pm'])):
530      self.assertEquals(
531          [], self.device._GetApplicationPathsInternal('not.installed.app'))
532
533  def testGetApplicationPathsInternal_fails(self):
534    with self.assertCalls(
535        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
536        (self.call.device.RunShellCommand(['pm', 'path', 'android'],
537                                          check_return=True),
538         self.CommandError('ERROR. Is package manager running?\n'))):
539      with self.assertRaises(device_errors.CommandFailedError):
540        self.device._GetApplicationPathsInternal('android')
541
542
543class DeviceUtils_GetApplicationVersionTest(DeviceUtilsTest):
544  def test_GetApplicationVersion_exists(self):
545    with self.assertCalls(
546        (self.call.adb.Shell('dumpsys package com.android.chrome'),
547         'Packages:\n'
548         '  Package [com.android.chrome] (3901ecfb):\n'
549         '    userId=1234 gids=[123, 456, 789]\n'
550         '    pkg=Package{1fecf634 com.android.chrome}\n'
551         '    versionName=45.0.1234.7\n')):
552      self.assertEquals('45.0.1234.7',
553                        self.device.GetApplicationVersion('com.android.chrome'))
554
555  def test_GetApplicationVersion_notExists(self):
556    with self.assertCalls(
557        (self.call.adb.Shell('dumpsys package com.android.chrome'), '')):
558      self.assertEquals(None,
559                        self.device.GetApplicationVersion('com.android.chrome'))
560
561  def test_GetApplicationVersion_fails(self):
562    with self.assertCalls(
563        (self.call.adb.Shell('dumpsys package com.android.chrome'),
564         'Packages:\n'
565         '  Package [com.android.chrome] (3901ecfb):\n'
566         '    userId=1234 gids=[123, 456, 789]\n'
567         '    pkg=Package{1fecf634 com.android.chrome}\n')):
568      with self.assertRaises(device_errors.CommandFailedError):
569        self.device.GetApplicationVersion('com.android.chrome')
570
571
572class DeviceUtils_GetApplicationTargetSdkTest(DeviceUtilsTest):
573  def test_GetApplicationTargetSdk_exists(self):
574    with self.assertCalls(
575        (self.call.device.IsApplicationInstalled('com.android.chrome'), True),
576        (self.call.device._GetDumpsysOutput(['package', 'com.android.chrome'],
577                                            'targetSdk='),
578         ['    versionCode=413200001 minSdk=21 targetSdk=29'])):
579      self.assertEquals(
580          '29', self.device.GetApplicationTargetSdk('com.android.chrome'))
581
582  def test_GetApplicationTargetSdk_notExists(self):
583    with self.assertCalls(
584        (self.call.device.IsApplicationInstalled('com.android.chrome'), False)):
585      self.assertIsNone(
586          self.device.GetApplicationTargetSdk('com.android.chrome'))
587
588  def test_GetApplicationTargetSdk_fails(self):
589    with self.assertCalls(
590        (self.call.device.IsApplicationInstalled('com.android.chrome'), True),
591        (self.call.device._GetDumpsysOutput(['package', 'com.android.chrome'],
592                                            'targetSdk='), [])):
593      with self.assertRaises(device_errors.CommandFailedError):
594        self.device.GetApplicationTargetSdk('com.android.chrome')
595
596  def test_GetApplicationTargetSdk_prefinalizedSdk(self):
597    with self.assertCalls(
598        (self.call.device.IsApplicationInstalled('com.android.chrome'), True),
599        (self.call.device._GetDumpsysOutput(['package', 'com.android.chrome'],
600                                            'targetSdk='),
601         ['    versionCode=410301483 minSdk=10000 targetSdk=10000']),
602        (self.call.device.GetProp('ro.build.version.codename',
603                                  cache=True), 'R')):
604      self.assertEquals(
605          'R', self.device.GetApplicationTargetSdk('com.android.chrome'))
606
607
608class DeviceUtils_GetPackageArchitectureTest(DeviceUtilsTest):
609  def test_GetPackageArchitecture_exists(self):
610    with self.assertCall(
611        self.call.device._RunPipedShellCommand(
612            'dumpsys package com.android.chrome | grep -F primaryCpuAbi'),
613        ['  primaryCpuAbi=armeabi-v7a']):
614      self.assertEquals(
615          abis.ARM, self.device.GetPackageArchitecture('com.android.chrome'))
616
617  def test_GetPackageArchitecture_notExists(self):
618    with self.assertCall(
619        self.call.device._RunPipedShellCommand(
620            'dumpsys package com.android.chrome | grep -F primaryCpuAbi'), []):
621      self.assertEquals(
622          None, self.device.GetPackageArchitecture('com.android.chrome'))
623
624
625class DeviceUtilsGetApplicationDataDirectoryTest(DeviceUtilsTest):
626  def testGetApplicationDataDirectory_exists(self):
627    with self.assertCalls(
628        (self.call.device.IsApplicationInstalled('foo.bar.baz'), True),
629        (self.call.device._RunPipedShellCommand(
630            'pm dump foo.bar.baz | grep dataDir='),
631         ['dataDir=/data/data/foo.bar.baz'])):
632      self.assertEquals('/data/data/foo.bar.baz',
633                        self.device.GetApplicationDataDirectory('foo.bar.baz'))
634
635  def testGetApplicationDataDirectory_notInstalled(self):
636    with self.assertCalls(
637        (self.call.device.IsApplicationInstalled('foo.bar.baz'), False)):
638      with self.assertRaises(device_errors.CommandFailedError):
639        self.device.GetApplicationDataDirectory('foo.bar.baz')
640
641  def testGetApplicationDataDirectory_notExists(self):
642    with self.assertCalls(
643        (self.call.device.IsApplicationInstalled('foo.bar.baz'), True),
644        (self.call.device._RunPipedShellCommand(
645            'pm dump foo.bar.baz | grep dataDir='), self.ShellError())):
646      with self.assertRaises(device_errors.CommandFailedError):
647        self.device.GetApplicationDataDirectory('foo.bar.baz')
648
649
650@mock.patch('time.sleep', mock.Mock())
651class DeviceUtilsWaitUntilFullyBootedTest(DeviceUtilsTest):
652  def testWaitUntilFullyBooted_succeedsWithDefaults(self):
653    with self.assertCalls(
654        self.call.adb.WaitForDevice(),
655        # sd_card_ready
656        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
657        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
658        # pm_ready
659        (self.call.device._GetApplicationPathsInternal(
660            'android', skip_cache=True), ['package:/some/fake/path']),
661        # boot_completed
662        (self.call.device.GetProp('sys.boot_completed', cache=False), '1')):
663      self.device.WaitUntilFullyBooted(wifi=False, decrypt=False)
664
665  def testWaitUntilFullyBooted_succeedsWithWifi(self):
666    with self.assertCalls(
667        self.call.adb.WaitForDevice(),
668        # sd_card_ready
669        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
670        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
671        # pm_ready
672        (self.call.device._GetApplicationPathsInternal(
673            'android', skip_cache=True), ['package:/some/fake/path']),
674        # boot_completed
675        (self.call.device.GetProp('sys.boot_completed', cache=False), '1'),
676        # wifi_enabled
677        (self.call.adb.Shell('dumpsys wifi'),
678         'stuff\nWi-Fi is enabled\nmore stuff\n')):
679      self.device.WaitUntilFullyBooted(wifi=True, decrypt=False)
680
681  def testWaitUntilFullyBooted_succeedsWithDecryptFDE(self):
682    with self.assertCalls(
683        self.call.adb.WaitForDevice(),
684        # sd_card_ready
685        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
686        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
687        # pm_ready
688        (self.call.device._GetApplicationPathsInternal(
689            'android', skip_cache=True), ['package:/some/fake/path']),
690        # boot_completed
691        (self.call.device.GetProp('sys.boot_completed', cache=False), '1'),
692        # decryption_completed
693        (self.call.device.GetProp('vold.decrypt', cache=False),
694         'trigger_restart_framework')):
695      self.device.WaitUntilFullyBooted(wifi=False, decrypt=True)
696
697  def testWaitUntilFullyBooted_succeedsWithDecryptNotFDE(self):
698    with self.assertCalls(
699        self.call.adb.WaitForDevice(),
700        # sd_card_ready
701        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
702        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
703        # pm_ready
704        (self.call.device._GetApplicationPathsInternal(
705            'android', skip_cache=True), ['package:/some/fake/path']),
706        # boot_completed
707        (self.call.device.GetProp('sys.boot_completed', cache=False), '1'),
708        # decryption_completed
709        (self.call.device.GetProp('vold.decrypt', cache=False), '')):
710      self.device.WaitUntilFullyBooted(wifi=False, decrypt=True)
711
712  def testWaitUntilFullyBooted_deviceNotInitiallyAvailable(self):
713    with self.assertCalls(
714        self.call.adb.WaitForDevice(),
715        # sd_card_ready
716        (self.call.device.GetExternalStoragePath(), self.AdbCommandError()),
717        # sd_card_ready
718        (self.call.device.GetExternalStoragePath(), self.AdbCommandError()),
719        # sd_card_ready
720        (self.call.device.GetExternalStoragePath(), self.AdbCommandError()),
721        # sd_card_ready
722        (self.call.device.GetExternalStoragePath(), self.AdbCommandError()),
723        # sd_card_ready
724        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
725        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
726        # pm_ready
727        (self.call.device._GetApplicationPathsInternal(
728            'android', skip_cache=True), ['package:/some/fake/path']),
729        # boot_completed
730        (self.call.device.GetProp('sys.boot_completed', cache=False), '1')):
731      self.device.WaitUntilFullyBooted(wifi=False, decrypt=False)
732
733  def testWaitUntilFullyBooted_deviceBrieflyOffline(self):
734    with self.assertCalls(
735        self.call.adb.WaitForDevice(),
736        # sd_card_ready
737        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
738        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
739        # pm_ready
740        (self.call.device._GetApplicationPathsInternal(
741            'android', skip_cache=True), ['package:/some/fake/path']),
742        # boot_completed
743        (self.call.device.GetProp('sys.boot_completed', cache=False),
744         self.AdbCommandError()),
745        # boot_completed
746        (self.call.device.GetProp('sys.boot_completed', cache=False), '1')):
747      self.device.WaitUntilFullyBooted(wifi=False, decrypt=False)
748
749  def testWaitUntilFullyBooted_sdCardReadyFails_noPath(self):
750    with self.assertCalls(
751        self.call.adb.WaitForDevice(),
752        # sd_card_ready
753        (self.call.device.GetExternalStoragePath(), self.CommandError())):
754      with self.assertRaises(device_errors.CommandFailedError):
755        self.device.WaitUntilFullyBooted(wifi=False, decrypt=False)
756
757  def testWaitUntilFullyBooted_sdCardReadyFails_notExists(self):
758    with self.assertCalls(
759        self.call.adb.WaitForDevice(),
760        # sd_card_ready
761        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
762        (self.call.adb.Shell('test -d /fake/storage/path'), self.ShellError()),
763        # sd_card_ready
764        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
765        (self.call.adb.Shell('test -d /fake/storage/path'), self.ShellError()),
766        # sd_card_ready
767        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
768        (self.call.adb.Shell('test -d /fake/storage/path'),
769         self.TimeoutError())):
770      with self.assertRaises(device_errors.CommandTimeoutError):
771        self.device.WaitUntilFullyBooted(wifi=False, decrypt=False)
772
773  def testWaitUntilFullyBooted_devicePmFails(self):
774    with self.assertCalls(
775        self.call.adb.WaitForDevice(),
776        # sd_card_ready
777        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
778        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
779        # pm_ready
780        (self.call.device._GetApplicationPathsInternal(
781            'android', skip_cache=True), self.CommandError()),
782        # pm_ready
783        (self.call.device._GetApplicationPathsInternal(
784            'android', skip_cache=True), self.CommandError()),
785        # pm_ready
786        (self.call.device._GetApplicationPathsInternal(
787            'android', skip_cache=True), self.TimeoutError())):
788      with self.assertRaises(device_errors.CommandTimeoutError):
789        self.device.WaitUntilFullyBooted(wifi=False, decrypt=False)
790
791  def testWaitUntilFullyBooted_bootFails(self):
792    with self.assertCalls(
793        self.call.adb.WaitForDevice(),
794        # sd_card_ready
795        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
796        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
797        # pm_ready
798        (self.call.device._GetApplicationPathsInternal(
799            'android', skip_cache=True), ['package:/some/fake/path']),
800        # boot_completed
801        (self.call.device.GetProp('sys.boot_completed', cache=False), '0'),
802        # boot_completed
803        (self.call.device.GetProp('sys.boot_completed', cache=False), '0'),
804        # boot_completed
805        (self.call.device.GetProp('sys.boot_completed', cache=False),
806         self.TimeoutError())):
807      with self.assertRaises(device_errors.CommandTimeoutError):
808        self.device.WaitUntilFullyBooted(wifi=False, decrypt=False)
809
810  def testWaitUntilFullyBooted_wifiFails(self):
811    with self.assertCalls(
812        self.call.adb.WaitForDevice(),
813        # sd_card_ready
814        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
815        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
816        # pm_ready
817        (self.call.device._GetApplicationPathsInternal(
818            'android', skip_cache=True), ['package:/some/fake/path']),
819        # boot_completed
820        (self.call.device.GetProp('sys.boot_completed', cache=False), '1'),
821        # wifi_enabled
822        (self.call.adb.Shell('dumpsys wifi'), 'stuff\nmore stuff\n'),
823        # wifi_enabled
824        (self.call.adb.Shell('dumpsys wifi'), 'stuff\nmore stuff\n'),
825        # wifi_enabled
826        (self.call.adb.Shell('dumpsys wifi'), self.TimeoutError())):
827      with self.assertRaises(device_errors.CommandTimeoutError):
828        self.device.WaitUntilFullyBooted(wifi=True, decrypt=False)
829
830  def testWaitUntilFullyBooted_decryptFails(self):
831    with self.assertCalls(
832        self.call.adb.WaitForDevice(),
833        # sd_card_ready
834        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
835        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
836        # pm_ready
837        (self.call.device._GetApplicationPathsInternal(
838            'android', skip_cache=True), ['package:/some/fake/path']),
839        # boot_completed
840        (self.call.device.GetProp('sys.boot_completed', cache=False), '1'),
841        # decryption_completed
842        (self.call.device.GetProp('vold.decrypt', cache=False),
843         'trigger_restart_min_framework'),
844        # decryption_completed
845        (self.call.device.GetProp('vold.decrypt', cache=False),
846         'trigger_restart_min_framework'),
847        # decryption_completed
848        (self.call.device.GetProp('vold.decrypt', cache=False),
849         self.TimeoutError())):
850      with self.assertRaises(device_errors.CommandTimeoutError):
851        self.device.WaitUntilFullyBooted(wifi=False, decrypt=True)
852
853
854@mock.patch('time.sleep', mock.Mock())
855class DeviceUtilsRebootTest(DeviceUtilsTest):
856  def testReboot_nonBlocking(self):
857    with self.assertCalls(self.call.adb.Reboot(),
858                          (self.call.device.IsOnline(), True),
859                          (self.call.device.IsOnline(), False)):
860      self.device.Reboot(block=False)
861
862  def testReboot_blocking(self):
863    with self.assertCalls(
864        (self.call.device.HasRoot(), False),
865        self.call.adb.Reboot(), (self.call.device.IsOnline(), True),
866        (self.call.device.IsOnline(), False),
867        self.call.device.WaitUntilFullyBooted(wifi=False, decrypt=False)):
868      self.device.Reboot(block=True)
869
870  def testReboot_blockingWithRoot(self):
871    with self.assertCalls(
872        (self.call.device.HasRoot(), True),
873        self.call.adb.Reboot(), (self.call.device.IsOnline(), True),
874        (self.call.device.IsOnline(), False),
875        self.call.device.WaitUntilFullyBooted(wifi=False, decrypt=False),
876        self.call.device.EnableRoot()):
877      self.device.Reboot(block=True)
878
879  def testReboot_blockUntilWifi(self):
880    with self.assertCalls(
881        (self.call.device.HasRoot(), False),
882        self.call.adb.Reboot(), (self.call.device.IsOnline(), True),
883        (self.call.device.IsOnline(), False),
884        self.call.device.WaitUntilFullyBooted(wifi=True, decrypt=False)):
885      self.device.Reboot(block=True, wifi=True, decrypt=False)
886
887  def testReboot_blockUntilDecrypt(self):
888    with self.assertCalls(
889        (self.call.device.HasRoot(), False),
890        self.call.adb.Reboot(), (self.call.device.IsOnline(), True),
891        (self.call.device.IsOnline(), False),
892        self.call.device.WaitUntilFullyBooted(wifi=False, decrypt=True)):
893      self.device.Reboot(block=True, wifi=False, decrypt=True)
894
895
896class DeviceUtilsInstallTest(DeviceUtilsTest):
897
898  mock_apk = _MockApkHelper(TEST_APK_PATH, TEST_PACKAGE, ['p1'])
899
900  def testInstall_noPriorInstall(self):
901    with self.patch_call(
902        self.call.device.product_name,
903        return_value='notflounder'), (self.patch_call(
904            self.call.device.build_version_sdk, return_value=23)):
905      with self.assertCalls(
906          (self.call.device._FakeInstall(set(), None, 'test.package')),
907          (mock.call.os.path.exists(TEST_APK_PATH), True),
908          (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE), []),
909          self.call.adb.Install(TEST_APK_PATH,
910                                reinstall=False,
911                                streaming=None,
912                                allow_downgrade=False),
913          (self.call.device.IsApplicationInstalled(TEST_PACKAGE, None), True),
914          (self.call.device.GrantPermissions(TEST_PACKAGE, ['p1']), [])):
915        self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
916
917  def testInstall_noStreaming(self):
918    with self.patch_call(
919        self.call.device.product_name,
920        return_value='flounder'), (self.patch_call(
921            self.call.device.build_version_sdk, return_value=23)):
922      with self.assertCalls(
923          (self.call.device._FakeInstall(set(), None, 'test.package')),
924          (mock.call.os.path.exists(TEST_APK_PATH), True),
925          (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE), []),
926          self.call.adb.Install(TEST_APK_PATH,
927                                reinstall=False,
928                                streaming=False,
929                                allow_downgrade=False),
930          (self.call.device.IsApplicationInstalled(TEST_PACKAGE, None), True),
931          (self.call.device.GrantPermissions(TEST_PACKAGE, ['p1']), [])):
932        self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
933
934  def testInstall_permissionsPreM(self):
935    with self.patch_call(
936        self.call.device.product_name,
937        return_value='notflounder'), (self.patch_call(
938            self.call.device.build_version_sdk, return_value=20)):
939      with self.assertCalls(
940          (self.call.device._FakeInstall(set(), None, 'test.package')),
941          (mock.call.os.path.exists(TEST_APK_PATH), True),
942          (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE), []),
943          (self.call.adb.Install(TEST_APK_PATH,
944                                 reinstall=False,
945                                 streaming=None,
946                                 allow_downgrade=False)),
947          (self.call.device.IsApplicationInstalled(TEST_PACKAGE, None), True)):
948        self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
949
950  def testInstall_findPermissions(self):
951    with self.patch_call(
952        self.call.device.product_name,
953        return_value='notflounder'), (self.patch_call(
954            self.call.device.build_version_sdk, return_value=23)):
955      with self.assertCalls(
956          (self.call.device._FakeInstall(set(), None, 'test.package')),
957          (mock.call.os.path.exists(TEST_APK_PATH), True),
958          (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE), []),
959          (self.call.adb.Install(TEST_APK_PATH,
960                                 reinstall=False,
961                                 streaming=None,
962                                 allow_downgrade=False)),
963          (self.call.device.IsApplicationInstalled(TEST_PACKAGE, None), True),
964          (self.call.device.GrantPermissions(TEST_PACKAGE, ['p1']), [])):
965        self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
966
967  def testInstall_passPermissions(self):
968    with self.patch_call(
969        self.call.device.product_name, return_value='notflounder'):
970      with self.assertCalls(
971          (self.call.device._FakeInstall(set(), None, 'test.package')),
972          (mock.call.os.path.exists(TEST_APK_PATH), True),
973          (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE), []),
974          (self.call.adb.Install(TEST_APK_PATH,
975                                 reinstall=False,
976                                 streaming=None,
977                                 allow_downgrade=False)),
978          (self.call.device.IsApplicationInstalled(TEST_PACKAGE, None), True),
979          (self.call.device.GrantPermissions(TEST_PACKAGE, ['p1', 'p2']), [])):
980        self.device.Install(
981            DeviceUtilsInstallTest.mock_apk,
982            retries=0,
983            permissions=['p1', 'p2'])
984
985  def testInstall_identicalPriorInstall(self):
986    with self.assertCalls(
987        (self.call.device._FakeInstall(set(), None, 'test.package')),
988        (mock.call.os.path.exists(TEST_APK_PATH), True),
989        (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE),
990         ['/fake/data/app/test.package.apk']),
991        (self.call.device._ComputeStaleApks(TEST_PACKAGE, [TEST_APK_PATH]),
992         ([], None)), (self.call.device.ForceStop(TEST_PACKAGE)),
993          (self.call.device.IsApplicationInstalled(TEST_PACKAGE, None), True)):
994      self.device.Install(
995          DeviceUtilsInstallTest.mock_apk, retries=0, permissions=[])
996
997  def testInstall_differentPriorInstall(self):
998    with self.patch_call(
999        self.call.device.product_name, return_value='notflounder'):
1000      with self.assertCalls(
1001          (self.call.device._FakeInstall(set(), None, 'test.package')),
1002          (mock.call.os.path.exists(TEST_APK_PATH), True),
1003          (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE),
1004           ['/fake/data/app/test.package.apk']),
1005          (self.call.device._ComputeStaleApks(TEST_PACKAGE, [TEST_APK_PATH]),
1006           ([TEST_APK_PATH], None)), self.call.device.Uninstall(TEST_PACKAGE),
1007          self.call.adb.Install(TEST_APK_PATH,
1008                                reinstall=False,
1009                                streaming=None,
1010                                allow_downgrade=False),
1011          (self.call.device.IsApplicationInstalled(TEST_PACKAGE, None), True)):
1012        self.device.Install(
1013            DeviceUtilsInstallTest.mock_apk, retries=0, permissions=[])
1014
1015  def testInstall_differentPriorInstallSplitApk(self):
1016    with self.patch_call(
1017        self.call.device.product_name, return_value='notflounder'):
1018      with self.assertCalls(
1019          (self.call.device._FakeInstall(set(), None, 'test.package')),
1020          (mock.call.os.path.exists(TEST_APK_PATH), True),
1021          (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE), [
1022              '/fake/data/app/test.package.apk',
1023              '/fake/data/app/test.package2.apk'
1024          ]), self.call.device.Uninstall(TEST_PACKAGE),
1025          self.call.adb.Install(TEST_APK_PATH,
1026                                reinstall=False,
1027                                streaming=None,
1028                                allow_downgrade=False),
1029          (self.call.device.IsApplicationInstalled(TEST_PACKAGE, None), True)):
1030        self.device.Install(
1031            DeviceUtilsInstallTest.mock_apk, retries=0, permissions=[])
1032
1033  def testInstall_differentPriorInstall_reinstall(self):
1034    with self.patch_call(
1035        self.call.device.product_name, return_value='notflounder'):
1036      with self.assertCalls(
1037          (self.call.device._FakeInstall(set(), None, 'test.package')),
1038          (mock.call.os.path.exists(TEST_APK_PATH), True),
1039          (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE),
1040           ['/fake/data/app/test.package.apk']),
1041          (self.call.device._ComputeStaleApks(TEST_PACKAGE, [TEST_APK_PATH]),
1042           ([TEST_APK_PATH], None)),
1043          self.call.adb.Install(TEST_APK_PATH,
1044                                reinstall=True,
1045                                streaming=None,
1046                                allow_downgrade=False),
1047          (self.call.device.IsApplicationInstalled(TEST_PACKAGE, None), True)):
1048        self.device.Install(
1049            DeviceUtilsInstallTest.mock_apk,
1050            reinstall=True,
1051            retries=0,
1052            permissions=[])
1053
1054  def testInstall_identicalPriorInstall_reinstall(self):
1055    with self.assertCalls(
1056        (self.call.device._FakeInstall(set(), None, 'test.package')),
1057        (mock.call.os.path.exists(TEST_APK_PATH), True),
1058        (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE),
1059         ['/fake/data/app/test.package.apk']),
1060        (self.call.device._ComputeStaleApks(TEST_PACKAGE, [TEST_APK_PATH]),
1061         ([], None)), (self.call.device.ForceStop(TEST_PACKAGE)),
1062          (self.call.device.IsApplicationInstalled(TEST_PACKAGE, None), True)):
1063      self.device.Install(
1064          DeviceUtilsInstallTest.mock_apk,
1065          reinstall=True,
1066          retries=0,
1067          permissions=[])
1068
1069  def testInstall_missingApk(self):
1070    with self.assertCalls(
1071        (self.call.device._FakeInstall(set(), None, 'test.package')),
1072        (mock.call.os.path.exists(TEST_APK_PATH), False)):
1073      with self.assertRaises(device_errors.CommandFailedError):
1074        self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
1075
1076  def testInstall_fails(self):
1077    with self.patch_call(
1078        self.call.device.product_name, return_value='notflounder'):
1079      with self.assertCalls(
1080          (self.call.device._FakeInstall(set(), None, 'test.package')),
1081          (mock.call.os.path.exists(TEST_APK_PATH), True),
1082          (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE), []),
1083          (self.call.adb.Install(
1084              TEST_APK_PATH,
1085              reinstall=False,
1086              streaming=None,
1087              allow_downgrade=False), self.CommandError('Failure\r\n'))):
1088        with self.assertRaises(device_errors.CommandFailedError):
1089          self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
1090
1091  def testInstall_downgrade(self):
1092    with self.patch_call(
1093        self.call.device.product_name, return_value='notflounder'):
1094      with self.assertCalls(
1095          (self.call.device._FakeInstall(set(), None, 'test.package')),
1096          (mock.call.os.path.exists(TEST_APK_PATH), True),
1097          (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE),
1098           ['/fake/data/app/test.package.apk']),
1099          (self.call.device._ComputeStaleApks(TEST_PACKAGE, [TEST_APK_PATH]),
1100           ([TEST_APK_PATH], None)),
1101          self.call.adb.Install(TEST_APK_PATH,
1102                                reinstall=True,
1103                                streaming=None,
1104                                allow_downgrade=True),
1105          (self.call.device.IsApplicationInstalled(TEST_PACKAGE, None), True)):
1106        self.device.Install(
1107            DeviceUtilsInstallTest.mock_apk,
1108            reinstall=True,
1109            retries=0,
1110            permissions=[],
1111            allow_downgrade=True)
1112
1113  def testInstall_pushesFakeModulesToDevice(self):
1114    @contextlib.contextmanager
1115    def mock_zip_temp_dir():
1116      yield '/test/tmp/dir'
1117
1118    mock_apk_with_fake = _MockApkHelper(
1119        TEST_APK_PATH, TEST_PACKAGE, splits=['fake1-master.apk'])
1120    fake_modules = ['fake1']
1121    with self.patch_call(
1122        self.call.device.product_name,
1123        return_value='notflounder'), (self.patch_call(
1124            self.call.device.build_version_sdk, return_value=23)):
1125      with self.assertCalls(
1126          (mock.call.py_utils.tempfile_ext.NamedTemporaryDirectory(),
1127           mock_zip_temp_dir),
1128          (mock.call.os.rename('fake1-master.apk', '/test/tmp/dir/fake1.apk')),
1129          (self.call.device.PushChangedFiles(
1130              [('/test/tmp/dir', '/data/local/tmp/modules/test.package')],
1131              delete_device_stale=True)),
1132          (mock.call.os.path.exists(TEST_APK_PATH), True),
1133          (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE), []),
1134          self.call.adb.Install(TEST_APK_PATH,
1135                                reinstall=False,
1136                                streaming=None,
1137                                allow_downgrade=False),
1138          (self.call.device.IsApplicationInstalled(TEST_PACKAGE, None), True),
1139          (self.call.device.GrantPermissions(TEST_PACKAGE, None), [])):
1140        self.device.Install(
1141            mock_apk_with_fake, fake_modules=fake_modules, retries=0)
1142
1143  def testInstall_packageNotAvailableAfterInstall(self):
1144    with self.patch_call(
1145        self.call.device.product_name,
1146        return_value='notflounder'), (self.patch_call(
1147            self.call.device.build_version_sdk, return_value=23)), (
1148                self.patch_call(self.call.device.IsApplicationInstalled,
1149                                return_value=False)):
1150      with self.assertCalls(
1151          (self.call.device._FakeInstall(set(), None, 'test.package')),
1152          (mock.call.os.path.exists(TEST_APK_PATH), True),
1153          (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE), []),
1154          self.call.adb.Install(TEST_APK_PATH,
1155                                reinstall=False,
1156                                streaming=None,
1157                                allow_downgrade=False)):
1158        with self.assertRaisesRegexp(
1159            device_errors.CommandFailedError,
1160            'not installed on device after explicit install attempt'):
1161          self.device.Install(
1162              DeviceUtilsInstallTest.mock_apk, retries=0)
1163
1164
1165class DeviceUtilsInstallSplitApkTest(DeviceUtilsTest):
1166
1167  mock_apk = _MockApkHelper('base.apk', TEST_PACKAGE, ['p1'],
1168                            ['split1.apk', 'split2.apk'])
1169
1170  def testInstallSplitApk_noPriorInstall(self):
1171    with self.patch_call(
1172        self.call.device.product_name, return_value='notflounder'):
1173      with self.assertCalls(
1174          (mock.call.devil.android.apk_helper.ToSplitHelper(
1175              'base.apk', ['split1.apk', 'split2.apk']),
1176           DeviceUtilsInstallSplitApkTest.mock_apk),
1177          (self.call.device._CheckSdkLevel(21)),
1178          (mock.call.os.path.exists('base.apk'), True),
1179          (mock.call.os.path.exists('split1.apk'), True),
1180          (mock.call.os.path.exists('split2.apk'), True),
1181          (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE), []),
1182          (self.call.adb.InstallMultiple(
1183              ['base.apk', 'split1.apk', 'split2.apk'],
1184              partial=None,
1185              reinstall=False,
1186              streaming=None,
1187              allow_downgrade=False)),
1188          (self.call.device.IsApplicationInstalled(TEST_PACKAGE, None), True)):
1189        self.device.InstallSplitApk(
1190            'base.apk', ['split1.apk', 'split2.apk'], permissions=[], retries=0)
1191
1192  def testInstallSplitApk_noStreaming(self):
1193    with self.patch_call(
1194        self.call.device.product_name, return_value='flounder'):
1195      with self.assertCalls(
1196          (mock.call.devil.android.apk_helper.ToSplitHelper(
1197              'base.apk', ['split1.apk', 'split2.apk']),
1198           DeviceUtilsInstallSplitApkTest.mock_apk),
1199          (self.call.device._CheckSdkLevel(21)),
1200          (mock.call.os.path.exists('base.apk'), True),
1201          (mock.call.os.path.exists('split1.apk'), True),
1202          (mock.call.os.path.exists('split2.apk'), True),
1203          (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE), []),
1204          (self.call.adb.InstallMultiple(
1205              ['base.apk', 'split1.apk', 'split2.apk'],
1206              partial=None,
1207              reinstall=False,
1208              streaming=False,
1209              allow_downgrade=False)),
1210          (self.call.device.IsApplicationInstalled(TEST_PACKAGE, None), True)):
1211        self.device.InstallSplitApk(
1212            'base.apk', ['split1.apk', 'split2.apk'], permissions=[], retries=0)
1213
1214  def testInstallSplitApk_partialInstall(self):
1215    with self.patch_call(
1216        self.call.device.product_name, return_value='notflounder'):
1217      with self.assertCalls(
1218          (mock.call.devil.android.apk_helper.ToSplitHelper(
1219              DeviceUtilsInstallSplitApkTest.mock_apk,
1220              ['split1.apk', 'split2.apk']),
1221           DeviceUtilsInstallSplitApkTest.mock_apk),
1222          (self.call.device._CheckSdkLevel(21)),
1223          (mock.call.os.path.exists('base.apk'), True),
1224          (mock.call.os.path.exists('split1.apk'), True),
1225          (mock.call.os.path.exists('split2.apk'), True),
1226          (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE),
1227           ['base-on-device.apk', 'split2-on-device.apk']),
1228          (self.call.device._ComputeStaleApks(
1229              TEST_PACKAGE, ['base.apk', 'split1.apk', 'split2.apk']),
1230           (['split2.apk'], None)),
1231          (self.call.adb.InstallMultiple(['split2.apk'],
1232                                         partial=TEST_PACKAGE,
1233                                         reinstall=True,
1234                                         streaming=None,
1235                                         allow_downgrade=False)),
1236          (self.call.device.IsApplicationInstalled(TEST_PACKAGE, None), True)):
1237        self.device.InstallSplitApk(
1238            DeviceUtilsInstallSplitApkTest.mock_apk,
1239            ['split1.apk', 'split2.apk'],
1240            reinstall=True,
1241            permissions=[],
1242            retries=0)
1243
1244  def testInstallSplitApk_downgrade(self):
1245    with self.patch_call(
1246        self.call.device.product_name, return_value='notflounder'):
1247      with self.assertCalls(
1248          (mock.call.devil.android.apk_helper.ToSplitHelper(
1249              DeviceUtilsInstallSplitApkTest.mock_apk,
1250              ['split1.apk', 'split2.apk']),
1251           DeviceUtilsInstallSplitApkTest.mock_apk),
1252          (self.call.device._CheckSdkLevel(21)),
1253          (mock.call.os.path.exists('base.apk'), True),
1254          (mock.call.os.path.exists('split1.apk'), True),
1255          (mock.call.os.path.exists('split2.apk'), True),
1256          (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE),
1257           ['base-on-device.apk', 'split2-on-device.apk']),
1258          (self.call.device._ComputeStaleApks(
1259              TEST_PACKAGE, ['base.apk', 'split1.apk', 'split2.apk']),
1260           (['split2.apk'], None)),
1261          (self.call.adb.InstallMultiple(['split2.apk'],
1262                                         partial=TEST_PACKAGE,
1263                                         reinstall=True,
1264                                         streaming=None,
1265                                         allow_downgrade=True)),
1266          (self.call.device.IsApplicationInstalled(TEST_PACKAGE, None), True)):
1267        self.device.InstallSplitApk(
1268            DeviceUtilsInstallSplitApkTest.mock_apk,
1269            ['split1.apk', 'split2.apk'],
1270            reinstall=True,
1271            permissions=[],
1272            retries=0,
1273            allow_downgrade=True)
1274
1275  def testInstallSplitApk_missingSplit(self):
1276    with self.assertCalls(
1277        (mock.call.devil.android.apk_helper.ToSplitHelper(
1278            DeviceUtilsInstallSplitApkTest.mock_apk,
1279            ['split1.apk', 'split2.apk']),
1280          DeviceUtilsInstallSplitApkTest.mock_apk),
1281        (self.call.device._CheckSdkLevel(21)),
1282        (mock.call.os.path.exists('base.apk'), True),
1283        (mock.call.os.path.exists('split1.apk'), True),
1284        (mock.call.os.path.exists('split2.apk'), False)),\
1285        self.assertRaises(device_errors.CommandFailedError):
1286      self.device.InstallSplitApk(
1287          DeviceUtilsInstallSplitApkTest.mock_apk, ['split1.apk', 'split2.apk'],
1288          permissions=[],
1289          retries=0)
1290
1291  def testInstallSplitApk_previouslyNonSplit(self):
1292    with self.patch_call(
1293        self.call.device.product_name, return_value='notflounder'):
1294      with self.assertCalls(
1295          (mock.call.devil.android.apk_helper.ToSplitHelper(
1296              DeviceUtilsInstallSplitApkTest.mock_apk,
1297              ['split1.apk', 'split2.apk']),
1298           DeviceUtilsInstallSplitApkTest.mock_apk),
1299          (self.call.device._CheckSdkLevel(21)),
1300          (mock.call.os.path.exists('base.apk'), True),
1301          (mock.call.os.path.exists('split1.apk'), True),
1302          (mock.call.os.path.exists('split2.apk'), True),
1303          (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE),
1304           ['/fake/data/app/test.package.apk']),
1305          self.call.device.Uninstall(TEST_PACKAGE),
1306          (self.call.adb.InstallMultiple(
1307              ['base.apk', 'split1.apk', 'split2.apk'],
1308              partial=None,
1309              reinstall=False,
1310              streaming=None,
1311              allow_downgrade=False)),
1312          (self.call.device.IsApplicationInstalled(TEST_PACKAGE, None), True)):
1313        self.device.InstallSplitApk(
1314            DeviceUtilsInstallSplitApkTest.mock_apk,
1315            ['split1.apk', 'split2.apk'],
1316            permissions=[],
1317            retries=0)
1318
1319
1320class DeviceUtilsUninstallTest(DeviceUtilsTest):
1321  def testUninstall_callsThrough(self):
1322    with self.assertCalls(
1323        (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE),
1324         ['/path.apk']), self.call.adb.Uninstall(TEST_PACKAGE, True)):
1325      self.device.Uninstall(TEST_PACKAGE, True)
1326
1327  def testUninstall_noop(self):
1328    with self.assertCalls(
1329        (self.call.device._GetApplicationPathsInternal(TEST_PACKAGE), [])):
1330      self.device.Uninstall(TEST_PACKAGE, True)
1331
1332
1333class DeviceUtilsSuTest(DeviceUtilsTest):
1334  def testSu_preM(self):
1335    with self.patch_call(
1336        self.call.device.build_version_sdk,
1337        return_value=version_codes.LOLLIPOP_MR1):
1338      self.assertEquals('su -c foo', self.device._Su('foo'))
1339
1340  def testSu_mAndAbove(self):
1341    with self.patch_call(
1342        self.call.device.build_version_sdk,
1343        return_value=version_codes.MARSHMALLOW):
1344      self.assertEquals('su 0 foo', self.device._Su('foo'))
1345
1346
1347class DeviceUtilsRunShellCommandTest(DeviceUtilsTest):
1348  def setUp(self):
1349    super(DeviceUtilsRunShellCommandTest, self).setUp()
1350    self.device.NeedsSU = mock.Mock(return_value=False)
1351
1352  def testRunShellCommand_commandAsList(self):
1353    with self.assertCall(self.call.adb.Shell('pm list packages'), ''):
1354      self.device.RunShellCommand(['pm', 'list', 'packages'], check_return=True)
1355
1356  def testRunShellCommand_commandAsListQuoted(self):
1357    with self.assertCall(self.call.adb.Shell("echo 'hello world' '$10'"), ''):
1358      self.device.RunShellCommand(['echo', 'hello world', '$10'],
1359                                  check_return=True)
1360
1361  def testRunShellCommand_commandAsString(self):
1362    with self.assertCall(self.call.adb.Shell('echo "$VAR"'), ''):
1363      self.device.RunShellCommand('echo "$VAR"', shell=True, check_return=True)
1364
1365  def testNewRunShellImpl_withEnv(self):
1366    with self.assertCall(
1367        self.call.adb.Shell('VAR=some_string echo "$VAR"'), ''):
1368      self.device.RunShellCommand(
1369          'echo "$VAR"',
1370          shell=True,
1371          check_return=True,
1372          env={'VAR': 'some_string'})
1373
1374  def testNewRunShellImpl_withEnvQuoted(self):
1375    with self.assertCall(
1376        self.call.adb.Shell('PATH="$PATH:/other/path" run_this'), ''):
1377      self.device.RunShellCommand(['run_this'],
1378                                  check_return=True,
1379                                  env={'PATH': '$PATH:/other/path'})
1380
1381  def testNewRunShellImpl_withEnv_failure(self):
1382    with self.assertRaises(KeyError):
1383      self.device.RunShellCommand(['some_cmd'],
1384                                  check_return=True,
1385                                  env={'INVALID NAME': 'value'})
1386
1387  def testNewRunShellImpl_withCwd(self):
1388    with self.assertCall(self.call.adb.Shell('cd /some/test/path && ls'), ''):
1389      self.device.RunShellCommand(['ls'],
1390                                  check_return=True,
1391                                  cwd='/some/test/path')
1392
1393  def testNewRunShellImpl_withCwdQuoted(self):
1394    with self.assertCall(
1395        self.call.adb.Shell("cd '/some test/path with/spaces' && ls"), ''):
1396      self.device.RunShellCommand(['ls'],
1397                                  check_return=True,
1398                                  cwd='/some test/path with/spaces')
1399
1400  def testRunShellCommand_withHugeCmd(self):
1401    payload = 'hi! ' * 1024
1402    expected_cmd = "echo '%s'" % payload
1403    with self.assertCalls(
1404        (mock.call.devil.android.device_temp_file.DeviceTempFile(
1405            self.adb, suffix='.sh'), MockTempFile('/sdcard/temp-123.sh')),
1406        self.call.device._WriteFileWithPush('/sdcard/temp-123.sh',
1407                                            expected_cmd),
1408        (self.call.adb.Shell('sh /sdcard/temp-123.sh'), payload + '\n')):
1409      self.assertEquals([payload],
1410                        self.device.RunShellCommand(['echo', payload],
1411                                                    check_return=True))
1412
1413  def testRunShellCommand_withHugeCmdAndSu(self):
1414    payload = 'hi! ' * 1024
1415    expected_cmd_without_su = """sh -c 'echo '"'"'%s'"'"''""" % payload
1416    expected_cmd = 'su -c %s' % expected_cmd_without_su
1417    with self.assertCalls(
1418        (self.call.device.NeedsSU(), True),
1419        (self.call.device._Su(expected_cmd_without_su), expected_cmd),
1420        (mock.call.devil.android.device_temp_file.DeviceTempFile(
1421            self.adb, suffix='.sh'), MockTempFile('/sdcard/temp-123.sh')),
1422        self.call.device._WriteFileWithPush('/sdcard/temp-123.sh',
1423                                            expected_cmd),
1424        (self.call.adb.Shell('sh /sdcard/temp-123.sh'), payload + '\n')):
1425      self.assertEquals([payload],
1426                        self.device.RunShellCommand(['echo', payload],
1427                                                    check_return=True,
1428                                                    as_root=True))
1429
1430  def testRunShellCommand_withSu(self):
1431    expected_cmd_without_su = "sh -c 'setprop service.adb.root 0'"
1432    expected_cmd = 'su -c %s' % expected_cmd_without_su
1433    with self.assertCalls(
1434        (self.call.device.NeedsSU(), True),
1435        (self.call.device._Su(expected_cmd_without_su), expected_cmd),
1436        (self.call.adb.Shell(expected_cmd), '')):
1437      self.device.RunShellCommand(['setprop', 'service.adb.root', '0'],
1438                                  check_return=True,
1439                                  as_root=True)
1440
1441  def testRunShellCommand_withRunAs(self):
1442    expected_cmd_without_run_as = "sh -c 'mkdir -p files'"
1443    expected_cmd = (
1444        'run-as org.devil.test_package %s' % expected_cmd_without_run_as)
1445    with self.assertCall(self.call.adb.Shell(expected_cmd), ''):
1446      self.device.RunShellCommand(['mkdir', '-p', 'files'],
1447                                  check_return=True,
1448                                  run_as='org.devil.test_package')
1449
1450  def testRunShellCommand_withRunAsAndSu(self):
1451    expected_cmd_with_nothing = "sh -c 'mkdir -p files'"
1452    expected_cmd_with_run_as = (
1453        'run-as org.devil.test_package %s' % expected_cmd_with_nothing)
1454    expected_cmd_without_su = (
1455        'sh -c %s' % cmd_helper.SingleQuote(expected_cmd_with_run_as))
1456    expected_cmd = 'su -c %s' % expected_cmd_without_su
1457    with self.assertCalls(
1458        (self.call.device.NeedsSU(), True),
1459        (self.call.device._Su(expected_cmd_without_su), expected_cmd),
1460        (self.call.adb.Shell(expected_cmd), '')):
1461      self.device.RunShellCommand(['mkdir', '-p', 'files'],
1462                                  check_return=True,
1463                                  run_as='org.devil.test_package',
1464                                  as_root=True)
1465
1466  def testRunShellCommand_manyLines(self):
1467    cmd = 'ls /some/path'
1468    with self.assertCall(self.call.adb.Shell(cmd), 'file1\nfile2\nfile3\n'):
1469      self.assertEquals(['file1', 'file2', 'file3'],
1470                        self.device.RunShellCommand(
1471                            cmd.split(), check_return=True))
1472
1473  def testRunShellCommand_manyLinesRawOutput(self):
1474    cmd = 'ls /some/path'
1475    with self.assertCall(self.call.adb.Shell(cmd), '\rfile1\nfile2\r\nfile3\n'):
1476      self.assertEquals(
1477          '\rfile1\nfile2\r\nfile3\n',
1478          self.device.RunShellCommand(
1479              cmd.split(), check_return=True, raw_output=True))
1480
1481  def testRunShellCommand_singleLine_success(self):
1482    cmd = 'echo $VALUE'
1483    with self.assertCall(self.call.adb.Shell(cmd), 'some value\n'):
1484      self.assertEquals(
1485          'some value',
1486          self.device.RunShellCommand(
1487              cmd, shell=True, check_return=True, single_line=True))
1488
1489  def testRunShellCommand_singleLine_successEmptyLine(self):
1490    cmd = 'echo $VALUE'
1491    with self.assertCall(self.call.adb.Shell(cmd), '\n'):
1492      self.assertEquals(
1493          '',
1494          self.device.RunShellCommand(
1495              cmd, shell=True, check_return=True, single_line=True))
1496
1497  def testRunShellCommand_singleLine_successWithoutEndLine(self):
1498    cmd = 'echo -n $VALUE'
1499    with self.assertCall(self.call.adb.Shell(cmd), 'some value'):
1500      self.assertEquals(
1501          'some value',
1502          self.device.RunShellCommand(
1503              cmd, shell=True, check_return=True, single_line=True))
1504
1505  def testRunShellCommand_singleLine_successNoOutput(self):
1506    cmd = 'echo -n $VALUE'
1507    with self.assertCall(self.call.adb.Shell(cmd), ''):
1508      self.assertEquals(
1509          '',
1510          self.device.RunShellCommand(
1511              cmd, shell=True, check_return=True, single_line=True))
1512
1513  def testRunShellCommand_singleLine_failTooManyLines(self):
1514    cmd = 'echo $VALUE'
1515    with self.assertCall(
1516        self.call.adb.Shell(cmd), 'some value\nanother value\n'):
1517      with self.assertRaises(device_errors.CommandFailedError):
1518        self.device.RunShellCommand(
1519            cmd, shell=True, check_return=True, single_line=True)
1520
1521  def testRunShellCommand_checkReturn_success(self):
1522    cmd = 'echo $ANDROID_DATA'
1523    output = '/data\n'
1524    with self.assertCall(self.call.adb.Shell(cmd), output):
1525      self.assertEquals([output.rstrip()],
1526                        self.device.RunShellCommand(
1527                            cmd, shell=True, check_return=True))
1528
1529  def testRunShellCommand_checkReturn_failure(self):
1530    cmd = 'ls /root'
1531    output = 'opendir failed, Permission denied\n'
1532    with self.assertCall(self.call.adb.Shell(cmd), self.ShellError(output)):
1533      with self.assertRaises(device_errors.AdbCommandFailedError):
1534        self.device.RunShellCommand(cmd.split(), check_return=True)
1535
1536  def testRunShellCommand_checkReturn_disabled(self):
1537    cmd = 'ls /root'
1538    output = 'opendir failed, Permission denied\n'
1539    with self.assertCall(self.call.adb.Shell(cmd), self.ShellError(output)):
1540      self.assertEquals([output.rstrip()],
1541                        self.device.RunShellCommand(
1542                            cmd.split(), check_return=False))
1543
1544  def testRunShellCommand_largeOutput_enabled(self):
1545    cmd = 'echo $VALUE'
1546    temp_file = MockTempFile('/sdcard/temp-123')
1547    cmd_redirect = '( %s )>%s 2>&1' % (cmd, temp_file.name)
1548    with self.assertCalls(
1549        (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb),
1550         temp_file),
1551        (self.call.adb.Shell(cmd_redirect)), (self.call.device.ReadFile(
1552            temp_file.name, force_pull=True), 'something')):
1553      self.assertEquals(['something'],
1554                        self.device.RunShellCommand(
1555                            cmd,
1556                            shell=True,
1557                            large_output=True,
1558                            check_return=True))
1559
1560  def testRunShellCommand_largeOutput_disabledNoTrigger(self):
1561    cmd = 'something'
1562    with self.assertCall(self.call.adb.Shell(cmd), self.ShellError('')):
1563      with self.assertRaises(device_errors.AdbCommandFailedError):
1564        self.device.RunShellCommand([cmd], check_return=True)
1565
1566  def testRunShellCommand_largeOutput_disabledTrigger(self):
1567    cmd = 'echo $VALUE'
1568    temp_file = MockTempFile('/sdcard/temp-123')
1569    cmd_redirect = '( %s )>%s 2>&1' % (cmd, temp_file.name)
1570    with self.assertCalls(
1571        (self.call.adb.Shell(cmd), self.ShellError('', None)),
1572        (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb),
1573         temp_file), (self.call.adb.Shell(cmd_redirect)),
1574        (self.call.device.ReadFile(mock.ANY, force_pull=True), 'something')):
1575      self.assertEquals(['something'],
1576                        self.device.RunShellCommand(
1577                            cmd, shell=True, check_return=True))
1578
1579
1580class DeviceUtilsRunPipedShellCommandTest(DeviceUtilsTest):
1581  def testRunPipedShellCommand_success(self):
1582    with self.assertCall(
1583        self.call.device.RunShellCommand(
1584            'ps | grep foo; echo "PIPESTATUS: ${PIPESTATUS[@]}"',
1585            shell=True,
1586            check_return=True), ['This line contains foo', 'PIPESTATUS: 0 0']):
1587      self.assertEquals(['This line contains foo'],
1588                        self.device._RunPipedShellCommand('ps | grep foo'))
1589
1590  def testRunPipedShellCommand_firstCommandFails(self):
1591    with self.assertCall(
1592        self.call.device.RunShellCommand(
1593            'ps | grep foo; echo "PIPESTATUS: ${PIPESTATUS[@]}"',
1594            shell=True,
1595            check_return=True), ['PIPESTATUS: 1 0']):
1596      with self.assertRaises(device_errors.AdbShellCommandFailedError) as ec:
1597        self.device._RunPipedShellCommand('ps | grep foo')
1598      self.assertEquals([1, 0], ec.exception.status)
1599
1600  def testRunPipedShellCommand_secondCommandFails(self):
1601    with self.assertCall(
1602        self.call.device.RunShellCommand(
1603            'ps | grep foo; echo "PIPESTATUS: ${PIPESTATUS[@]}"',
1604            shell=True,
1605            check_return=True), ['PIPESTATUS: 0 1']):
1606      with self.assertRaises(device_errors.AdbShellCommandFailedError) as ec:
1607        self.device._RunPipedShellCommand('ps | grep foo')
1608      self.assertEquals([0, 1], ec.exception.status)
1609
1610  def testRunPipedShellCommand_outputCutOff(self):
1611    with self.assertCall(
1612        self.call.device.RunShellCommand(
1613            'ps | grep foo; echo "PIPESTATUS: ${PIPESTATUS[@]}"',
1614            shell=True,
1615            check_return=True), ['foo.bar'] * 256 + ['foo.ba']):
1616      with self.assertRaises(device_errors.AdbShellCommandFailedError) as ec:
1617        self.device._RunPipedShellCommand('ps | grep foo')
1618      self.assertIs(None, ec.exception.status)
1619
1620
1621@mock.patch('time.sleep', mock.Mock())
1622class DeviceUtilsKillAllTest(DeviceUtilsTest):
1623  def testKillAll_noMatchingProcessesFailure(self):
1624    with self.assertCall(self.call.device.ListProcesses('test_process'), []):
1625      with self.assertRaises(device_errors.CommandFailedError):
1626        self.device.KillAll('test_process')
1627
1628  def testKillAll_noMatchingProcessesQuiet(self):
1629    with self.assertCall(self.call.device.ListProcesses('test_process'), []):
1630      self.assertEqual(0, self.device.KillAll('test_process', quiet=True))
1631
1632  def testKillAll_nonblocking(self):
1633    with self.assertCalls((self.call.device.ListProcesses('some.process'),
1634                           Processes(('some.process', 1234),
1635                                     ('some.process.thing', 5678))),
1636                          (self.call.adb.Shell('kill -9 1234 5678'), '')):
1637      self.assertEquals(2, self.device.KillAll('some.process', blocking=False))
1638
1639  def testKillAll_blocking(self):
1640    with self.assertCalls(
1641        (self.call.device.ListProcesses('some.process'),
1642         Processes(('some.process', 1234), ('some.process.thing', 5678))),
1643        (self.call.adb.Shell('kill -9 1234 5678'), ''),
1644        (self.call.device.ListProcesses('some.process'),
1645         Processes(('some.process.thing', 5678))),
1646        (
1647            self.call.device.ListProcesses('some.process'),
1648            # Other instance with different pid.
1649            Processes(('some.process', 111)))):
1650      self.assertEquals(2, self.device.KillAll('some.process', blocking=True))
1651
1652  def testKillAll_exactNonblocking(self):
1653    with self.assertCalls((self.call.device.ListProcesses('some.process'),
1654                           Processes(('some.process', 1234),
1655                                     ('some.process.thing', 5678))),
1656                          (self.call.adb.Shell('kill -9 1234'), '')):
1657      self.assertEquals(
1658          1, self.device.KillAll('some.process', exact=True, blocking=False))
1659
1660  def testKillAll_exactBlocking(self):
1661    with self.assertCalls((self.call.device.ListProcesses('some.process'),
1662                           Processes(('some.process', 1234),
1663                                     ('some.process.thing', 5678))),
1664                          (self.call.adb.Shell('kill -9 1234'), ''),
1665                          (self.call.device.ListProcesses('some.process'),
1666                           Processes(('some.process', 1234),
1667                                     ('some.process.thing', 5678))),
1668                          (self.call.device.ListProcesses('some.process'),
1669                           Processes(('some.process.thing', 5678)))):
1670      self.assertEquals(
1671          1, self.device.KillAll('some.process', exact=True, blocking=True))
1672
1673  def testKillAll_root(self):
1674    with self.assertCalls(
1675        (self.call.device.ListProcesses('some.process'),
1676         Processes(('some.process', 1234))), (self.call.device.NeedsSU(), True),
1677        (self.call.device._Su("sh -c 'kill -9 1234'"),
1678         "su -c sh -c 'kill -9 1234'"),
1679        (self.call.adb.Shell("su -c sh -c 'kill -9 1234'"), '')):
1680      self.assertEquals(1, self.device.KillAll('some.process', as_root=True))
1681
1682  def testKillAll_sigterm(self):
1683    with self.assertCalls((self.call.device.ListProcesses('some.process'),
1684                           Processes(('some.process', 1234))),
1685                          (self.call.adb.Shell('kill -15 1234'), '')):
1686      self.assertEquals(
1687          1, self.device.KillAll('some.process', signum=device_signal.SIGTERM))
1688
1689  def testKillAll_multipleInstances(self):
1690    with self.assertCalls((self.call.device.ListProcesses('some.process'),
1691                           Processes(('some.process', 1234),
1692                                     ('some.process', 4567))),
1693                          (self.call.adb.Shell('kill -15 1234 4567'), '')):
1694      self.assertEquals(
1695          2, self.device.KillAll('some.process', signum=device_signal.SIGTERM))
1696
1697
1698class DeviceUtilsStartActivityTest(DeviceUtilsTest):
1699  def testStartActivity_actionOnly(self):
1700    test_intent = intent.Intent(action='android.intent.action.VIEW')
1701    with self.assertCall(
1702        self.call.adb.Shell('am start '
1703                            '-a android.intent.action.VIEW'),
1704        'Starting: Intent { act=android.intent.action.VIEW }'):
1705      self.device.StartActivity(test_intent)
1706
1707  def testStartActivity_success(self):
1708    test_intent = intent.Intent(
1709        action='android.intent.action.VIEW',
1710        package=TEST_PACKAGE,
1711        activity='.Main')
1712    with self.assertCall(
1713        self.call.adb.Shell('am start '
1714                            '-a android.intent.action.VIEW '
1715                            '-n test.package/.Main'),
1716        'Starting: Intent { act=android.intent.action.VIEW }'):
1717      self.device.StartActivity(test_intent)
1718
1719  def testStartActivity_failure(self):
1720    test_intent = intent.Intent(
1721        action='android.intent.action.VIEW',
1722        package=TEST_PACKAGE,
1723        activity='.Main')
1724    with self.assertCall(
1725        self.call.adb.Shell('am start '
1726                            '-a android.intent.action.VIEW '
1727                            '-n test.package/.Main'),
1728        'Error: Failed to start test activity'):
1729      with self.assertRaises(device_errors.CommandFailedError):
1730        self.device.StartActivity(test_intent)
1731
1732  def testStartActivity_blocking(self):
1733    test_intent = intent.Intent(
1734        action='android.intent.action.VIEW',
1735        package=TEST_PACKAGE,
1736        activity='.Main')
1737    with self.assertCall(
1738        self.call.adb.Shell('am start '
1739                            '-W '
1740                            '-a android.intent.action.VIEW '
1741                            '-n test.package/.Main'),
1742        'Starting: Intent { act=android.intent.action.VIEW }'):
1743      self.device.StartActivity(test_intent, blocking=True)
1744
1745  def testStartActivity_withCategory(self):
1746    test_intent = intent.Intent(
1747        action='android.intent.action.VIEW',
1748        package=TEST_PACKAGE,
1749        activity='.Main',
1750        category='android.intent.category.HOME')
1751    with self.assertCall(
1752        self.call.adb.Shell('am start '
1753                            '-a android.intent.action.VIEW '
1754                            '-c android.intent.category.HOME '
1755                            '-n test.package/.Main'),
1756        'Starting: Intent { act=android.intent.action.VIEW }'):
1757      self.device.StartActivity(test_intent)
1758
1759  def testStartActivity_withMultipleCategories(self):
1760    test_intent = intent.Intent(
1761        action='android.intent.action.VIEW',
1762        package=TEST_PACKAGE,
1763        activity='.Main',
1764        category=[
1765            'android.intent.category.HOME', 'android.intent.category.BROWSABLE'
1766        ])
1767    with self.assertCall(
1768        self.call.adb.Shell('am start '
1769                            '-a android.intent.action.VIEW '
1770                            '-c android.intent.category.HOME '
1771                            '-c android.intent.category.BROWSABLE '
1772                            '-n test.package/.Main'),
1773        'Starting: Intent { act=android.intent.action.VIEW }'):
1774      self.device.StartActivity(test_intent)
1775
1776  def testStartActivity_withData(self):
1777    test_intent = intent.Intent(
1778        action='android.intent.action.VIEW',
1779        package=TEST_PACKAGE,
1780        activity='.Main',
1781        data='http://www.google.com/')
1782    with self.assertCall(
1783        self.call.adb.Shell('am start '
1784                            '-a android.intent.action.VIEW '
1785                            '-d http://www.google.com/ '
1786                            '-n test.package/.Main'),
1787        'Starting: Intent { act=android.intent.action.VIEW }'):
1788      self.device.StartActivity(test_intent)
1789
1790  def testStartActivity_withStringExtra(self):
1791    test_intent = intent.Intent(
1792        action='android.intent.action.VIEW',
1793        package=TEST_PACKAGE,
1794        activity='.Main',
1795        extras={'foo': 'test'})
1796    with self.assertCall(
1797        self.call.adb.Shell('am start '
1798                            '-a android.intent.action.VIEW '
1799                            '-n test.package/.Main '
1800                            '--es foo test'),
1801        'Starting: Intent { act=android.intent.action.VIEW }'):
1802      self.device.StartActivity(test_intent)
1803
1804  def testStartActivity_withBoolExtra(self):
1805    test_intent = intent.Intent(
1806        action='android.intent.action.VIEW',
1807        package=TEST_PACKAGE,
1808        activity='.Main',
1809        extras={'foo': True})
1810    with self.assertCall(
1811        self.call.adb.Shell('am start '
1812                            '-a android.intent.action.VIEW '
1813                            '-n test.package/.Main '
1814                            '--ez foo True'),
1815        'Starting: Intent { act=android.intent.action.VIEW }'):
1816      self.device.StartActivity(test_intent)
1817
1818  def testStartActivity_withIntExtra(self):
1819    test_intent = intent.Intent(
1820        action='android.intent.action.VIEW',
1821        package=TEST_PACKAGE,
1822        activity='.Main',
1823        extras={'foo': 123})
1824    with self.assertCall(
1825        self.call.adb.Shell('am start '
1826                            '-a android.intent.action.VIEW '
1827                            '-n test.package/.Main '
1828                            '--ei foo 123'),
1829        'Starting: Intent { act=android.intent.action.VIEW }'):
1830      self.device.StartActivity(test_intent)
1831
1832  def testStartActivity_withTraceFile(self):
1833    test_intent = intent.Intent(
1834        action='android.intent.action.VIEW',
1835        package=TEST_PACKAGE,
1836        activity='.Main')
1837    with self.assertCall(
1838        self.call.adb.Shell('am start '
1839                            '--start-profiler test_trace_file.out '
1840                            '-a android.intent.action.VIEW '
1841                            '-n test.package/.Main'),
1842        'Starting: Intent { act=android.intent.action.VIEW }'):
1843      self.device.StartActivity(
1844          test_intent, trace_file_name='test_trace_file.out')
1845
1846  def testStartActivity_withForceStop(self):
1847    test_intent = intent.Intent(
1848        action='android.intent.action.VIEW',
1849        package=TEST_PACKAGE,
1850        activity='.Main')
1851    with self.assertCall(
1852        self.call.adb.Shell('am start '
1853                            '-S '
1854                            '-a android.intent.action.VIEW '
1855                            '-n test.package/.Main'),
1856        'Starting: Intent { act=android.intent.action.VIEW }'):
1857      self.device.StartActivity(test_intent, force_stop=True)
1858
1859  def testStartActivity_withFlags(self):
1860    test_intent = intent.Intent(
1861        action='android.intent.action.VIEW',
1862        package=TEST_PACKAGE,
1863        activity='.Main',
1864        flags=[
1865            intent.FLAG_ACTIVITY_NEW_TASK,
1866            intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
1867        ])
1868    with self.assertCall(
1869        self.call.adb.Shell('am start '
1870                            '-a android.intent.action.VIEW '
1871                            '-n test.package/.Main '
1872                            '-f 0x10200000'),
1873        'Starting: Intent { act=android.intent.action.VIEW }'):
1874      self.device.StartActivity(test_intent)
1875
1876
1877class DeviceUtilsStartServiceTest(DeviceUtilsTest):
1878  def testStartService_success(self):
1879    test_intent = intent.Intent(
1880        action='android.intent.action.START',
1881        package=TEST_PACKAGE,
1882        activity='.Main')
1883    with self.patch_call(
1884        self.call.device.build_version_sdk, return_value=version_codes.NOUGAT):
1885      with self.assertCall(
1886          self.call.adb.Shell('am startservice '
1887                              '-a android.intent.action.START '
1888                              '-n test.package/.Main'),
1889          'Starting service: Intent { act=android.intent.action.START }'):
1890        self.device.StartService(test_intent)
1891
1892  def testStartService_failure(self):
1893    test_intent = intent.Intent(
1894        action='android.intent.action.START',
1895        package=TEST_PACKAGE,
1896        activity='.Main')
1897    with self.patch_call(
1898        self.call.device.build_version_sdk, return_value=version_codes.NOUGAT):
1899      with self.assertCall(
1900          self.call.adb.Shell('am startservice '
1901                              '-a android.intent.action.START '
1902                              '-n test.package/.Main'),
1903          'Error: Failed to start test service'):
1904        with self.assertRaises(device_errors.CommandFailedError):
1905          self.device.StartService(test_intent)
1906
1907  def testStartService_withUser(self):
1908    test_intent = intent.Intent(
1909        action='android.intent.action.START',
1910        package=TEST_PACKAGE,
1911        activity='.Main')
1912    with self.patch_call(
1913        self.call.device.build_version_sdk, return_value=version_codes.NOUGAT):
1914      with self.assertCall(
1915          self.call.adb.Shell('am startservice '
1916                              '--user TestUser '
1917                              '-a android.intent.action.START '
1918                              '-n test.package/.Main'),
1919          'Starting service: Intent { act=android.intent.action.START }'):
1920        self.device.StartService(test_intent, user_id='TestUser')
1921
1922  def testStartService_onOreo(self):
1923    test_intent = intent.Intent(
1924        action='android.intent.action.START',
1925        package=TEST_PACKAGE,
1926        activity='.Main')
1927    with self.patch_call(
1928        self.call.device.build_version_sdk, return_value=version_codes.OREO):
1929      with self.assertCall(
1930          self.call.adb.Shell('am start-service '
1931                              '-a android.intent.action.START '
1932                              '-n test.package/.Main'),
1933          'Starting service: Intent { act=android.intent.action.START }'):
1934        self.device.StartService(test_intent)
1935
1936
1937class DeviceUtilsStartInstrumentationTest(DeviceUtilsTest):
1938  def testStartInstrumentation_nothing(self):
1939    with self.assertCalls(
1940        self.call.device.RunShellCommand(
1941            'p=test.package;am instrument "$p"/.TestInstrumentation',
1942            shell=True,
1943            check_return=True,
1944            large_output=True)):
1945      self.device.StartInstrumentation(
1946          'test.package/.TestInstrumentation',
1947          finish=False,
1948          raw=False,
1949          extras=None)
1950
1951  def testStartInstrumentation_finish(self):
1952    with self.assertCalls((self.call.device.RunShellCommand(
1953        'p=test.package;am instrument -w "$p"/.TestInstrumentation',
1954        shell=True,
1955        check_return=True,
1956        large_output=True), ['OK (1 test)'])):
1957      output = self.device.StartInstrumentation(
1958          'test.package/.TestInstrumentation',
1959          finish=True,
1960          raw=False,
1961          extras=None)
1962      self.assertEquals(['OK (1 test)'], output)
1963
1964  def testStartInstrumentation_raw(self):
1965    with self.assertCalls(
1966        self.call.device.RunShellCommand(
1967            'p=test.package;am instrument -r "$p"/.TestInstrumentation',
1968            shell=True,
1969            check_return=True,
1970            large_output=True)):
1971      self.device.StartInstrumentation(
1972          'test.package/.TestInstrumentation',
1973          finish=False,
1974          raw=True,
1975          extras=None)
1976
1977  def testStartInstrumentation_extras(self):
1978    with self.assertCalls(
1979        self.call.device.RunShellCommand(
1980            'p=test.package;am instrument -e "$p".foo Foo -e bar \'Val \'"$p" '
1981            '"$p"/.TestInstrumentation',
1982            shell=True,
1983            check_return=True,
1984            large_output=True)):
1985      self.device.StartInstrumentation(
1986          'test.package/.TestInstrumentation',
1987          finish=False,
1988          raw=False,
1989          extras={
1990              'test.package.foo': 'Foo',
1991              'bar': 'Val test.package'
1992          })
1993
1994
1995class DeviceUtilsBroadcastIntentTest(DeviceUtilsTest):
1996  def testBroadcastIntent_noExtras(self):
1997    test_intent = intent.Intent(action='test.package.with.an.INTENT')
1998    with self.assertCall(
1999        self.call.adb.Shell('am broadcast -a test.package.with.an.INTENT'),
2000        'Broadcasting: Intent { act=test.package.with.an.INTENT } '):
2001      self.device.BroadcastIntent(test_intent)
2002
2003  def testBroadcastIntent_withExtra(self):
2004    test_intent = intent.Intent(
2005        action='test.package.with.an.INTENT', extras={'foo': 'bar value'})
2006    with self.assertCall(
2007        self.call.adb.Shell(
2008            "am broadcast -a test.package.with.an.INTENT --es foo 'bar value'"),
2009        'Broadcasting: Intent { act=test.package.with.an.INTENT } '):
2010      self.device.BroadcastIntent(test_intent)
2011
2012  def testBroadcastIntent_withExtra_noValue(self):
2013    test_intent = intent.Intent(
2014        action='test.package.with.an.INTENT', extras={'foo': None})
2015    with self.assertCall(
2016        self.call.adb.Shell(
2017            'am broadcast -a test.package.with.an.INTENT --esn foo'),
2018        'Broadcasting: Intent { act=test.package.with.an.INTENT } '):
2019      self.device.BroadcastIntent(test_intent)
2020
2021
2022class DeviceUtilsGoHomeTest(DeviceUtilsTest):
2023  def testGoHome_popupsExist(self):
2024    with self.assertCalls(
2025        (self.call.device.RunShellCommand(['dumpsys', 'window', 'windows'],
2026                                          check_return=True,
2027                                          large_output=True), []),
2028        (self.call.device.RunShellCommand([
2029            'am', 'start', '-W', '-a', 'android.intent.action.MAIN', '-c',
2030            'android.intent.category.HOME'
2031        ],
2032                                          check_return=True),
2033         'Starting: Intent { act=android.intent.action.MAIN }\r\n'
2034         ''),
2035        (self.call.device.RunShellCommand(['dumpsys', 'window', 'windows'],
2036                                          check_return=True,
2037                                          large_output=True), []),
2038        (self.call.device.RunShellCommand(['input', 'keyevent', '66'],
2039                                          check_return=True)),
2040        (self.call.device.RunShellCommand(['input', 'keyevent', '4'],
2041                                          check_return=True)),
2042        (self.call.device.RunShellCommand(['dumpsys', 'window', 'windows'],
2043                                          check_return=True,
2044                                          large_output=True),
2045         ['mCurrentFocus Launcher'])):
2046      self.device.GoHome()
2047
2048  def testGoHome_willRetry(self):
2049    with self.assertCalls(
2050        (self.call.device.RunShellCommand(['dumpsys', 'window', 'windows'],
2051                                          check_return=True,
2052                                          large_output=True), []),
2053        (self.call.device.RunShellCommand([
2054            'am', 'start', '-W', '-a', 'android.intent.action.MAIN', '-c',
2055            'android.intent.category.HOME'
2056        ],
2057                                          check_return=True),
2058         'Starting: Intent { act=android.intent.action.MAIN }\r\n'
2059         ''),
2060        (self.call.device.RunShellCommand(['dumpsys', 'window', 'windows'],
2061                                          check_return=True,
2062                                          large_output=True), []),
2063        (self.call.device.RunShellCommand(
2064            ['input', 'keyevent', '66'],
2065            check_return=True,
2066        )), (self.call.device.RunShellCommand(['input', 'keyevent', '4'],
2067                                              check_return=True)),
2068        (self.call.device.RunShellCommand(['dumpsys', 'window', 'windows'],
2069                                          check_return=True,
2070                                          large_output=True), []),
2071        (self.call.device.RunShellCommand(['input', 'keyevent', '66'],
2072                                          check_return=True)),
2073        (self.call.device.RunShellCommand(['input', 'keyevent', '4'],
2074                                          check_return=True)),
2075        (self.call.device.RunShellCommand(['dumpsys', 'window', 'windows'],
2076                                          check_return=True,
2077                                          large_output=True),
2078         self.TimeoutError())):
2079      with self.assertRaises(device_errors.CommandTimeoutError):
2080        self.device.GoHome()
2081
2082  def testGoHome_alreadyFocused(self):
2083    with self.assertCall(
2084        self.call.device.RunShellCommand(['dumpsys', 'window', 'windows'],
2085                                         check_return=True,
2086                                         large_output=True),
2087        ['mCurrentFocus Launcher']):
2088      self.device.GoHome()
2089
2090  def testGoHome_alreadyFocusedAlternateCase(self):
2091    with self.assertCall(
2092        self.call.device.RunShellCommand(['dumpsys', 'window', 'windows'],
2093                                         check_return=True,
2094                                         large_output=True),
2095        [' mCurrentFocus .launcher/.']):
2096      self.device.GoHome()
2097
2098  def testGoHome_obtainsFocusAfterGoingHome(self):
2099    with self.assertCalls(
2100        (self.call.device.RunShellCommand(['dumpsys', 'window', 'windows'],
2101                                          check_return=True,
2102                                          large_output=True), []),
2103        (self.call.device.RunShellCommand([
2104            'am', 'start', '-W', '-a', 'android.intent.action.MAIN', '-c',
2105            'android.intent.category.HOME'
2106        ],
2107                                          check_return=True),
2108         'Starting: Intent { act=android.intent.action.MAIN }\r\n'
2109         ''), (self.call.device.RunShellCommand(
2110             ['dumpsys', 'window', 'windows'],
2111             check_return=True,
2112             large_output=True), ['mCurrentFocus Launcher'])):
2113      self.device.GoHome()
2114
2115
2116class DeviceUtilsForceStopTest(DeviceUtilsTest):
2117  def testForceStop(self):
2118    with self.assertCalls(
2119        (self.call.device.GetApplicationPids(TEST_PACKAGE), [1111]),
2120        (self.call.device.RunShellCommand(['am', 'force-stop', TEST_PACKAGE],
2121                                          check_return=True), ['Success'])):
2122      self.device.ForceStop(TEST_PACKAGE)
2123
2124  def testForceStop_NoProcessFound(self):
2125    with self.assertCall(self.call.device.GetApplicationPids(TEST_PACKAGE), []):
2126      self.device.ForceStop(TEST_PACKAGE)
2127
2128
2129class DeviceUtilsClearApplicationStateTest(DeviceUtilsTest):
2130  def testClearApplicationState_setPermissions(self):
2131    with self.assertCalls(
2132        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '17'),
2133        (self.call.device._GetApplicationPathsInternal('this.package.exists'),
2134         ['/data/app/this.package.exists.apk']),
2135        (self.call.device.RunShellCommand(
2136            ['pm', 'clear', 'this.package.exists'], check_return=True),
2137         ['Success']),
2138        (self.call.device.GrantPermissions('this.package.exists', ['p1']), [])):
2139      self.device.ClearApplicationState(
2140          'this.package.exists', permissions=['p1'])
2141
2142  def testClearApplicationState_packageDoesntExist(self):
2143    with self.assertCalls(
2144        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '11'),
2145        (self.call.device._GetApplicationPathsInternal('does.not.exist'), [])):
2146      self.device.ClearApplicationState('does.not.exist')
2147
2148  def testClearApplicationState_packageDoesntExistOnAndroidJBMR2OrAbove(self):
2149    with self.assertCalls(
2150        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '18'),
2151        (self.call.device.RunShellCommand(
2152            ['pm', 'clear', 'this.package.does.not.exist'], check_return=True),
2153         ['Failed'])):
2154      self.device.ClearApplicationState('this.package.does.not.exist')
2155
2156  def testClearApplicationState_packageExists(self):
2157    with self.assertCalls(
2158        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '17'),
2159        (self.call.device._GetApplicationPathsInternal('this.package.exists'),
2160         ['/data/app/this.package.exists.apk']),
2161        (self.call.device.RunShellCommand(
2162            ['pm', 'clear', 'this.package.exists'], check_return=True),
2163         ['Success'])):
2164      self.device.ClearApplicationState('this.package.exists')
2165
2166  def testClearApplicationState_packageExistsOnAndroidJBMR2OrAbove(self):
2167    with self.assertCalls(
2168        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '18'),
2169        (self.call.device.RunShellCommand(
2170            ['pm', 'clear', 'this.package.exists'], check_return=True),
2171         ['Success'])):
2172      self.device.ClearApplicationState('this.package.exists')
2173
2174
2175class DeviceUtilsSendKeyEventTest(DeviceUtilsTest):
2176  def testSendKeyEvent(self):
2177    with self.assertCall(self.call.adb.Shell('input keyevent 66'), ''):
2178      self.device.SendKeyEvent(66)
2179
2180
2181class DeviceUtilsPushChangedFilesIndividuallyTest(DeviceUtilsTest):
2182  def testPushChangedFilesIndividually_empty(self):
2183    test_files = []
2184    with self.assertCalls():
2185      self.device._PushChangedFilesIndividually(test_files)
2186
2187  def testPushChangedFilesIndividually_single(self):
2188    test_files = [('/test/host/path', '/test/device/path')]
2189    with self.assertCalls(self.call.adb.Push(*test_files[0])):
2190      self.device._PushChangedFilesIndividually(test_files)
2191
2192  def testPushChangedFilesIndividually_multiple(self):
2193    test_files = [('/test/host/path/file1', '/test/device/path/file1'),
2194                  ('/test/host/path/file2', '/test/device/path/file2')]
2195    with self.assertCalls(
2196        self.call.adb.Push(*test_files[0]), self.call.adb.Push(*test_files[1])):
2197      self.device._PushChangedFilesIndividually(test_files)
2198
2199
2200class DeviceUtilsPushChangedFilesZippedTest(DeviceUtilsTest):
2201  def testPushChangedFilesZipped_noUnzipCommand(self):
2202    test_files = [('/test/host/path/file1', '/test/device/path/file1')]
2203    with self.assertCalls((self.call.device._MaybeInstallCommands(), False)):
2204      self.assertFalse(
2205          self.device._PushChangedFilesZipped(test_files, ['/test/dir']))
2206
2207  def _testPushChangedFilesZipped_spec(self, test_files, test_dirs):
2208    @contextlib.contextmanager
2209    def mock_zip_temp_dir():
2210      yield '/test/temp/dir'
2211
2212    expected_cmd = ''.join([
2213        '\n  /data/local/tmp/bin/unzip %s &&',
2214        ' (for dir in %s\n  do\n    chmod -R 777 "$dir" || exit 1\n',
2215        '  done)\n'
2216    ]) % ('/sdcard/foo123.zip', ' '.join(test_dirs))
2217    with self.assertCalls(
2218        (self.call.device._MaybeInstallCommands(), True),
2219        (mock.call.py_utils.tempfile_ext.NamedTemporaryDirectory(),
2220         mock_zip_temp_dir), (mock.call.devil.utils.zip_utils.WriteZipFile(
2221             '/test/temp/dir/tmp.zip', test_files)),
2222        (mock.call.os.path.getsize('/test/temp/dir/tmp.zip'), 123),
2223        (self.call.device.NeedsSU(), True),
2224        (mock.call.devil.android.device_temp_file.DeviceTempFile(
2225            self.adb, suffix='.zip'), MockTempFile('/sdcard/foo123.zip')),
2226        self.call.adb.Push('/test/temp/dir/tmp.zip', '/sdcard/foo123.zip'),
2227        (mock.call.devil.android.device_temp_file.DeviceTempFile(
2228            self.adb, suffix='.sh'), MockTempFile('/sdcard/temp-123.sh')),
2229        self.call.device.WriteFile('/sdcard/temp-123.sh', expected_cmd),
2230        (self.call.device.RunShellCommand(['source', '/sdcard/temp-123.sh'],
2231                                          check_return=True,
2232                                          as_root=True))):
2233      self.assertTrue(
2234          self.device._PushChangedFilesZipped(test_files, test_dirs))
2235
2236  def testPushChangedFilesZipped_single(self):
2237    self._testPushChangedFilesZipped_spec(
2238        [('/test/host/path/file1', '/test/device/path/file1')],
2239        ['/test/dir1'])
2240
2241  def testPushChangedFilesZipped_multiple(self):
2242    self._testPushChangedFilesZipped_spec(
2243        [('/test/host/path/file1', '/test/device/path/file1'),
2244         ('/test/host/path/file2', '/test/device/path/file2')],
2245        ['/test/dir1', '/test/dir2'])
2246
2247
2248class DeviceUtilsPathExistsTest(DeviceUtilsTest):
2249  def testPathExists_pathExists(self):
2250    with self.assertCall(
2251        self.call.device.RunShellCommand(['test', '-e', '/path/file exists'],
2252                                         as_root=False,
2253                                         check_return=True,
2254                                         timeout=10,
2255                                         retries=0), []):
2256      self.assertTrue(self.device.PathExists('/path/file exists'))
2257
2258  def testPathExists_multiplePathExists(self):
2259    with self.assertCall(
2260        self.call.device.RunShellCommand(
2261            ['test', '-e', '/path 1', '-a', '-e', '/path2'],
2262            as_root=False,
2263            check_return=True,
2264            timeout=10,
2265            retries=0), []):
2266      self.assertTrue(self.device.PathExists(('/path 1', '/path2')))
2267
2268  def testPathExists_pathDoesntExist(self):
2269    with self.assertCall(
2270        self.call.device.RunShellCommand(
2271            ['test', '-e', '/path/file.not.exists'],
2272            as_root=False,
2273            check_return=True,
2274            timeout=10,
2275            retries=0), self.ShellError()):
2276      self.assertFalse(self.device.PathExists('/path/file.not.exists'))
2277
2278  def testPathExists_asRoot(self):
2279    with self.assertCall(
2280        self.call.device.RunShellCommand(['test', '-e', '/root/path/exists'],
2281                                         as_root=True,
2282                                         check_return=True,
2283                                         timeout=10,
2284                                         retries=0), self.ShellError()):
2285      self.assertFalse(
2286          self.device.PathExists('/root/path/exists', as_root=True))
2287
2288  def testFileExists_pathDoesntExist(self):
2289    with self.assertCall(
2290        self.call.device.RunShellCommand(
2291            ['test', '-e', '/path/file.not.exists'],
2292            as_root=False,
2293            check_return=True,
2294            timeout=10,
2295            retries=0), self.ShellError()):
2296      self.assertFalse(self.device.FileExists('/path/file.not.exists'))
2297
2298
2299class DeviceUtilsRemovePathTest(DeviceUtilsTest):
2300  def testRemovePath_regular(self):
2301    with self.assertCall(
2302        self.call.device.RunShellCommand(['rm', 'some file'],
2303                                         as_root=False,
2304                                         check_return=True), []):
2305      self.device.RemovePath('some file')
2306
2307  def testRemovePath_withForce(self):
2308    with self.assertCall(
2309        self.call.device.RunShellCommand(['rm', '-f', 'some file'],
2310                                         as_root=False,
2311                                         check_return=True), []):
2312      self.device.RemovePath('some file', force=True)
2313
2314  def testRemovePath_recursively(self):
2315    with self.assertCall(
2316        self.call.device.RunShellCommand(['rm', '-r', '/remove/this/dir'],
2317                                         as_root=False,
2318                                         check_return=True), []):
2319      self.device.RemovePath('/remove/this/dir', recursive=True)
2320
2321  def testRemovePath_withRoot(self):
2322    with self.assertCall(
2323        self.call.device.RunShellCommand(['rm', 'some file'],
2324                                         as_root=True,
2325                                         check_return=True), []):
2326      self.device.RemovePath('some file', as_root=True)
2327
2328  def testRemovePath_manyPaths(self):
2329    with self.assertCall(
2330        self.call.device.RunShellCommand(['rm', 'eeny', 'meeny', 'miny', 'moe'],
2331                                         as_root=False,
2332                                         check_return=True), []):
2333      self.device.RemovePath(['eeny', 'meeny', 'miny', 'moe'])
2334
2335
2336class DeviceUtilsPullFileTest(DeviceUtilsTest):
2337  def testPullFile_existsOnDevice(self):
2338    with mock.patch('os.path.exists', return_value=True):
2339      with self.assertCall(
2340          self.call.adb.Pull('/data/app/test.file.exists',
2341                             '/test/file/host/path')):
2342        self.device.PullFile('/data/app/test.file.exists',
2343                             '/test/file/host/path')
2344
2345  def testPullFile_doesntExistOnDevice(self):
2346    with mock.patch('os.path.exists', return_value=True):
2347      with self.assertCall(
2348          self.call.adb.Pull('/data/app/test.file.does.not.exist',
2349                             '/test/file/host/path'),
2350          self.CommandError('remote object does not exist')):
2351        with self.assertRaises(device_errors.CommandFailedError):
2352          self.device.PullFile('/data/app/test.file.does.not.exist',
2353                               '/test/file/host/path')
2354
2355  def testPullFile_asRoot(self):
2356    with mock.patch('os.path.exists', return_value=True):
2357      with self.assertCalls(
2358          (self.call.device.NeedsSU(), True), (self.call.device.PathExists(
2359              '/this/file/can.be.read.with.su', as_root=True), True),
2360          (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb),
2361           MockTempFile('/sdcard/tmp/on.device')),
2362          self.call.device.RunShellCommand(
2363              'SRC=/this/file/can.be.read.with.su DEST=/sdcard/tmp/on.device;'
2364              'cp "$SRC" "$DEST" && chmod 666 "$DEST"',
2365              shell=True,
2366              as_root=True,
2367              check_return=True), (self.call.adb.Pull('/sdcard/tmp/on.device',
2368                                                      '/test/file/host/path'))):
2369        self.device.PullFile(
2370            '/this/file/can.be.read.with.su',
2371            '/test/file/host/path',
2372            as_root=True)
2373
2374  def testPullFile_asRootDoesntExistOnDevice(self):
2375    with mock.patch('os.path.exists', return_value=True):
2376      with self.assertCalls(
2377          (self.call.device.NeedsSU(), True), (self.call.device.PathExists(
2378              '/data/app/test.file.does.not.exist', as_root=True), False)):
2379        with self.assertRaises(device_errors.CommandFailedError):
2380          self.device.PullFile(
2381              '/data/app/test.file.does.not.exist',
2382              '/test/file/host/path',
2383              as_root=True)
2384
2385
2386class DeviceUtilsReadFileTest(DeviceUtilsTest):
2387  def testReadFileWithPull_success(self):
2388    tmp_host_dir = '/tmp/dir/on.host/'
2389    tmp_host = MockTempFile('/tmp/dir/on.host/tmp_ReadFileWithPull')
2390    tmp_host.file.read.return_value = 'some interesting contents'
2391    with self.assertCalls(
2392        (mock.call.tempfile.mkdtemp(), tmp_host_dir),
2393        (self.call.adb.Pull('/path/to/device/file', mock.ANY)),
2394        (mock.call.__builtin__.open(mock.ANY, 'r'), tmp_host) if six.PY2 else \
2395            (mock.call.builtins.open(mock.ANY, 'r'), tmp_host),
2396        (mock.call.os.path.exists(tmp_host_dir), True),
2397        (mock.call.shutil.rmtree(tmp_host_dir), None)):
2398      self.assertEquals('some interesting contents',
2399                        self.device._ReadFileWithPull('/path/to/device/file'))
2400    tmp_host.file.read.assert_called_once_with()
2401
2402  def testReadFileWithPull_rejected(self):
2403    tmp_host_dir = '/tmp/dir/on.host/'
2404    with self.assertCalls((mock.call.tempfile.mkdtemp(), tmp_host_dir),
2405                          (self.call.adb.Pull('/path/to/device/file', mock.ANY),
2406                           self.CommandError()),
2407                          (mock.call.os.path.exists(tmp_host_dir), True),
2408                          (mock.call.shutil.rmtree(tmp_host_dir), None)):
2409      with self.assertRaises(device_errors.CommandFailedError):
2410        self.device._ReadFileWithPull('/path/to/device/file')
2411
2412  def testReadFile_withSU_zeroSize(self):
2413    with self.assertCalls(
2414        (self.call.device.NeedsSU(), True),
2415        (self.call.device.FileSize(
2416            '/this/file/has/zero/size', as_root=True), 0),
2417        (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb),
2418         MockTempFile('/sdcard/tmp/on.device')),
2419        self.call.device.RunShellCommand(
2420            'SRC=/this/file/has/zero/size DEST=/sdcard/tmp/on.device;'
2421            'cp "$SRC" "$DEST" && chmod 666 "$DEST"',
2422            shell=True,
2423            as_root=True,
2424            check_return=True),
2425        (self.call.device._ReadFileWithPull('/sdcard/tmp/on.device'),
2426         'but it has contents\n')):
2427      self.assertEqual('but it has contents\n',
2428                       self.device.ReadFile('/this/file/has/zero/size',
2429                       as_root=True))
2430
2431  def testReadFile_withSU(self):
2432    with self.assertCalls(
2433        (self.call.device.NeedsSU(), True),
2434        (self.call.device.FileSize(
2435            '/this/file/can.be.read.with.su', as_root=True), 256),
2436        (self.call.device.RunShellCommand(
2437            ['cat', '/this/file/can.be.read.with.su'],
2438            as_root=True,
2439            check_return=True), ['this is a test file', 'read with su'])):
2440      self.assertEqual(
2441          'this is a test file\nread with su\n',
2442          self.device.ReadFile('/this/file/can.be.read.with.su', as_root=True))
2443
2444  def testReadFile_withSU_doesNotExist(self):
2445    with self.assertCalls(
2446        (self.call.device.NeedsSU(), True),
2447        (self.call.device.FileSize('/this/file/does.not.exist', as_root=True),
2448         self.CommandError('File does not exist'))):
2449      with self.assertRaises(device_errors.CommandFailedError):
2450        self.device.ReadFile('/this/file/does.not.exist', as_root=True)
2451
2452  def testReadFile_withPull(self):
2453    contents = 'a' * 123456
2454    with self.assertCalls(
2455        (self.call.device._ReadFileWithPull('/read/this/big/test/file'),
2456         contents)):
2457      self.assertEqual(contents,
2458                       self.device.ReadFile('/read/this/big/test/file'))
2459
2460  def testReadFile_withPullAndSU(self):
2461    contents = 'b' * 123456
2462    with self.assertCalls(
2463        (self.call.device.NeedsSU(), True),
2464        (self.call.device.FileSize(
2465            '/this/big/file/can.be.read.with.su', as_root=True), 123456),
2466        (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb),
2467         MockTempFile('/sdcard/tmp/on.device')),
2468        self.call.device.RunShellCommand(
2469            'SRC=/this/big/file/can.be.read.with.su DEST=/sdcard/tmp/on.device;'
2470            'cp "$SRC" "$DEST" && chmod 666 "$DEST"',
2471            shell=True,
2472            as_root=True,
2473            check_return=True),
2474        (self.call.device._ReadFileWithPull('/sdcard/tmp/on.device'),
2475         contents)):
2476      self.assertEqual(
2477          contents,
2478          self.device.ReadFile(
2479              '/this/big/file/can.be.read.with.su', as_root=True))
2480
2481  def testReadFile_forcePull(self):
2482    contents = 'a' * 123456
2483    with self.assertCall(
2484        self.call.device._ReadFileWithPull('/read/this/big/test/file'),
2485        contents):
2486      self.assertEqual(
2487          contents,
2488          self.device.ReadFile('/read/this/big/test/file', force_pull=True))
2489
2490
2491class DeviceUtilsWriteFileTest(DeviceUtilsTest):
2492  def testWriteFileWithPush_success(self):
2493    tmp_host = MockTempFile('/tmp/file/on.host')
2494    contents = 'some interesting contents'
2495    with self.assertCalls((mock.call.tempfile.NamedTemporaryFile(), tmp_host),
2496                          self.call.adb.Push('/tmp/file/on.host',
2497                                             '/path/to/device/file')):
2498      self.device._WriteFileWithPush('/path/to/device/file', contents)
2499    tmp_host.file.write.assert_called_once_with(contents)
2500
2501  def testWriteFileWithPush_rejected(self):
2502    tmp_host = MockTempFile('/tmp/file/on.host')
2503    contents = 'some interesting contents'
2504    with self.assertCalls(
2505        (mock.call.tempfile.NamedTemporaryFile(), tmp_host),
2506        (self.call.adb.Push('/tmp/file/on.host', '/path/to/device/file'),
2507         self.CommandError())):
2508      with self.assertRaises(device_errors.CommandFailedError):
2509        self.device._WriteFileWithPush('/path/to/device/file', contents)
2510
2511  def testWriteFile_withPush(self):
2512    contents = 'some large contents ' * 26  # 20 * 26 = 520 chars
2513    with self.assertCalls(
2514        self.call.device._WriteFileWithPush('/path/to/device/file', contents)):
2515      self.device.WriteFile('/path/to/device/file', contents)
2516
2517  def testWriteFile_withPushForced(self):
2518    contents = 'tiny contents'
2519    with self.assertCalls(
2520        self.call.device._WriteFileWithPush('/path/to/device/file', contents)):
2521      self.device.WriteFile('/path/to/device/file', contents, force_push=True)
2522
2523  def testWriteFile_withPushAndSU(self):
2524    contents = 'some large contents ' * 26  # 20 * 26 = 520 chars
2525    with self.assertCalls(
2526        (self.call.device.NeedsSU(), True),
2527        (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb),
2528         MockTempFile('/sdcard/tmp/on.device')),
2529        self.call.device._WriteFileWithPush('/sdcard/tmp/on.device', contents),
2530        self.call.device.RunShellCommand(
2531            ['cp', '/sdcard/tmp/on.device', '/path/to/device/file'],
2532            as_root=True,
2533            check_return=True)):
2534      self.device.WriteFile('/path/to/device/file', contents, as_root=True)
2535
2536  def testWriteFile_withEcho(self):
2537    with self.assertCall(
2538        self.call.adb.Shell("echo -n the.contents > /test/file/to.write"), ''):
2539      self.device.WriteFile('/test/file/to.write', 'the.contents')
2540
2541  def testWriteFile_withEchoAndQuotes(self):
2542    with self.assertCall(
2543        self.call.adb.Shell("echo -n 'the contents' > '/test/file/to write'"),
2544        ''):
2545      self.device.WriteFile('/test/file/to write', 'the contents')
2546
2547  def testWriteFile_withEchoAndSU(self):
2548    expected_cmd_without_su = "sh -c 'echo -n contents > /test/file'"
2549    expected_cmd = 'su -c %s' % expected_cmd_without_su
2550    with self.assertCalls(
2551        (self.call.device.NeedsSU(), True),
2552        (self.call.device._Su(expected_cmd_without_su), expected_cmd),
2553        (self.call.adb.Shell(expected_cmd), '')):
2554      self.device.WriteFile('/test/file', 'contents', as_root=True)
2555
2556
2557class DeviceUtilsStatDirectoryTest(DeviceUtilsTest):
2558  # Note: Also tests ListDirectory in testStatDirectory_fileList.
2559
2560  EXAMPLE_LS_OUTPUT = [
2561      'total 12345',
2562      'drwxr-xr-x  19 root   root          0 1970-04-06 18:03 .',
2563      'drwxr-xr-x  19 root   root          0 1970-04-06 18:03 ..',
2564      'drwxr-xr-x   6 root   root            1970-01-01 00:00 some_dir',
2565      '-rw-r--r--   1 root   root        723 1971-01-01 07:04 some_file',
2566      '-rw-r-----   1 root   root        327 2009-02-13 23:30 My Music File',
2567      # Some Android versions escape spaces in file names
2568      '-rw-rw-rw-   1 root   root          0 2018-01-11 13:35 Local\\ State',
2569      # Older Android versions do not print st_nlink
2570      'lrwxrwxrwx root     root              1970-01-01 00:00 lnk -> /a/path',
2571      'srwxrwx--- system   system            2016-05-31 17:25 a_socket1',
2572      'drwxrwxrwt system   misc              1970-11-23 02:25 tmp',
2573      'drwxr-s--- system   shell             1970-11-23 02:24 my_cmd',
2574      'cr--r----- root     system    10, 183 1971-01-01 07:04 random',
2575      'brw------- root     root       7,   0 1971-01-01 07:04 block_dev',
2576      '-rwS------ root     shell      157404 2015-04-13 15:44 silly',
2577  ]
2578
2579  FILENAMES = [
2580      'some_dir', 'some_file', 'My Music File', 'Local State', 'lnk',
2581      'a_socket1', 'tmp', 'my_cmd', 'random', 'block_dev', 'silly'
2582  ]
2583
2584  def getStatEntries(self, path_given='/', path_listed='/'):
2585    with self.assertCall(
2586        self.call.device.RunShellCommand(['ls', '-a', '-l', path_listed],
2587                                         check_return=True,
2588                                         as_root=False,
2589                                         env={'TZ': 'utc'}),
2590        self.EXAMPLE_LS_OUTPUT):
2591      entries = self.device.StatDirectory(path_given)
2592    return {f['filename']: f for f in entries}
2593
2594  def getListEntries(self):
2595    with self.assertCall(
2596        self.call.device.RunShellCommand(['ls', '-a', '-l', '/'],
2597                                         check_return=True,
2598                                         as_root=False,
2599                                         env={'TZ': 'utc'}),
2600        self.EXAMPLE_LS_OUTPUT):
2601      return self.device.ListDirectory('/')
2602
2603  def testStatDirectory_forceTrailingSlash(self):
2604    self.getStatEntries(path_given='/foo/bar/', path_listed='/foo/bar/')
2605    self.getStatEntries(path_given='/foo/bar', path_listed='/foo/bar/')
2606
2607  def testStatDirectory_fileList(self):
2608    self.safeAssertItemsEqual(self.getStatEntries().keys(), self.FILENAMES)
2609    self.safeAssertItemsEqual(self.getListEntries(), self.FILENAMES)
2610
2611  def testStatDirectory_fileModes(self):
2612    expected_modes = (
2613        ('some_dir', stat.S_ISDIR),
2614        ('some_file', stat.S_ISREG),
2615        ('lnk', stat.S_ISLNK),
2616        ('a_socket1', stat.S_ISSOCK),
2617        ('block_dev', stat.S_ISBLK),
2618        ('random', stat.S_ISCHR),
2619    )
2620    entries = self.getStatEntries()
2621    for filename, check in expected_modes:
2622      self.assertTrue(check(entries[filename]['st_mode']))
2623
2624  def testStatDirectory_filePermissions(self):
2625    should_have = (
2626        ('some_file', stat.S_IWUSR),  # Owner can write.
2627        ('tmp', stat.S_IXOTH),  # Others can execute.
2628        ('tmp', stat.S_ISVTX),  # Has sticky bit.
2629        ('my_cmd', stat.S_ISGID),  # Has set-group-ID bit.
2630        ('silly', stat.S_ISUID),  # Has set UID bit.
2631    )
2632    should_not_have = (
2633        ('some_file', stat.S_IWOTH),  # Others can't write.
2634        ('block_dev', stat.S_IRGRP),  # Group can't read.
2635        ('silly', stat.S_IXUSR),  # Owner can't execute.
2636    )
2637    entries = self.getStatEntries()
2638    for filename, bit in should_have:
2639      self.assertTrue(entries[filename]['st_mode'] & bit)
2640    for filename, bit in should_not_have:
2641      self.assertFalse(entries[filename]['st_mode'] & bit)
2642
2643  def testStatDirectory_numHardLinks(self):
2644    entries = self.getStatEntries()
2645    self.assertEqual(entries['some_dir']['st_nlink'], 6)
2646    self.assertEqual(entries['some_file']['st_nlink'], 1)
2647    self.assertFalse('st_nlink' in entries['tmp'])
2648
2649  def testStatDirectory_fileOwners(self):
2650    entries = self.getStatEntries()
2651    self.assertEqual(entries['some_dir']['st_owner'], 'root')
2652    self.assertEqual(entries['my_cmd']['st_owner'], 'system')
2653    self.assertEqual(entries['my_cmd']['st_group'], 'shell')
2654    self.assertEqual(entries['tmp']['st_group'], 'misc')
2655
2656  def testStatDirectory_fileSize(self):
2657    entries = self.getStatEntries()
2658    self.assertEqual(entries['some_file']['st_size'], 723)
2659    self.assertEqual(entries['My Music File']['st_size'], 327)
2660    # Sizes are sometimes not reported for non-regular files, don't try to
2661    # guess the size in those cases.
2662    self.assertFalse('st_size' in entries['some_dir'])
2663
2664  def testStatDirectory_fileDateTime(self):
2665    entries = self.getStatEntries()
2666    self.assertEqual(entries['some_dir']['st_mtime'], 0)  # Epoch!
2667    self.assertEqual(entries['My Music File']['st_mtime'], 1234567800)
2668
2669  def testStatDirectory_deviceType(self):
2670    entries = self.getStatEntries()
2671    self.assertEqual(entries['random']['st_rdev_pair'], (10, 183))
2672    self.assertEqual(entries['block_dev']['st_rdev_pair'], (7, 0))
2673
2674  def testStatDirectory_symbolicLinks(self):
2675    entries = self.getStatEntries()
2676    self.assertEqual(entries['lnk']['symbolic_link_to'], '/a/path')
2677    for d in entries.values():
2678      self.assertEqual('symbolic_link_to' in d, stat.S_ISLNK(d['st_mode']))
2679
2680
2681class DeviceUtilsStatPathTest(DeviceUtilsTest):
2682
2683  EXAMPLE_DIRECTORY = [{
2684      'filename': 'foo.txt',
2685      'st_size': 123,
2686      'st_time': 456
2687  }, {
2688      'filename': 'some_dir',
2689      'st_time': 0
2690  }]
2691  INDEX = {e['filename']: e for e in EXAMPLE_DIRECTORY}
2692
2693  def testStatPath_file(self):
2694    with self.assertCall(
2695        self.call.device.StatDirectory('/data/local/tmp', as_root=False),
2696        self.EXAMPLE_DIRECTORY):
2697      self.assertEquals(self.INDEX['foo.txt'],
2698                        self.device.StatPath('/data/local/tmp/foo.txt'))
2699
2700  def testStatPath_directory(self):
2701    with self.assertCall(
2702        self.call.device.StatDirectory('/data/local/tmp', as_root=False),
2703        self.EXAMPLE_DIRECTORY):
2704      self.assertEquals(self.INDEX['some_dir'],
2705                        self.device.StatPath('/data/local/tmp/some_dir'))
2706
2707  def testStatPath_directoryWithTrailingSlash(self):
2708    with self.assertCall(
2709        self.call.device.StatDirectory('/data/local/tmp', as_root=False),
2710        self.EXAMPLE_DIRECTORY):
2711      self.assertEquals(self.INDEX['some_dir'],
2712                        self.device.StatPath('/data/local/tmp/some_dir/'))
2713
2714  def testStatPath_doesNotExist(self):
2715    with self.assertCall(
2716        self.call.device.StatDirectory('/data/local/tmp', as_root=False),
2717        self.EXAMPLE_DIRECTORY):
2718      with self.assertRaises(device_errors.CommandFailedError):
2719        self.device.StatPath('/data/local/tmp/does.not.exist.txt')
2720
2721
2722class DeviceUtilsFileSizeTest(DeviceUtilsTest):
2723
2724  EXAMPLE_DIRECTORY = [{
2725      'filename': 'foo.txt',
2726      'st_size': 123,
2727      'st_mtime': 456
2728  }, {
2729      'filename': 'some_dir',
2730      'st_mtime': 0
2731  }]
2732
2733  def testFileSize_file(self):
2734    with self.assertCall(
2735        self.call.device.StatDirectory('/data/local/tmp', as_root=False),
2736        self.EXAMPLE_DIRECTORY):
2737      self.assertEquals(123, self.device.FileSize('/data/local/tmp/foo.txt'))
2738
2739  def testFileSize_doesNotExist(self):
2740    with self.assertCall(
2741        self.call.device.StatDirectory('/data/local/tmp', as_root=False),
2742        self.EXAMPLE_DIRECTORY):
2743      with self.assertRaises(device_errors.CommandFailedError):
2744        self.device.FileSize('/data/local/tmp/does.not.exist.txt')
2745
2746  def testFileSize_directoryWithNoSize(self):
2747    with self.assertCall(
2748        self.call.device.StatDirectory('/data/local/tmp', as_root=False),
2749        self.EXAMPLE_DIRECTORY):
2750      with self.assertRaises(device_errors.CommandFailedError):
2751        self.device.FileSize('/data/local/tmp/some_dir')
2752
2753
2754class DeviceUtilsSetJavaAssertsTest(DeviceUtilsTest):
2755  def testSetJavaAsserts_enable(self):
2756    with self.assertCalls(
2757        (self.call.device.ReadFile(self.device.LOCAL_PROPERTIES_PATH),
2758         'some.example.prop=with an example value\n'
2759         'some.other.prop=value_ok\n'),
2760        self.call.device.WriteFile(
2761            self.device.LOCAL_PROPERTIES_PATH,
2762            'some.example.prop=with an example value\n'
2763            'some.other.prop=value_ok\n'
2764            'dalvik.vm.enableassertions=all\n'),
2765        (self.call.device.GetProp('dalvik.vm.enableassertions'), ''),
2766        self.call.device.SetProp('dalvik.vm.enableassertions', 'all')):
2767      self.assertTrue(self.device.SetJavaAsserts(True))
2768
2769  def testSetJavaAsserts_disable(self):
2770    with self.assertCalls(
2771        (self.call.device.ReadFile(self.device.LOCAL_PROPERTIES_PATH),
2772         'some.example.prop=with an example value\n'
2773         'dalvik.vm.enableassertions=all\n'
2774         'some.other.prop=value_ok\n'),
2775        self.call.device.WriteFile(
2776            self.device.LOCAL_PROPERTIES_PATH,
2777            'some.example.prop=with an example value\n'
2778            'some.other.prop=value_ok\n'),
2779        (self.call.device.GetProp('dalvik.vm.enableassertions'), 'all'),
2780        self.call.device.SetProp('dalvik.vm.enableassertions', '')):
2781      self.assertTrue(self.device.SetJavaAsserts(False))
2782
2783  def testSetJavaAsserts_alreadyEnabled(self):
2784    with self.assertCalls(
2785        (self.call.device.ReadFile(self.device.LOCAL_PROPERTIES_PATH),
2786         'some.example.prop=with an example value\n'
2787         'dalvik.vm.enableassertions=all\n'
2788         'some.other.prop=value_ok\n'),
2789        (self.call.device.GetProp('dalvik.vm.enableassertions'), 'all')):
2790      self.assertFalse(self.device.SetJavaAsserts(True))
2791
2792  def testSetJavaAsserts_malformedLocalProp(self):
2793    with self.assertCalls(
2794        (self.call.device.ReadFile(self.device.LOCAL_PROPERTIES_PATH),
2795         'some.example.prop=with an example value\n'
2796         'malformed_property\n'
2797         'dalvik.vm.enableassertions=all\n'
2798         'some.other.prop=value_ok\n'),
2799        (self.call.device.GetProp('dalvik.vm.enableassertions'), 'all')):
2800      self.assertFalse(self.device.SetJavaAsserts(True))
2801
2802
2803class DeviceUtilsEnsureCacheInitializedTest(DeviceUtilsTest):
2804  def testEnsureCacheInitialized_noCache_success(self):
2805    self.assertIsNone(self.device._cache['token'])
2806    with self.assertCall(
2807        self.call.device.RunShellCommand(
2808            AnyStringWith('getprop'),
2809            shell=True,
2810            check_return=True,
2811            large_output=True), ['/sdcard', 'TOKEN']):
2812      self.device._EnsureCacheInitialized()
2813    self.assertIsNotNone(self.device._cache['token'])
2814
2815  def testEnsureCacheInitialized_noCache_failure(self):
2816    self.assertIsNone(self.device._cache['token'])
2817    with self.assertCall(
2818        self.call.device.RunShellCommand(
2819            AnyStringWith('getprop'),
2820            shell=True,
2821            check_return=True,
2822            large_output=True), self.TimeoutError()):
2823      with self.assertRaises(device_errors.CommandTimeoutError):
2824        self.device._EnsureCacheInitialized()
2825    self.assertIsNone(self.device._cache['token'])
2826
2827  def testEnsureCacheInitialized_cache(self):
2828    self.device._cache['token'] = 'TOKEN'
2829    with self.assertCalls():
2830      self.device._EnsureCacheInitialized()
2831    self.assertIsNotNone(self.device._cache['token'])
2832
2833
2834class DeviceUtilsGetPropTest(DeviceUtilsTest):
2835  def testGetProp_exists(self):
2836    with self.assertCall(
2837        self.call.device.RunShellCommand(['getprop', 'test.property'],
2838                                         check_return=True,
2839                                         single_line=True,
2840                                         timeout=self.device._default_timeout,
2841                                         retries=self.device._default_retries),
2842        'property_value'):
2843      self.assertEqual('property_value', self.device.GetProp('test.property'))
2844
2845  def testGetProp_doesNotExist(self):
2846    with self.assertCall(
2847        self.call.device.RunShellCommand(['getprop', 'property.does.not.exist'],
2848                                         check_return=True,
2849                                         single_line=True,
2850                                         timeout=self.device._default_timeout,
2851                                         retries=self.device._default_retries),
2852        ''):
2853      self.assertEqual('', self.device.GetProp('property.does.not.exist'))
2854
2855  def testGetProp_cachedRoProp(self):
2856    with self.assertCalls(
2857        self.EnsureCacheInitialized(props=['[ro.build.type]: [userdebug]'])):
2858      self.assertEqual('userdebug',
2859                       self.device.GetProp('ro.build.type', cache=True))
2860      self.assertEqual('userdebug',
2861                       self.device.GetProp('ro.build.type', cache=True))
2862
2863
2864class DeviceUtilsSetPropTest(DeviceUtilsTest):
2865  def testSetProp(self):
2866    with self.assertCall(
2867        self.call.device.RunShellCommand(
2868            ['setprop', 'test.property', 'test value'], check_return=True)):
2869      self.device.SetProp('test.property', 'test value')
2870
2871  def testSetProp_check_succeeds(self):
2872    with self.assertCalls(
2873        (self.call.device.RunShellCommand(
2874            ['setprop', 'test.property', 'new_value'], check_return=True)),
2875        (self.call.device.GetProp('test.property', cache=False), 'new_value')):
2876      self.device.SetProp('test.property', 'new_value', check=True)
2877
2878  def testSetProp_check_fails(self):
2879    with self.assertCalls(
2880        (self.call.device.RunShellCommand(
2881            ['setprop', 'test.property', 'new_value'], check_return=True)),
2882        (self.call.device.GetProp('test.property', cache=False), 'old_value')):
2883      with self.assertRaises(device_errors.CommandFailedError):
2884        self.device.SetProp('test.property', 'new_value', check=True)
2885
2886
2887class DeviceUtilsListProcessesTest(DeviceUtilsTest):
2888  def setUp(self):
2889    super(DeviceUtilsListProcessesTest, self).setUp()
2890    self.sample_output = [
2891        'USER  PID     PPID  VSIZE RSS   WCHAN          PC  NAME',
2892        'user  1001    100   1024  1024  ffffffff 00000000 one.match',
2893        'user  1002    100   1024  1024  ffffffff 00000000 two.match',
2894        'user  1003    101   1024  1024  ffffffff 00000000 three.match',
2895        'user  1234    101   1024  1024  ffffffff 00000000 my$process',
2896        'user  1236    100   1024  1024  ffffffff 00000000 foo',
2897        'user  1578    1236  1024  1024  ffffffff 00000000 foo',
2898    ]
2899
2900  def _grepOutput(self, substring):
2901    return [line for line in self.sample_output if substring in line]
2902
2903  def testListProcesses_sdkGreaterThanNougatMR1(self):
2904    with self.patch_call(
2905        self.call.device.build_version_sdk,
2906        return_value=(version_codes.NOUGAT_MR1 + 1)):
2907      with self.patch_call(self.call.device.build_id, return_value='ZZZ99Z'):
2908        with self.assertCall(
2909            self.call.device._RunPipedShellCommand(
2910                'ps -e | grep -F example.process'), []):
2911          self.device.ListProcesses('example.process')
2912
2913  def testListProcesses_noMatches(self):
2914    with self.patch_call(
2915        self.call.device.build_version_sdk,
2916        return_value=version_codes.LOLLIPOP):
2917      with self.assertCall(
2918          self.call.device._RunPipedShellCommand('ps | grep -F does.not.match'),
2919          self._grepOutput('does.not.match')):
2920        self.assertEqual([], self.device.ListProcesses('does.not.match'))
2921
2922  def testListProcesses_oneMatch(self):
2923    with self.patch_call(
2924        self.call.device.build_version_sdk,
2925        return_value=version_codes.LOLLIPOP):
2926      with self.assertCall(
2927          self.call.device._RunPipedShellCommand('ps | grep -F one.match'),
2928          self._grepOutput('one.match')):
2929        self.assertEqual(
2930            Processes(('one.match', 1001, 100)),
2931            self.device.ListProcesses('one.match'))
2932
2933  def testListProcesses_multipleMatches(self):
2934    with self.patch_call(
2935        self.call.device.build_version_sdk,
2936        return_value=version_codes.LOLLIPOP):
2937      with self.assertCall(
2938          self.call.device._RunPipedShellCommand('ps | grep -F match'),
2939          self._grepOutput('match')):
2940        self.assertEqual(
2941            Processes(('one.match', 1001, 100), ('two.match', 1002, 100),
2942                      ('three.match', 1003, 101)),
2943            self.device.ListProcesses('match'))
2944
2945  def testListProcesses_quotable(self):
2946    with self.patch_call(
2947        self.call.device.build_version_sdk,
2948        return_value=version_codes.LOLLIPOP):
2949      with self.assertCall(
2950          self.call.device._RunPipedShellCommand("ps | grep -F 'my$process'"),
2951          self._grepOutput('my$process')):
2952        self.assertEqual(
2953            Processes(('my$process', 1234, 101)),
2954            self.device.ListProcesses('my$process'))
2955
2956  # Tests for the GetPids wrapper interface.
2957  def testGetPids_multipleInstances(self):
2958    with self.patch_call(
2959        self.call.device.build_version_sdk,
2960        return_value=version_codes.LOLLIPOP):
2961      with self.assertCall(
2962          self.call.device._RunPipedShellCommand('ps | grep -F foo'),
2963          self._grepOutput('foo')):
2964        self.assertEqual({'foo': ['1236', '1578']}, self.device.GetPids('foo'))
2965
2966  def testGetPids_allProcesses(self):
2967    with self.patch_call(
2968        self.call.device.build_version_sdk,
2969        return_value=version_codes.LOLLIPOP):
2970      with self.assertCall(
2971          self.call.device.RunShellCommand(['ps'],
2972                                           check_return=True,
2973                                           large_output=True),
2974          self.sample_output):
2975        self.assertEqual({
2976            'one.match': ['1001'],
2977            'two.match': ['1002'],
2978            'three.match': ['1003'],
2979            'my$process': ['1234'],
2980            'foo': ['1236', '1578']
2981        }, self.device.GetPids())
2982
2983  # Tests for the GetApplicationPids wrapper interface.
2984  def testGetApplicationPids_notFound(self):
2985    with self.patch_call(
2986        self.call.device.build_version_sdk,
2987        return_value=version_codes.LOLLIPOP):
2988      with self.assertCall(
2989          self.call.device._RunPipedShellCommand('ps | grep -F match'),
2990          self._grepOutput('match')):
2991        # No PIDs found, process name should be exact match.
2992        self.assertEqual([], self.device.GetApplicationPids('match'))
2993
2994  def testGetApplicationPids_foundOne(self):
2995    with self.patch_call(
2996        self.call.device.build_version_sdk,
2997        return_value=version_codes.LOLLIPOP):
2998      with self.assertCall(
2999          self.call.device._RunPipedShellCommand('ps | grep -F one.match'),
3000          self._grepOutput('one.match')):
3001        self.assertEqual([1001], self.device.GetApplicationPids('one.match'))
3002
3003  def testGetApplicationPids_foundMany(self):
3004    with self.patch_call(
3005        self.call.device.build_version_sdk,
3006        return_value=version_codes.LOLLIPOP):
3007      with self.assertCall(
3008          self.call.device._RunPipedShellCommand('ps | grep -F foo'),
3009          self._grepOutput('foo')):
3010        self.assertEqual([1236, 1578], self.device.GetApplicationPids('foo'))
3011
3012  def testGetApplicationPids_atMostOneNotFound(self):
3013    with self.patch_call(
3014        self.call.device.build_version_sdk,
3015        return_value=version_codes.LOLLIPOP):
3016      with self.assertCall(
3017          self.call.device._RunPipedShellCommand('ps | grep -F match'),
3018          self._grepOutput('match')):
3019        # No PIDs found, process name should be exact match.
3020        self.assertEqual(
3021            None, self.device.GetApplicationPids('match', at_most_one=True))
3022
3023  def testGetApplicationPids_atMostOneFound(self):
3024    with self.patch_call(
3025        self.call.device.build_version_sdk,
3026        return_value=version_codes.LOLLIPOP):
3027      with self.assertCall(
3028          self.call.device._RunPipedShellCommand('ps | grep -F one.match'),
3029          self._grepOutput('one.match')):
3030        self.assertEqual(
3031            1001, self.device.GetApplicationPids('one.match', at_most_one=True))
3032
3033  def testGetApplicationPids_atMostOneFoundTooMany(self):
3034    with self.patch_call(
3035        self.call.device.build_version_sdk,
3036        return_value=version_codes.LOLLIPOP):
3037      with self.assertRaises(device_errors.CommandFailedError):
3038        with self.assertCall(
3039            self.call.device._RunPipedShellCommand('ps | grep -F foo'),
3040            self._grepOutput('foo')):
3041          self.device.GetApplicationPids('foo', at_most_one=True)
3042
3043
3044class DeviceUtilsGetSetEnforce(DeviceUtilsTest):
3045  def testGetEnforce_Enforcing(self):
3046    with self.assertCall(self.call.adb.Shell('getenforce'), 'Enforcing'):
3047      self.assertEqual(True, self.device.GetEnforce())
3048
3049  def testGetEnforce_Permissive(self):
3050    with self.assertCall(self.call.adb.Shell('getenforce'), 'Permissive'):
3051      self.assertEqual(False, self.device.GetEnforce())
3052
3053  def testGetEnforce_Disabled(self):
3054    with self.assertCall(self.call.adb.Shell('getenforce'), 'Disabled'):
3055      self.assertEqual(None, self.device.GetEnforce())
3056
3057  def testSetEnforce_Enforcing(self):
3058    with self.assertCalls((self.call.device.NeedsSU(), False),
3059                          (self.call.adb.Shell('setenforce 1'), '')):
3060      self.device.SetEnforce(enabled=True)
3061
3062  def testSetEnforce_Permissive(self):
3063    with self.assertCalls((self.call.device.NeedsSU(), False),
3064                          (self.call.adb.Shell('setenforce 0'), '')):
3065      self.device.SetEnforce(enabled=False)
3066
3067  def testSetEnforce_EnforcingWithInt(self):
3068    with self.assertCalls((self.call.device.NeedsSU(), False),
3069                          (self.call.adb.Shell('setenforce 1'), '')):
3070      self.device.SetEnforce(enabled=1)
3071
3072  def testSetEnforce_PermissiveWithInt(self):
3073    with self.assertCalls((self.call.device.NeedsSU(), False),
3074                          (self.call.adb.Shell('setenforce 0'), '')):
3075      self.device.SetEnforce(enabled=0)
3076
3077  def testSetEnforce_EnforcingWithStr(self):
3078    with self.assertCalls((self.call.device.NeedsSU(), False),
3079                          (self.call.adb.Shell('setenforce 1'), '')):
3080      self.device.SetEnforce(enabled='1')
3081
3082  def testSetEnforce_PermissiveWithStr(self):
3083    with self.assertCalls((self.call.device.NeedsSU(), False),
3084                          (self.call.adb.Shell('setenforce 0'), '')):
3085      self.device.SetEnforce(enabled='0')  # Not recommended but it works!
3086
3087
3088class DeviceUtilsGetWebViewUpdateServiceDumpTest(DeviceUtilsTest):
3089  def testGetWebViewUpdateServiceDump_success(self):
3090    # Some of the lines of adb shell dumpsys webviewupdate:
3091    dumpsys_lines = [
3092        'Fallback logic enabled: true',
3093        ('Current WebView package (name, version): '
3094         '(com.android.chrome, 61.0.3163.98)'),
3095        'Minimum WebView version code: 12345',
3096        'WebView packages:',
3097        ('Valid package com.android.chrome (versionName: '
3098         '61.0.3163.98, versionCode: 1, targetSdkVersion: 26) is  '
3099         'installed/enabled for all users'),
3100        ('Valid package com.google.android.webview (versionName: '
3101         '58.0.3029.125, versionCode: 1, targetSdkVersion: 26) is NOT '
3102         'installed/enabled for all users'),
3103        ('Invalid package com.google.android.apps.chrome (versionName: '
3104         '56.0.2924.122, versionCode: 2, targetSdkVersion: 25), reason: SDK '
3105         'version too low'),
3106        ('com.chrome.canary is NOT installed.'),
3107    ]
3108    with self.patch_call(
3109        self.call.device.build_version_sdk, return_value=version_codes.OREO):
3110      with self.assertCall(
3111          self.call.adb.Shell('dumpsys webviewupdate'),
3112          '\n'.join(dumpsys_lines)):
3113        update = self.device.GetWebViewUpdateServiceDump()
3114        self.assertTrue(update['FallbackLogicEnabled'])
3115        self.assertEqual('com.android.chrome', update['CurrentWebViewPackage'])
3116        self.assertEqual(12345, update['MinimumWebViewVersionCode'])
3117        # Order isn't really important, and we shouldn't have duplicates, so we
3118        # convert to sets.
3119        expected = {
3120            'com.android.chrome', 'com.google.android.webview',
3121            'com.google.android.apps.chrome', 'com.chrome.canary'
3122        }
3123        self.assertSetEqual(expected, set(update['WebViewPackages'].keys()))
3124        self.assertEquals('is  installed/enabled for all users',
3125                          update['WebViewPackages']['com.android.chrome'])
3126        self.assertEquals(
3127            'is NOT installed/enabled for all users',
3128            update['WebViewPackages']['com.google.android.webview'])
3129        self.assertEquals(
3130            'reason: SDK version too low',
3131            update['WebViewPackages']['com.google.android.apps.chrome'])
3132        self.assertEquals('is NOT installed.',
3133                          update['WebViewPackages']['com.chrome.canary'])
3134
3135  def testGetWebViewUpdateServiceDump_missingkey(self):
3136    with self.patch_call(
3137        self.call.device.build_version_sdk, return_value=version_codes.OREO):
3138      with self.assertCall(
3139          self.call.adb.Shell('dumpsys webviewupdate'),
3140          'Fallback logic enabled: true'):
3141        update = self.device.GetWebViewUpdateServiceDump()
3142        self.assertEqual(True, update['FallbackLogicEnabled'])
3143
3144  def testGetWebViewUpdateServiceDump_noop(self):
3145    with self.patch_call(
3146        self.call.device.build_version_sdk,
3147        return_value=version_codes.NOUGAT_MR1):
3148      with self.assertCalls():
3149        self.device.GetWebViewUpdateServiceDump()
3150
3151  def testGetWebViewUpdateServiceDump_noPackage(self):
3152    with self.patch_call(
3153        self.call.device.build_version_sdk, return_value=version_codes.OREO):
3154      with self.assertCall(
3155          self.call.adb.Shell('dumpsys webviewupdate'),
3156          'Fallback logic enabled: true\n'
3157          'Current WebView package is null'):
3158        update = self.device.GetWebViewUpdateServiceDump()
3159        self.assertEqual(True, update['FallbackLogicEnabled'])
3160        self.assertEqual(None, update['CurrentWebViewPackage'])
3161
3162
3163class DeviceUtilsSetWebViewImplementationTest(DeviceUtilsTest):
3164  def testSetWebViewImplementation_success(self):
3165    with self.patch_call(
3166        self.call.device.IsApplicationInstalled, return_value=True):
3167      with self.assertCall(
3168          self.call.adb.Shell(
3169              'cmd webviewupdate set-webview-implementation foo.org'),
3170          'Success'):
3171        self.device.SetWebViewImplementation('foo.org')
3172
3173  def testSetWebViewImplementation_uninstalled(self):
3174    with self.patch_call(
3175        self.call.device.IsApplicationInstalled, return_value=False):
3176      with self.assertRaises(device_errors.CommandFailedError) as cfe:
3177        self.device.SetWebViewImplementation('foo.org')
3178      self.assertIn('is not installed', cfe.exception.message)
3179
3180  def _testSetWebViewImplementationHelper(self, mock_dump_sys,
3181                                          exception_message_substr):
3182    with self.patch_call(
3183        self.call.device.IsApplicationInstalled, return_value=True):
3184      with self.assertCall(
3185          self.call.adb.Shell(
3186              'cmd webviewupdate set-webview-implementation foo.org'), 'Oops!'):
3187        with self.patch_call(
3188            self.call.device.GetWebViewUpdateServiceDump,
3189            return_value=mock_dump_sys):
3190          with self.assertRaises(device_errors.CommandFailedError) as cfe:
3191            self.device.SetWebViewImplementation('foo.org')
3192          self.assertIn(exception_message_substr, cfe.exception.message)
3193
3194  def testSetWebViewImplementation_notInProviderList(self):
3195    mock_dump_sys = {
3196        'WebViewPackages': {
3197            'some.package': 'any reason',
3198            'other.package': 'any reason',
3199        }
3200    }
3201    self._testSetWebViewImplementationHelper(mock_dump_sys, 'provider list')
3202
3203  def testSetWebViewImplementation_notEnabled(self):
3204    mock_dump_sys = {
3205        'WebViewPackages': {
3206            'foo.org': 'is NOT installed/enabled for all users',
3207        }
3208    }
3209    self._testSetWebViewImplementationHelper(mock_dump_sys, 'is disabled')
3210
3211  def testSetWebViewImplementation_missingManifestTag(self):
3212    mock_dump_sys = {
3213        'WebViewPackages': {
3214            'foo.org': 'No WebView-library manifest flag',
3215        }
3216    }
3217    self._testSetWebViewImplementationHelper(mock_dump_sys,
3218                                             'WebView native library')
3219
3220  def testSetWebViewImplementation_lowTargetSdkVersion_finalizedSdk(self):
3221    mock_dump_sys = {'WebViewPackages': {'foo.org': 'SDK version too low', }}
3222    with self.assertCalls(
3223        (self.call.device.GetApplicationTargetSdk('foo.org'), '29'),
3224        (self.call.device.GetProp('ro.build.version.preview_sdk'), '0')):
3225      with self.patch_call(self.call.device.build_version_sdk, return_value=30):
3226        self._testSetWebViewImplementationHelper(
3227            mock_dump_sys,
3228            "has targetSdkVersion '29', but valid WebView providers must "
3229            "target >= 30 on this device")
3230
3231  def testSetWebViewImplementation_lowTargetSdkVersion_prefinalizedSdk(self):
3232    mock_dump_sys = {'WebViewPackages': {'foo.org': 'SDK version too low', }}
3233    with self.assertCalls(
3234        (self.call.device.GetApplicationTargetSdk('foo.org'), '29'),
3235        (self.call.device.GetProp('ro.build.version.preview_sdk'), '1'),
3236        (self.call.device.GetProp('ro.build.version.codename'), 'R')):
3237      with self.patch_call(self.call.device.build_version_sdk, return_value=29):
3238        self._testSetWebViewImplementationHelper(
3239            mock_dump_sys,
3240            "targets a finalized SDK ('29'), but valid WebView providers must "
3241            "target a pre-finalized SDK ('R') on this device")
3242
3243  def testSetWebViewImplementation_lowVersionCode(self):
3244    mock_dump_sys = {
3245        'MinimumWebViewVersionCode': 12345,
3246        'WebViewPackages': {
3247            'foo.org': 'Version code too low',
3248        }
3249    }
3250    self._testSetWebViewImplementationHelper(mock_dump_sys,
3251                                             'higher versionCode')
3252
3253  def testSetWebViewImplementation_invalidSignature(self):
3254    mock_dump_sys = {'WebViewPackages': {'foo.org': 'Incorrect signature'}}
3255    self._testSetWebViewImplementationHelper(mock_dump_sys,
3256                                             'signed with release keys')
3257
3258
3259class DeviceUtilsSetWebViewFallbackLogicTest(DeviceUtilsTest):
3260  def testSetWebViewFallbackLogic_False_success(self):
3261    with self.patch_call(
3262        self.call.device.build_version_sdk, return_value=version_codes.NOUGAT):
3263      with self.assertCall(
3264          self.call.adb.Shell('cmd webviewupdate enable-redundant-packages'),
3265          'Success'):
3266        self.device.SetWebViewFallbackLogic(False)
3267
3268  def testSetWebViewFallbackLogic_True_success(self):
3269    with self.patch_call(
3270        self.call.device.build_version_sdk, return_value=version_codes.NOUGAT):
3271      with self.assertCall(
3272          self.call.adb.Shell('cmd webviewupdate disable-redundant-packages'),
3273          'Success'):
3274        self.device.SetWebViewFallbackLogic(True)
3275
3276  def testSetWebViewFallbackLogic_failure(self):
3277    with self.patch_call(
3278        self.call.device.build_version_sdk, return_value=version_codes.NOUGAT):
3279      with self.assertCall(
3280          self.call.adb.Shell('cmd webviewupdate enable-redundant-packages'),
3281          'Oops!'):
3282        with self.assertRaises(device_errors.CommandFailedError):
3283          self.device.SetWebViewFallbackLogic(False)
3284
3285  def testSetWebViewFallbackLogic_beforeNougat(self):
3286    with self.patch_call(
3287        self.call.device.build_version_sdk,
3288        return_value=version_codes.MARSHMALLOW):
3289      with self.assertCalls():
3290        self.device.SetWebViewFallbackLogic(False)
3291
3292  def testSetWebViewFallbackLogic_afterPie(self):
3293    with self.patch_call(
3294        self.call.device.build_version_sdk, return_value=version_codes.Q):
3295      with self.assertCalls():
3296        self.device.SetWebViewFallbackLogic(False)
3297
3298
3299class DeviceUtilsTakeScreenshotTest(DeviceUtilsTest):
3300  def testTakeScreenshot_fileNameProvided(self):
3301    with self.assertCalls(
3302        (mock.call.devil.android.device_temp_file.DeviceTempFile(
3303            self.adb, suffix='.png'), MockTempFile('/tmp/path/temp-123.png')),
3304        (self.call.adb.Shell('/system/bin/screencap -p /tmp/path/temp-123.png'),
3305         ''),
3306        self.call.device.PullFile('/tmp/path/temp-123.png',
3307                                  '/test/host/screenshot.png')):
3308      self.device.TakeScreenshot('/test/host/screenshot.png')
3309
3310
3311class DeviceUtilsDismissCrashDialogIfNeededTest(DeviceUtilsTest):
3312  def testDismissCrashDialogIfNeeded_crashedPageckageNotFound(self):
3313    sample_dumpsys_output = '''
3314WINDOW MANAGER WINDOWS (dumpsys window windows)
3315  Window #11 Window{f8b647a u0 SearchPanel}:
3316    mDisplayId=0 mSession=Session{8 94:122} mClient=android.os.BinderProxy@1ba5
3317    mOwnerUid=100 mShowToOwnerOnly=false package=com.android.systemui appop=NONE
3318    mAttrs=WM.LayoutParams{(0,0)(fillxfill) gr=#53 sim=#31 ty=2024 fl=100
3319    Requested w=1080 h=1920 mLayoutSeq=426
3320    mBaseLayer=211000 mSubLayer=0 mAnimLayer=211000+0=211000 mLastLayer=211000
3321'''
3322    with self.assertCalls(
3323        (self.call.device.RunShellCommand(['dumpsys', 'window', 'windows'],
3324                                          check_return=True,
3325                                          large_output=True),
3326         sample_dumpsys_output.split('\n'))):
3327      package_name = self.device.DismissCrashDialogIfNeeded()
3328      self.assertIsNone(package_name)
3329
3330  def testDismissCrashDialogIfNeeded_crashedPageckageFound(self):
3331    sample_dumpsys_output = '''
3332WINDOW MANAGER WINDOWS (dumpsys window windows)
3333  Window #11 Window{f8b647a u0 SearchPanel}:
3334    mDisplayId=0 mSession=Session{8 94:122} mClient=android.os.BinderProxy@1ba5
3335    mOwnerUid=102 mShowToOwnerOnly=false package=com.android.systemui appop=NONE
3336    mAttrs=WM.LayoutParams{(0,0)(fillxfill) gr=#53 sim=#31 ty=2024 fl=100
3337    Requested w=1080 h=1920 mLayoutSeq=426
3338    mBaseLayer=211000 mSubLayer=0 mAnimLayer=211000+0=211000 mLastLayer=211000
3339  mHasPermanentDpad=false
3340  mCurrentFocus=Window{3a27740f u0 Application Error: com.android.chrome}
3341  mFocusedApp=AppWindowToken{470af6f token=Token{272ec24e ActivityRecord{t894}}}
3342'''
3343    with self.assertCalls(
3344        (self.call.device.RunShellCommand(['dumpsys', 'window', 'windows'],
3345                                          check_return=True,
3346                                          large_output=True),
3347         sample_dumpsys_output.split('\n')), (self.call.device.RunShellCommand(
3348             ['input', 'keyevent', '22'], check_return=True)),
3349        (self.call.device.RunShellCommand(['input', 'keyevent', '22'],
3350                                          check_return=True)),
3351        (self.call.device.RunShellCommand(['input', 'keyevent', '66'],
3352                                          check_return=True)),
3353        (self.call.device.RunShellCommand(['dumpsys', 'window', 'windows'],
3354                                          check_return=True,
3355                                          large_output=True), [])):
3356      package_name = self.device.DismissCrashDialogIfNeeded()
3357      self.assertEqual(package_name, 'com.android.chrome')
3358
3359
3360class DeviceUtilsClientCache(DeviceUtilsTest):
3361  def testClientCache_twoCaches(self):
3362    self.device._cache['test'] = 0
3363    client_cache_one = self.device.GetClientCache('ClientOne')
3364    client_cache_one['test'] = 1
3365    client_cache_two = self.device.GetClientCache('ClientTwo')
3366    client_cache_two['test'] = 2
3367    self.assertEqual(self.device._cache['test'], 0)
3368    self.assertEqual(client_cache_one, {'test': 1})
3369    self.assertEqual(client_cache_two, {'test': 2})
3370    self.device.ClearCache()
3371    self.assertTrue('test' not in self.device._cache)
3372    self.assertEqual(client_cache_one, {})
3373    self.assertEqual(client_cache_two, {})
3374
3375  def testClientCache_multipleInstances(self):
3376    client_cache_one = self.device.GetClientCache('ClientOne')
3377    client_cache_one['test'] = 1
3378    client_cache_two = self.device.GetClientCache('ClientOne')
3379    self.assertEqual(client_cache_one, {'test': 1})
3380    self.assertEqual(client_cache_two, {'test': 1})
3381    self.device.ClearCache()
3382    self.assertEqual(client_cache_one, {})
3383    self.assertEqual(client_cache_two, {})
3384
3385
3386class DeviceUtilsHealthyDevicesTest(mock_calls.TestCase):
3387  def testHealthyDevices_emptyDenylist_defaultDeviceArg(self):
3388    test_serials = ['0123456789abcdef', 'fedcba9876543210']
3389    with self.assertCalls(
3390        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
3391         [_AdbWrapperMock(s) for s in test_serials]),
3392        (mock.call.devil.android.device_utils.DeviceUtils.GetABI(), abis.ARM),
3393        (mock.call.devil.android.device_utils.DeviceUtils.GetABI(), abis.ARM)):
3394      denylist = mock.NonCallableMock(**{'Read.return_value': []})
3395      devices = device_utils.DeviceUtils.HealthyDevices(denylist)
3396    for serial, device in zip(test_serials, devices):
3397      self.assertTrue(isinstance(device, device_utils.DeviceUtils))
3398      self.assertEquals(serial, device.adb.GetDeviceSerial())
3399
3400  def testHealthyDevices_denylist_defaultDeviceArg(self):
3401    test_serials = ['0123456789abcdef', 'fedcba9876543210']
3402    with self.assertCalls(
3403        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
3404         [_AdbWrapperMock(s) for s in test_serials]),
3405        (mock.call.devil.android.device_utils.DeviceUtils.GetABI(), abis.ARM)):
3406      denylist = mock.NonCallableMock(
3407          **{'Read.return_value': ['fedcba9876543210']})
3408      devices = device_utils.DeviceUtils.HealthyDevices(denylist)
3409    self.assertEquals(1, len(devices))
3410    self.assertTrue(isinstance(devices[0], device_utils.DeviceUtils))
3411    self.assertEquals('0123456789abcdef', devices[0].adb.GetDeviceSerial())
3412
3413  def testHealthyDevices_noneDeviceArg_multiple_attached(self):
3414    test_serials = ['0123456789abcdef', 'fedcba9876543210']
3415    with self.assertCalls(
3416        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
3417         [_AdbWrapperMock(s) for s in test_serials]),
3418        (mock.call.devil.android.device_utils.DeviceUtils.GetABI(), abis.ARM),
3419        (mock.call.devil.android.device_utils.DeviceUtils.GetABI(), abis.ARM),
3420        (mock.call.devil.android.device_errors.MultipleDevicesError(mock.ANY),
3421         _MockMultipleDevicesError())):
3422      with self.assertRaises(_MockMultipleDevicesError):
3423        device_utils.DeviceUtils.HealthyDevices(device_arg=None)
3424
3425  def testHealthyDevices_noneDeviceArg_one_attached(self):
3426    test_serials = ['0123456789abcdef']
3427    with self.assertCalls(
3428        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
3429         [_AdbWrapperMock(s) for s in test_serials]),
3430        (mock.call.devil.android.device_utils.DeviceUtils.GetABI(), abis.ARM)):
3431      devices = device_utils.DeviceUtils.HealthyDevices(device_arg=None)
3432    self.assertEquals(1, len(devices))
3433
3434  def testHealthyDevices_noneDeviceArg_no_attached(self):
3435    test_serials = []
3436    with self.assertCalls(
3437        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
3438         [_AdbWrapperMock(s) for s in test_serials])):
3439      with self.assertRaises(device_errors.NoDevicesError):
3440        device_utils.DeviceUtils.HealthyDevices(device_arg=None, retries=0)
3441
3442  def testHealthyDevices_noneDeviceArg_multiple_attached_ANDROID_SERIAL(self):
3443    try:
3444      os.environ['ANDROID_SERIAL'] = '0123456789abcdef'
3445      with self.assertCalls():  # Should skip adb devices when device is known.
3446        device_utils.DeviceUtils.HealthyDevices(device_arg=None)
3447    finally:
3448      del os.environ['ANDROID_SERIAL']
3449
3450  def testHealthyDevices_stringDeviceArg(self):
3451    with self.assertCalls():  # Should skip adb devices when device is known.
3452      devices = device_utils.DeviceUtils.HealthyDevices(
3453          device_arg='0123456789abcdef')
3454    self.assertEquals(1, len(devices))
3455
3456  def testHealthyDevices_EmptyListDeviceArg_multiple_attached(self):
3457    test_serials = ['0123456789abcdef', 'fedcba9876543210']
3458    with self.assertCalls(
3459        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
3460         [_AdbWrapperMock(s) for s in test_serials]),
3461        (mock.call.devil.android.device_utils.DeviceUtils.GetABI(), abis.ARM),
3462        (mock.call.devil.android.device_utils.DeviceUtils.GetABI(), abis.ARM)):
3463      devices = device_utils.DeviceUtils.HealthyDevices(device_arg=())
3464    self.assertEquals(2, len(devices))
3465
3466  def testHealthyDevices_EmptyListDeviceArg_ANDROID_SERIAL(self):
3467    try:
3468      os.environ['ANDROID_SERIAL'] = '0123456789abcdef'
3469      with self.assertCalls():  # Should skip adb devices when device is known.
3470        devices = device_utils.DeviceUtils.HealthyDevices(device_arg=())
3471    finally:
3472      del os.environ['ANDROID_SERIAL']
3473    self.assertEquals(1, len(devices))
3474
3475  def testHealthyDevices_EmptyListDeviceArg_no_attached(self):
3476    test_serials = []
3477    with self.assertCalls(
3478        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
3479         [_AdbWrapperMock(s) for s in test_serials])):
3480      with self.assertRaises(device_errors.NoDevicesError):
3481        device_utils.DeviceUtils.HealthyDevices(device_arg=[], retries=0)
3482
3483  @mock.patch('time.sleep')
3484  @mock.patch('devil.android.sdk.adb_wrapper.RestartServer')
3485  def testHealthyDevices_EmptyListDeviceArg_no_attached_with_retry(
3486      self, mock_restart, mock_sleep):
3487    with self.assertCalls(
3488        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), []),
3489        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), []),
3490        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), []),
3491        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), []),
3492        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), [])):
3493      with self.assertRaises(device_errors.NoDevicesError):
3494        device_utils.DeviceUtils.HealthyDevices(device_arg=[], retries=4)
3495    self.assertEquals(mock_restart.call_count, 4)
3496    self.assertEquals(
3497        mock_sleep.call_args_list,
3498        [mock.call(2), mock.call(4),
3499         mock.call(8), mock.call(16)])
3500
3501  @mock.patch('time.sleep')
3502  @mock.patch('devil.android.sdk.adb_wrapper.RestartServer')
3503  def testHealthyDevices_EmptyListDeviceArg_no_attached_with_resets(
3504      self, mock_restart, mock_sleep):
3505    # The reset_usb import fails on windows. Mock the full import here so it can
3506    # succeed like it would on linux.
3507    mock_reset_import = mock.MagicMock()
3508    sys.modules['devil.utils.reset_usb'] = mock_reset_import
3509    with self.assertCalls(
3510        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), []),
3511        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), []),
3512        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), []),
3513        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), []),
3514        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(), [])):
3515      with self.assertRaises(device_errors.NoDevicesError):
3516        with mock.patch.object(mock_reset_import,
3517                               'reset_all_android_devices') as mock_reset:
3518          device_utils.DeviceUtils.HealthyDevices(
3519              device_arg=[], retries=4, enable_usb_resets=True)
3520          self.assertEquals(mock_reset.call_count, 1)
3521    self.assertEquals(mock_restart.call_count, 4)
3522    self.assertEquals(
3523        mock_sleep.call_args_list,
3524        [mock.call(2), mock.call(4),
3525         mock.call(8), mock.call(16)])
3526
3527  def testHealthyDevices_ListDeviceArg(self):
3528    device_arg = ['0123456789abcdef', 'fedcba9876543210']
3529    try:
3530      os.environ['ANDROID_SERIAL'] = 'should-not-apply'
3531      with self.assertCalls():  # Should skip adb devices when device is known.
3532        devices = device_utils.DeviceUtils.HealthyDevices(device_arg=device_arg)
3533    finally:
3534      del os.environ['ANDROID_SERIAL']
3535    self.assertEquals(2, len(devices))
3536
3537  def testHealthyDevices_abisArg_no_matching_abi(self):
3538    test_serials = ['0123456789abcdef', 'fedcba9876543210']
3539    with self.assertCalls(
3540        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
3541         [_AdbWrapperMock(s) for s in test_serials]),
3542        (mock.call.devil.android.device_utils.DeviceUtils.GetABI(), abis.ARM),
3543        (mock.call.devil.android.device_utils.DeviceUtils.GetABI(), abis.ARM)):
3544      with self.assertRaises(device_errors.NoDevicesError):
3545        device_utils.DeviceUtils.HealthyDevices(
3546            device_arg=[], retries=0, abis=[abis.ARM_64])
3547
3548  def testHealthyDevices_abisArg_filter_on_abi(self):
3549    test_serials = ['0123456789abcdef', 'fedcba9876543210']
3550    with self.assertCalls(
3551        (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
3552         [_AdbWrapperMock(s) for s in test_serials]),
3553        (mock.call.devil.android.device_utils.DeviceUtils.GetABI(),
3554         abis.ARM_64),
3555        (mock.call.devil.android.device_utils.DeviceUtils.GetABI(), abis.ARM)):
3556      devices = device_utils.DeviceUtils.HealthyDevices(
3557          device_arg=[], retries=0, abis=[abis.ARM_64])
3558    self.assertEquals(1, len(devices))
3559
3560
3561class DeviceUtilsRestartAdbdTest(DeviceUtilsTest):
3562  def testAdbdRestart(self):
3563    mock_temp_file = '/sdcard/temp-123.sh'
3564    with self.assertCalls(
3565        (mock.call.devil.android.device_temp_file.DeviceTempFile(
3566            self.adb, suffix='.sh'), MockTempFile(mock_temp_file)),
3567        self.call.device.WriteFile(mock.ANY, mock.ANY),
3568        (self.call.device.RunShellCommand(
3569            ['source', mock_temp_file], check_return=True, as_root=True)),
3570        self.call.adb.WaitForDevice()):
3571      self.device.RestartAdbd()
3572
3573
3574class DeviceUtilsGrantPermissionsTest(DeviceUtilsTest):
3575  def _PmGrantShellCall(self, package, permissions):
3576    fragment = 'p=%s;for q in %s;' % (package, ' '.join(sorted(permissions)))
3577    results = []
3578    for permission, result in sorted(permissions.items()):
3579      if result:
3580        output, status = result + '\n', 1
3581      else:
3582        output, status = '', 0
3583      results.append('{output}{sep}{permission}{sep}{status}{sep}\n'.format(
3584          output=output,
3585          permission=permission,
3586          status=status,
3587          sep=device_utils._SHELL_OUTPUT_SEPARATOR))
3588    return (self.call.device.RunShellCommand(
3589        AnyStringWith(fragment),
3590        shell=True,
3591        raw_output=True,
3592        large_output=True,
3593        check_return=True), ''.join(results))
3594
3595  def testGrantPermissions_none(self):
3596    self.device.GrantPermissions('package', [])
3597
3598  def testGrantPermissions_one(self):
3599    with self.patch_call(
3600        self.call.device.build_version_sdk,
3601        return_value=version_codes.MARSHMALLOW):
3602      with self.assertCalls(self._PmGrantShellCall('package', {'p1': 0})):
3603        self.device.GrantPermissions('package', ['p1'])
3604
3605  def testGrantPermissions_multiple(self):
3606    with self.patch_call(
3607        self.call.device.build_version_sdk,
3608        return_value=version_codes.MARSHMALLOW):
3609      with self.assertCalls(
3610          self._PmGrantShellCall('package', {
3611              'p1': 0,
3612              'p2': 0
3613          })):
3614        self.device.GrantPermissions('package', ['p1', 'p2'])
3615
3616  def testGrantPermissions_WriteExtrnalStorage(self):
3617    WRITE = 'android.permission.WRITE_EXTERNAL_STORAGE'
3618    READ = 'android.permission.READ_EXTERNAL_STORAGE'
3619    with PatchLogger() as logger:
3620      with self.patch_call(
3621          self.call.device.build_version_sdk,
3622          return_value=version_codes.MARSHMALLOW):
3623        with self.assertCalls(
3624            self._PmGrantShellCall('package', {
3625                READ: 0,
3626                WRITE: 0
3627            })):
3628          self.device.GrantPermissions('package', [WRITE])
3629      self.assertEqual(logger.warnings, [])
3630
3631  def testGrantPermissions_ManageExtrnalStorage(self):
3632    with PatchLogger() as logger:
3633      with self.patch_call(self.call.device.build_version_sdk,
3634                           return_value=version_codes.R):
3635        with self.assertCalls(
3636            (self.call.device.RunShellCommand(
3637                AnyStringWith('appops set pkg MANAGE_EXTERNAL_STORAGE allow'),
3638                shell=True,
3639                raw_output=True,
3640                large_output=True,
3641                check_return=True),
3642             '{sep}MANAGE_EXTERNAL_STORAGE{sep}0{sep}\n'.format(
3643                 sep=device_utils._SHELL_OUTPUT_SEPARATOR))):
3644          self.device.GrantPermissions(
3645              'pkg', ['android.permission.MANAGE_EXTERNAL_STORAGE'])
3646      self.assertEqual(logger.warnings, [])
3647
3648  def testGrantPermissions_DenyList(self):
3649    with PatchLogger() as logger:
3650      with self.patch_call(
3651          self.call.device.build_version_sdk,
3652          return_value=version_codes.MARSHMALLOW):
3653        with self.assertCalls(self._PmGrantShellCall('package', {'p1': 0})):
3654          self.device.GrantPermissions('package',
3655                                       ['p1', 'foo.permission.C2D_MESSAGE'])
3656      self.assertEqual(logger.warnings, [])
3657
3658  def testGrantPermissions_unchangeablePermision(self):
3659    error_message = (
3660        'Operation not allowed: java.lang.SecurityException: '
3661        'Permission UNCHANGEABLE is not a changeable permission type')
3662    with PatchLogger() as logger:
3663      with self.patch_call(
3664          self.call.device.build_version_sdk,
3665          return_value=version_codes.MARSHMALLOW):
3666        with self.assertCalls(
3667            self._PmGrantShellCall('package', {'UNCHANGEABLE': error_message})):
3668          self.device.GrantPermissions('package', ['UNCHANGEABLE'])
3669      self.assertEqual(logger.warnings,
3670                       [mock.ANY, AnyStringWith('UNCHANGEABLE')])
3671
3672
3673class DeviecUtilsIsScreenOn(DeviceUtilsTest):
3674
3675  _L_SCREEN_ON = ['test=test mInteractive=true']
3676  _K_SCREEN_ON = ['test=test mScreenOn=true']
3677  _L_SCREEN_OFF = ['mInteractive=false']
3678  _K_SCREEN_OFF = ['mScreenOn=false']
3679
3680  def testIsScreenOn_onPreL(self):
3681    with self.patch_call(
3682        self.call.device.build_version_sdk, return_value=version_codes.KITKAT):
3683      with self.assertCalls((self.call.device._RunPipedShellCommand(
3684          'dumpsys input_method | grep mScreenOn'), self._K_SCREEN_ON)):
3685        self.assertTrue(self.device.IsScreenOn())
3686
3687  def testIsScreenOn_onL(self):
3688    with self.patch_call(
3689        self.call.device.build_version_sdk,
3690        return_value=version_codes.LOLLIPOP):
3691      with self.assertCalls((self.call.device._RunPipedShellCommand(
3692          'dumpsys input_method | grep mInteractive'), self._L_SCREEN_ON)):
3693        self.assertTrue(self.device.IsScreenOn())
3694
3695  def testIsScreenOn_offPreL(self):
3696    with self.patch_call(
3697        self.call.device.build_version_sdk, return_value=version_codes.KITKAT):
3698      with self.assertCalls((self.call.device._RunPipedShellCommand(
3699          'dumpsys input_method | grep mScreenOn'), self._K_SCREEN_OFF)):
3700        self.assertFalse(self.device.IsScreenOn())
3701
3702  def testIsScreenOn_offL(self):
3703    with self.patch_call(
3704        self.call.device.build_version_sdk,
3705        return_value=version_codes.LOLLIPOP):
3706      with self.assertCalls((self.call.device._RunPipedShellCommand(
3707          'dumpsys input_method | grep mInteractive'), self._L_SCREEN_OFF)):
3708        self.assertFalse(self.device.IsScreenOn())
3709
3710  def testIsScreenOn_noOutput(self):
3711    with self.patch_call(
3712        self.call.device.build_version_sdk,
3713        return_value=version_codes.LOLLIPOP):
3714      with self.assertCalls((self.call.device._RunPipedShellCommand(
3715          'dumpsys input_method | grep mInteractive'), [])):
3716        with self.assertRaises(device_errors.CommandFailedError):
3717          self.device.IsScreenOn()
3718
3719
3720class DeviecUtilsSetScreen(DeviceUtilsTest):
3721  @mock.patch('time.sleep', mock.Mock())
3722  def testSetScren_alreadySet(self):
3723    with self.assertCalls((self.call.device.IsScreenOn(), False)):
3724      self.device.SetScreen(False)
3725
3726  @mock.patch('time.sleep', mock.Mock())
3727  def testSetScreen_on(self):
3728    with self.assertCalls(
3729        (self.call.device.IsScreenOn(), False),
3730        (self.call.device.SendKeyEvent(keyevent.KEYCODE_POWER), None),
3731        (self.call.device.IsScreenOn(), True)):
3732      self.device.SetScreen(True)
3733
3734  @mock.patch('time.sleep', mock.Mock())
3735  def testSetScreen_off(self):
3736    with self.assertCalls(
3737        (self.call.device.IsScreenOn(), True),
3738        (self.call.device.SendKeyEvent(keyevent.KEYCODE_POWER), None),
3739        (self.call.device.IsScreenOn(), False)):
3740      self.device.SetScreen(False)
3741
3742  @mock.patch('time.sleep', mock.Mock())
3743  def testSetScreen_slow(self):
3744    with self.assertCalls(
3745        (self.call.device.IsScreenOn(), True),
3746        (self.call.device.SendKeyEvent(keyevent.KEYCODE_POWER), None),
3747        (self.call.device.IsScreenOn(), True),
3748        (self.call.device.IsScreenOn(), True),
3749        (self.call.device.IsScreenOn(), False)):
3750      self.device.SetScreen(False)
3751
3752
3753class DeviecUtilsLoadCacheData(DeviceUtilsTest):
3754  def testInvalidJson(self):
3755    self.assertFalse(self.device.LoadCacheData(''))
3756
3757  def testTokenMissing(self):
3758    with self.assertCalls(self.EnsureCacheInitialized()):
3759      self.assertFalse(self.device.LoadCacheData('{}'))
3760
3761  def testTokenStale(self):
3762    with self.assertCalls(self.EnsureCacheInitialized()):
3763      self.assertFalse(self.device.LoadCacheData('{"token":"foo"}'))
3764
3765  def testTokenMatches(self):
3766    with self.assertCalls(self.EnsureCacheInitialized()):
3767      self.assertTrue(self.device.LoadCacheData('{"token":"TOKEN"}'))
3768
3769  def testDumpThenLoad(self):
3770    with self.assertCalls(self.EnsureCacheInitialized()):
3771      data = json.loads(self.device.DumpCacheData())
3772      data['token'] = 'TOKEN'
3773      self.assertTrue(self.device.LoadCacheData(json.dumps(data)))
3774
3775
3776class DeviceUtilsGetIMEITest(DeviceUtilsTest):
3777  def testSuccessfulDumpsys(self):
3778    dumpsys_output = ('Phone Subscriber Info:'
3779                      '  Phone Type = GSM'
3780                      '  Device ID = 123454321')
3781    with self.assertCalls(
3782        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
3783        (self.call.adb.Shell('dumpsys iphonesubinfo'), dumpsys_output)):
3784      self.assertEquals(self.device.GetIMEI(), '123454321')
3785
3786  def testSuccessfulServiceCall(self):
3787    service_output = """
3788        Result: Parcel(\n'
3789          0x00000000: 00000000 0000000f 00350033 00360033 '........7.6.5.4.'
3790          0x00000010: 00360032 00370030 00300032 00300039 '3.2.1.0.1.2.3.4.'
3791          0x00000020: 00380033 00000039                   '5.6.7...        ')
3792    """
3793    with self.assertCalls(
3794        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '24'),
3795        (self.call.adb.Shell('service call iphonesubinfo 1'), service_output)):
3796      self.assertEquals(self.device.GetIMEI(), '765432101234567')
3797
3798  def testNoIMEI(self):
3799    with self.assertCalls(
3800        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
3801        (self.call.adb.Shell('dumpsys iphonesubinfo'), 'no device id')):
3802      with self.assertRaises(device_errors.CommandFailedError):
3803        self.device.GetIMEI()
3804
3805  def testAdbError(self):
3806    with self.assertCalls(
3807        (self.call.device.GetProp('ro.build.version.sdk', cache=True), '24'),
3808        (self.call.adb.Shell('service call iphonesubinfo 1'),
3809         self.ShellError())):
3810      with self.assertRaises(device_errors.CommandFailedError):
3811        self.device.GetIMEI()
3812
3813
3814class DeviceUtilsChangeOwner(DeviceUtilsTest):
3815  def testChangeOwner(self):
3816    with self.assertCalls(
3817        (self.call.device.RunShellCommand(
3818            ['chown', 'user.group', '/path/to/file1', 'file2'],
3819            check_return=True))):
3820      self.device.ChangeOwner('user.group', ['/path/to/file1', 'file2'])
3821
3822
3823class DeviceUtilsChangeSecurityContext(DeviceUtilsTest):
3824  def testChangeSecurityContext(self):
3825    with self.assertCalls((self.call.device.RunShellCommand(
3826        ['chcon', 'u:object_r:system_data_file:s0', '/path', '/path2'],
3827        as_root=device_utils._FORCE_SU,
3828        check_return=True))):
3829      self.device.ChangeSecurityContext('u:object_r:system_data_file:s0',
3830                                        ['/path', '/path2'])
3831
3832
3833class DeviceUtilsLocale(DeviceUtilsTest):
3834  def testLocaleLegacy(self):
3835    with self.assertCalls(
3836        (self.call.device.GetProp('persist.sys.locale', cache=False), ''),
3837        (self.call.device.GetProp('persist.sys.language', cache=False), 'en'),
3838        (self.call.device.GetProp('persist.sys.country', cache=False), 'US')):
3839      self.assertEquals(self.device.GetLocale(), ('en', 'US'))
3840
3841  def testLocale(self):
3842    with self.assertCalls(
3843        (self.call.device.GetProp('persist.sys.locale', cache=False), 'en-US'),
3844        (self.call.device.GetProp('persist.sys.locale', cache=False),
3845         'en-US-sw')):
3846      self.assertEquals(self.device.GetLocale(), ('en', 'US'))
3847      self.assertEquals(self.device.GetLocale(), ('en', 'US-sw'))
3848
3849  def testBadLocale(self):
3850    with self.assertCalls((self.call.device.GetProp(
3851        'persist.sys.locale', cache=False), 'en')):
3852      self.assertEquals(self.device.GetLocale(), ('', ''))
3853
3854  def testLanguageAndCountryLegacy(self):
3855    with self.assertCalls(
3856        (self.call.device.GetProp('persist.sys.locale', cache=False), ''),
3857        (self.call.device.GetProp('persist.sys.language', cache=False), 'en'),
3858        (self.call.device.GetProp('persist.sys.country', cache=False), 'US'),
3859        (self.call.device.GetProp('persist.sys.locale', cache=False), ''),
3860        (self.call.device.GetProp('persist.sys.language', cache=False), 'en'),
3861        (self.call.device.GetProp('persist.sys.country', cache=False), 'US')):
3862      self.assertEquals(self.device.GetLanguage(), 'en')
3863      self.assertEquals(self.device.GetCountry(), 'US')
3864
3865  def testLanguageAndCountry(self):
3866    with self.assertCalls(
3867        (self.call.device.GetProp('persist.sys.locale', cache=False), 'en-US'),
3868        (self.call.device.GetProp('persist.sys.locale', cache=False), 'en-US')):
3869      self.assertEquals(self.device.GetLanguage(), 'en')
3870      self.assertEquals(self.device.GetCountry(), 'US')
3871
3872
3873class IterPushableComponentsTest(unittest.TestCase):
3874  @classmethod
3875  @contextlib.contextmanager
3876  def sampleLayout(cls):
3877    Layout = collections.namedtuple('Layout', [
3878        'root', 'basic_file', 'symlink_file', 'symlink_dir',
3879        'dir_with_symlinks', 'dir_without_symlinks'
3880    ])
3881
3882    with tempfile_ext.NamedTemporaryDirectory() as layout_root:
3883      dir1 = os.path.join(layout_root, 'dir1')
3884      os.makedirs(dir1)
3885
3886      basic_file = os.path.join(dir1, 'file1.txt')
3887      with open(basic_file, 'w') as f:
3888        f.write('hello world')
3889
3890      symlink = os.path.join(dir1, 'symlink.txt')
3891      os.symlink(basic_file, symlink)
3892
3893      dir2 = os.path.join(layout_root, 'dir2')
3894      os.makedirs(dir2)
3895
3896      with open(os.path.join(dir2, 'file2.txt'), 'w') as f:
3897        f.write('goodnight moon')
3898
3899      symlink_dir = os.path.join(layout_root, 'dir3')
3900      os.symlink(dir2, symlink_dir)
3901
3902      yield Layout(layout_root, basic_file, symlink, symlink_dir, dir1, dir2)
3903
3904  def safeAssertItemsEqual(self, expected, actual):
3905    if six.PY2:
3906      self.assertItemsEqual(expected, actual)
3907    else:
3908      self.assertCountEqual(expected, actual) # pylint: disable=no-member
3909
3910  def testFile(self):
3911    with self.sampleLayout() as layout:
3912      device_path = '/sdcard/basic_file'
3913
3914      expected = [(layout.basic_file, device_path, True)]
3915      actual = list(
3916          device_utils._IterPushableComponents(layout.basic_file, device_path))
3917      self.safeAssertItemsEqual(expected, actual)
3918
3919  def testSymlinkFile(self):
3920    with self.sampleLayout() as layout:
3921      device_path = '/sdcard/basic_symlink'
3922
3923      expected = [(os.path.realpath(layout.symlink_file), device_path, False)]
3924      actual = list(
3925          device_utils._IterPushableComponents(layout.symlink_file,
3926                                               device_path))
3927      self.safeAssertItemsEqual(expected, actual)
3928
3929  def testDirectoryWithNoSymlink(self):
3930    with self.sampleLayout() as layout:
3931      device_path = '/sdcard/basic_directory'
3932
3933      expected = [(layout.dir_without_symlinks, device_path, True)]
3934      actual = list(
3935          device_utils._IterPushableComponents(layout.dir_without_symlinks,
3936                                               device_path))
3937      self.safeAssertItemsEqual(expected, actual)
3938
3939  def testDirectoryWithSymlink(self):
3940    with self.sampleLayout() as layout:
3941      device_path = '/sdcard/directory'
3942
3943      expected = [
3944          (layout.basic_file,
3945           posixpath.join(device_path, os.path.basename(layout.basic_file)),
3946           True),
3947          (os.path.realpath(layout.symlink_file),
3948           posixpath.join(device_path, os.path.basename(layout.symlink_file)),
3949           False),
3950      ]
3951      actual = list(
3952          device_utils._IterPushableComponents(layout.dir_with_symlinks,
3953                                               device_path))
3954      self.safeAssertItemsEqual(expected, actual)
3955
3956  def testSymlinkDirectory(self):
3957    with self.sampleLayout() as layout:
3958      device_path = '/sdcard/directory'
3959
3960      expected = [(os.path.realpath(layout.symlink_dir), device_path, False)]
3961      actual = list(
3962          device_utils._IterPushableComponents(layout.symlink_dir, device_path))
3963      self.safeAssertItemsEqual(expected, actual)
3964
3965  def testDirectoryWithNestedSymlink(self):
3966    with self.sampleLayout() as layout:
3967      device_path = '/sdcard/directory'
3968
3969      expected = [
3970          (layout.dir_without_symlinks,
3971           posixpath.join(device_path,
3972                          os.path.basename(layout.dir_without_symlinks)), True),
3973          (layout.basic_file,
3974           posixpath.join(
3975               device_path,
3976               *os.path.split(os.path.relpath(layout.basic_file, layout.root))),
3977           True),
3978          (os.path.realpath(layout.symlink_file),
3979           posixpath.join(
3980               device_path,
3981               *os.path.split(
3982                   os.path.relpath(layout.symlink_file, layout.root))), False),
3983          (os.path.realpath(layout.symlink_dir),
3984           posixpath.join(
3985               device_path,
3986               *os.path.split(os.path.relpath(layout.symlink_dir,
3987                                              layout.root))), False),
3988      ]
3989      actual = list(
3990          device_utils._IterPushableComponents(layout.root, device_path))
3991      self.safeAssertItemsEqual(expected, actual)
3992
3993
3994class DeviceUtilsGetTracingPathTest(DeviceUtilsTest):
3995  def testGetTracingPath_hasDebugfs(self):
3996    with self.assertCalls(
3997        (self.call.device.RunShellCommand(['mount'], retries=0,
3998                                          timeout=10, check_return=True),
3999        ['debugfs on /sys/kernel/debug', 'proc on /proc'])):
4000      self.assertEquals('/sys/kernel/debug/tracing',
4001                        self.device.GetTracingPath())
4002
4003  def testGetTracingPath_noDebugfs(self):
4004    with self.assertCalls(
4005        (self.call.device.RunShellCommand(['mount'], retries=0,
4006                                          timeout=10, check_return=True),
4007        ['proc on /proc'])):
4008      self.assertEquals('/sys/kernel/tracing', self.device.GetTracingPath())
4009
4010
4011if __name__ == '__main__':
4012  logging.getLogger().setLevel(logging.DEBUG)
4013  unittest.main(verbosity=2)
4014