dthkao: <img class="emoji" title=":lgtm:" alt=":lgtm:" align="absmiddle" src="https://reviewable.io/lgtm.png" height="20" width="61"/>

---

Review status: 0 of 2 files reviewed at latest revision, all discussions resolved, some commit checks failed.

---



*Comments from [Reviewable](https://reviewable.io:443/reviews/google/mobly/380#-:-L28eYMOEVk9ut_WEarD:bnfp4nl)*
<!-- Sent from Reviewable.io -->

diff --git a/mobly/controllers/android_device.py b/mobly/controllers/android_device.py
index e4f05de..4eee55b 100644
--- a/mobly/controllers/android_device.py
+++ b/mobly/controllers/android_device.py
@@ -421,7 +421,7 @@ class AndroidDevice(object):
     """
 
     def __init__(self, serial=''):
-        self._serial = serial
+        self._serial = str(serial)
         # logging.log_path only exists when this is used in an Mobly test run.
         self._log_path_base = getattr(logging, 'log_path', '/tmp/logs')
         self._log_path = os.path.join(self._log_path_base,
@@ -570,6 +570,7 @@ class AndroidDevice(object):
         Raises:
             DeviceError: tries to update serial when any service is running.
         """
+        new_serial = str(new_serial)
         if self.has_active_service:
             raise DeviceError(
                 self,

adb call fails if numeric serial numbers are used
If users use devices whose serials are entirely numeric and do not wrap the serial with quotation mark, we get:

```
Traceback (most recent call last):
  File ".../mobly/test_runner.py", line 420, in _register_controller
    objects = create(controller_config)
  File ".../mobly/controllers/android_device.py", line 87, in create
    ads = get_instances_with_configs(configs)
  File ".../mobly/controllers/android_device.py", line 257, in get_instances_with_configs
    ad = AndroidDevice(serial)
  File ".../mobly/controllers/android_device.py", line 402, in __init__
    if not self.is_bootloader and self.is_rootable:
  File ".../mobly/controllers/android_device.py", line 637, in is_rootable
    build_type_output = self.adb.getprop('ro.build.type').lower()
  File ".../mobly/controllers/android_device_lib/adb.py", line 175, in getprop
    return self.shell('getprop %s' % prop_name).decode('utf-8').strip()
  File ".../mobly/controllers/android_device_lib/adb.py", line 199, in adb_call
    clean_name, args, shell=shell, timeout=timeout)
  File ".../mobly/controllers/android_device_lib/adb.py", line 161, in _exec_adb_cmd
    return self._exec_cmd(adb_cmd, shell=shell, timeout=timeout)
  File ".../mobly/controllers/android_device_lib/adb.py", line 122, in _exec_cmd
    args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=shell)
  File "/usr/lib/python2.7/subprocess.py", line 711, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1343, in _execute_child
    raise child_exception
TypeError: execv() arg 2 must contain only strings
```
  
diff --git a/tests/mobly/controllers/android_device_test.py b/tests/mobly/controllers/android_device_test.py
index e57db60..f9c6cf3 100755
--- a/tests/mobly/controllers/android_device_test.py
+++ b/tests/mobly/controllers/android_device_test.py
@@ -233,17 +233,17 @@ class AndroidDeviceTest(unittest.TestCase):
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1))
+        return_value=mock_android_device.MockAdbProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     def test_AndroidDevice_instantiation(self, MockFastboot, MockAdbProxy):
         """Verifies the AndroidDevice object's basic attributes are correctly
         set after instantiation.
         """
         mock_serial = 1
         ad = android_device.AndroidDevice(serial=mock_serial)
-        self.assertEqual(ad.serial, 1)
+        self.assertEqual(ad.serial, '1')
         self.assertEqual(ad.model, 'fakemodel')
         self.assertIsNone(ad._adb_logcat_process)
         self.assertIsNone(ad.adb_logcat_file_path)
@@ -253,29 +253,29 @@ class AndroidDeviceTest(unittest.TestCase):
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1))
+        return_value=mock_android_device.MockAdbProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     def test_AndroidDevice_build_info(self, MockFastboot, MockAdbProxy):
         """Verifies the AndroidDevice object's basic attributes are correctly
         set after instantiation.
         """
-        ad = android_device.AndroidDevice(serial=1)
+        ad = android_device.AndroidDevice(serial='1')
         build_info = ad.build_info
         self.assertEqual(build_info['build_id'], 'AB42')
         self.assertEqual(build_info['build_type'], 'userdebug')
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1))
+        return_value=mock_android_device.MockAdbProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     def test_AndroidDevice_device_info(self, MockFastboot, MockAdbProxy):
         ad = android_device.AndroidDevice(serial=1)
         device_info = ad.device_info
-        self.assertEqual(device_info['serial'], 1)
+        self.assertEqual(device_info['serial'], '1')
         self.assertEqual(device_info['model'], 'fakemodel')
         self.assertEqual(device_info['build_info']['build_id'], 'AB42')
         self.assertEqual(device_info['build_info']['build_type'], 'userdebug')
@@ -297,7 +297,7 @@ class AndroidDeviceTest(unittest.TestCase):
         """Verifies AndroidDevice.take_bug_report calls the correct adb command
         and writes the bugreport file to the correct path.
         """
-        mock_serial = 1
+        mock_serial = '1'
         ad = android_device.AndroidDevice(serial=mock_serial)
         ad.take_bug_report('test_something', 'sometime')
         expected_path = os.path.join(
@@ -306,17 +306,17 @@ class AndroidDeviceTest(unittest.TestCase):
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1, fail_br=True))
+        return_value=mock_android_device.MockAdbProxy('1', fail_br=True))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     @mock.patch('mobly.utils.create_dir')
     def test_AndroidDevice_take_bug_report_fail(self, create_dir_mock,
                                                 FastbootProxy, MockAdbProxy):
         """Verifies AndroidDevice.take_bug_report writes out the correct message
         when taking bugreport fails.
         """
-        mock_serial = 1
+        mock_serial = '1'
         ad = android_device.AndroidDevice(serial=mock_serial)
         expected_msg = '.* Failed to take bugreport.'
         with self.assertRaisesRegex(android_device.Error, expected_msg):
@@ -324,14 +324,14 @@ class AndroidDeviceTest(unittest.TestCase):
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1))
+        return_value=mock_android_device.MockAdbProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     @mock.patch('mobly.utils.create_dir')
     def test_AndroidDevice_take_bug_report_with_destination(
             self, create_dir_mock, FastbootProxy, MockAdbProxy):
-        mock_serial = 1
+        mock_serial = '1'
         ad = android_device.AndroidDevice(serial=mock_serial)
         dest = tempfile.gettempdir()
         ad.take_bug_report("test_something", "sometime", destination=dest)
@@ -341,17 +341,17 @@ class AndroidDeviceTest(unittest.TestCase):
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
         return_value=mock_android_device.MockAdbProxy(
-            1, fail_br_before_N=True))
+            '1', fail_br_before_N=True))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     @mock.patch('mobly.utils.create_dir')
     def test_AndroidDevice_take_bug_report_fallback(
             self, create_dir_mock, FastbootProxy, MockAdbProxy):
         """Verifies AndroidDevice.take_bug_report falls back to traditional
         bugreport on builds that do not have bugreportz.
         """
-        mock_serial = 1
+        mock_serial = '1'
         ad = android_device.AndroidDevice(serial=mock_serial)
         ad.take_bug_report('test_something', 'sometime')
         expected_path = os.path.join(
@@ -360,10 +360,10 @@ class AndroidDeviceTest(unittest.TestCase):
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1))
+        return_value=mock_android_device.MockAdbProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     @mock.patch('mobly.utils.create_dir')
     @mock.patch(
         'mobly.utils.start_standing_subprocess', return_value='process')
@@ -375,7 +375,7 @@ class AndroidDeviceTest(unittest.TestCase):
         object, including various function calls and the expected behaviors of
         the calls.
         """
-        mock_serial = 1
+        mock_serial = '1'
         ad = android_device.AndroidDevice(serial=mock_serial)
         expected_msg = '.* No ongoing adb logcat collection found.'
         # Expect error if stop is called before start.
@@ -406,10 +406,10 @@ class AndroidDeviceTest(unittest.TestCase):
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1))
+        return_value=mock_android_device.MockAdbProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     @mock.patch('mobly.utils.create_dir')
     @mock.patch(
         'mobly.utils.start_standing_subprocess', return_value='process')
@@ -421,7 +421,7 @@ class AndroidDeviceTest(unittest.TestCase):
         object, including various function calls and the expected behaviors of
         the calls.
         """
-        mock_serial = 1
+        mock_serial = '1'
         ad = android_device.AndroidDevice(serial=mock_serial)
         ad.adb_logcat_param = '-b radio'
         expected_msg = '.* No ongoing adb logcat collection found.'
@@ -442,17 +442,17 @@ class AndroidDeviceTest(unittest.TestCase):
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1))
+        return_value=mock_android_device.MockAdbProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     @mock.patch(
         'mobly.utils.start_standing_subprocess', return_value='process')
     @mock.patch('mobly.utils.stop_standing_subprocess')
     def test_AndroidDevice_change_log_path(self, stop_proc_mock,
                                            start_proc_mock, FastbootProxy,
                                            MockAdbProxy):
-        ad = android_device.AndroidDevice(serial=1)
+        ad = android_device.AndroidDevice(serial='1')
         ad.start_adb_logcat()
         ad.stop_adb_logcat()
         old_path = ad.log_path
@@ -463,17 +463,17 @@ class AndroidDeviceTest(unittest.TestCase):
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1))
+        return_value=mock_android_device.MockAdbProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     @mock.patch(
         'mobly.utils.start_standing_subprocess', return_value='process')
     @mock.patch('mobly.utils.stop_standing_subprocess')
     def test_AndroidDevice_change_log_path_no_log_exists(
             self, stop_proc_mock, start_proc_mock, FastbootProxy,
             MockAdbProxy):
-        ad = android_device.AndroidDevice(serial=1)
+        ad = android_device.AndroidDevice(serial='1')
         old_path = ad.log_path
         new_log_path = tempfile.mkdtemp()
         ad.log_path = new_log_path
@@ -482,10 +482,10 @@ class AndroidDeviceTest(unittest.TestCase):
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1))
+        return_value=mock_android_device.MockAdbProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     @mock.patch('mobly.utils.create_dir')
     @mock.patch(
         'mobly.utils.start_standing_subprocess', return_value='process')
@@ -493,7 +493,7 @@ class AndroidDeviceTest(unittest.TestCase):
     def test_AndroidDevice_change_log_path_with_service(
             self, stop_proc_mock, start_proc_mock, creat_dir_mock,
             FastbootProxy, MockAdbProxy):
-        ad = android_device.AndroidDevice(serial=1)
+        ad = android_device.AndroidDevice(serial='1')
         ad.start_adb_logcat()
         new_log_path = tempfile.mkdtemp()
         expected_msg = '.* Cannot change `log_path` when there is service running.'
@@ -502,10 +502,10 @@ class AndroidDeviceTest(unittest.TestCase):
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1))
+        return_value=mock_android_device.MockAdbProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     @mock.patch('mobly.utils.create_dir')
     @mock.patch(
         'mobly.utils.start_standing_subprocess', return_value='process')
@@ -513,7 +513,7 @@ class AndroidDeviceTest(unittest.TestCase):
     def test_AndroidDevice_change_log_path_with_existing_file(
             self, stop_proc_mock, start_proc_mock, creat_dir_mock,
             FastbootProxy, MockAdbProxy):
-        ad = android_device.AndroidDevice(serial=1)
+        ad = android_device.AndroidDevice(serial='1')
         new_log_path = tempfile.mkdtemp()
         with open(os.path.join(new_log_path, 'file.txt'), 'w') as f:
             f.write('hahah.')
@@ -523,10 +523,10 @@ class AndroidDeviceTest(unittest.TestCase):
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1))
+        return_value=mock_android_device.MockAdbProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     @mock.patch('mobly.utils.create_dir')
     @mock.patch(
         'mobly.utils.start_standing_subprocess', return_value='process')
@@ -534,19 +534,19 @@ class AndroidDeviceTest(unittest.TestCase):
     def test_AndroidDevice_update_serial(self, stop_proc_mock, start_proc_mock,
                                          creat_dir_mock, FastbootProxy,
                                          MockAdbProxy):
-        ad = android_device.AndroidDevice(serial=1)
-        ad.update_serial(2)
-        self.assertEqual(ad.serial, 2)
+        ad = android_device.AndroidDevice(serial='1')
+        ad.update_serial('2')
+        self.assertEqual(ad.serial, '2')
         self.assertEqual(ad.debug_tag, ad.serial)
         self.assertEqual(ad.adb.serial, ad.serial)
         self.assertEqual(ad.fastboot.serial, ad.serial)
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1))
+        return_value=mock_android_device.MockAdbProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     @mock.patch('mobly.utils.create_dir')
     @mock.patch(
         'mobly.utils.start_standing_subprocess', return_value='process')
@@ -554,18 +554,18 @@ class AndroidDeviceTest(unittest.TestCase):
     def test_AndroidDevice_update_serial_with_service_running(
             self, stop_proc_mock, start_proc_mock, creat_dir_mock,
             FastbootProxy, MockAdbProxy):
-        ad = android_device.AndroidDevice(serial=1)
+        ad = android_device.AndroidDevice(serial='1')
         ad.start_adb_logcat()
         expected_msg = '.* Cannot change device serial number when there is service running.'
         with self.assertRaisesRegex(android_device.Error, expected_msg):
-            ad.update_serial(2)
+            ad.update_serial('2')
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1))
+        return_value=mock_android_device.MockAdbProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     @mock.patch(
         'mobly.utils.start_standing_subprocess', return_value='process')
     @mock.patch('mobly.utils.stop_standing_subprocess')
@@ -579,7 +579,7 @@ class AndroidDeviceTest(unittest.TestCase):
         file, locates the correct adb log lines within the given time range,
         and writes the lines to the correct output file.
         """
-        mock_serial = 1
+        mock_serial = '1'
         ad = android_device.AndroidDevice(serial=mock_serial)
         # Direct the log path of the ad to a temp dir to avoid racing.
         ad._log_path_base = self.tmp_dir
@@ -606,32 +606,32 @@ class AndroidDeviceTest(unittest.TestCase):
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1))
+        return_value=mock_android_device.MockAdbProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.snippet_client.SnippetClient')
     @mock.patch('mobly.utils.get_available_host_port')
     def test_AndroidDevice_load_snippet(self, MockGetPort, MockSnippetClient,
                                         MockFastboot, MockAdbProxy):
-        ad = android_device.AndroidDevice(serial=1)
+        ad = android_device.AndroidDevice(serial='1')
         ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME)
         self.assertTrue(hasattr(ad, 'snippet'))
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1))
+        return_value=mock_android_device.MockAdbProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.snippet_client.SnippetClient',
         return_value=MockSnippetClient)
     @mock.patch('mobly.utils.get_available_host_port')
     def test_AndroidDevice_load_snippet_dup_package(
             self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy):
-        ad = android_device.AndroidDevice(serial=1)
+        ad = android_device.AndroidDevice(serial='1')
         ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME)
         expected_msg = ('Snippet package "%s" has already been loaded under '
                         'name "snippet".') % MOCK_SNIPPET_PACKAGE_NAME
@@ -640,17 +640,17 @@ class AndroidDeviceTest(unittest.TestCase):
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1))
+        return_value=mock_android_device.MockAdbProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.snippet_client.SnippetClient',
         return_value=MockSnippetClient)
     @mock.patch('mobly.utils.get_available_host_port')
     def test_AndroidDevice_load_snippet_dup_snippet_name(
             self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy):
-        ad = android_device.AndroidDevice(serial=1)
+        ad = android_device.AndroidDevice(serial='1')
         ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME)
         expected_msg = ('Attribute "%s" is already registered with package '
                         '"%s", it cannot be used again.') % (
@@ -660,16 +660,16 @@ class AndroidDeviceTest(unittest.TestCase):
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1))
+        return_value=mock_android_device.MockAdbProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.snippet_client.SnippetClient')
     @mock.patch('mobly.utils.get_available_host_port')
     def test_AndroidDevice_load_snippet_dup_attribute_name(
             self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy):
-        ad = android_device.AndroidDevice(serial=1)
+        ad = android_device.AndroidDevice(serial='1')
         expected_msg = ('Attribute "%s" already exists, please use a different'
                         ' name') % 'adb'
         with self.assertRaisesRegex(android_device.Error, expected_msg):
@@ -677,10 +677,10 @@ class AndroidDeviceTest(unittest.TestCase):
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1))
+        return_value=mock_android_device.MockAdbProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.snippet_client.SnippetClient')
     @mock.patch('mobly.utils.get_available_host_port')
@@ -697,7 +697,7 @@ class AndroidDeviceTest(unittest.TestCase):
             side_effect=expected_e)
         MockSnippetClient.stop_app = mock.Mock(
             side_effect=Exception('stop failed.'))
-        ad = android_device.AndroidDevice(serial=1)
+        ad = android_device.AndroidDevice(serial='1')
         try:
             ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME)
         except Exception as e:
@@ -705,30 +705,30 @@ class AndroidDeviceTest(unittest.TestCase):
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1))
+        return_value=mock_android_device.MockAdbProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.snippet_client.SnippetClient')
     @mock.patch('mobly.utils.get_available_host_port')
     def test_AndroidDevice_snippet_cleanup(
             self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy):
-        ad = android_device.AndroidDevice(serial=1)
+        ad = android_device.AndroidDevice(serial='1')
         ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME)
         ad.stop_services()
         self.assertFalse(hasattr(ad, 'snippet'))
 
     @mock.patch(
         'mobly.controllers.android_device_lib.adb.AdbProxy',
-        return_value=mock_android_device.MockAdbProxy(1))
+        return_value=mock_android_device.MockAdbProxy('1'))
     @mock.patch(
         'mobly.controllers.android_device_lib.fastboot.FastbootProxy',
-        return_value=mock_android_device.MockFastbootProxy(1))
+        return_value=mock_android_device.MockFastbootProxy('1'))
     def test_AndroidDevice_debug_tag(self, MockFastboot, MockAdbProxy):
-        mock_serial = 1
+        mock_serial = '1'
         ad = android_device.AndroidDevice(serial=mock_serial)
-        self.assertEqual(ad.debug_tag, 1)
+        self.assertEqual(ad.debug_tag, '1')
         try:
             raise android_device.DeviceError(ad, 'Something')
         except android_device.DeviceError as e:

pip install -e .
parse_log_pytest
pytest
pytest
apt-get update apt-get install -y gcc
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
exceptiongroup @ file:///croot/exceptiongroup_1706031385326/work
future==1.0.0
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
-e git+https://github.com/google/mobly.git@7e5e62af4ab4537bf619f0ee403c05f004c5baf0#egg=mobly
mock==1.0.1
packaging @ file:///croot/packaging_1734472117206/work
pluggy @ file:///croot/pluggy_1733169602837/work
portpicker==1.6.0
psutil==7.0.0
pytest @ file:///croot/pytest_1738938843180/work
pytz==2025.2
PyYAML==6.0.2
timeout-decorator==0.5.0
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work

name: mobly
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - exceptiongroup=1.2.0=py39h06a4308_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - packaging=24.2=py39h06a4308_0
  - pip=25.0=py39h06a4308_0
  - pluggy=1.5.0=py39h06a4308_0
  - pytest=8.3.4=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py39h06a4308_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - future==1.0.0
      - mock==1.0.1
      - portpicker==1.6.0
      - psutil==7.0.0
      - pytz==2025.2
      - pyyaml==6.0.2
      - timeout-decorator==0.5.0
prefix: /opt/conda/envs/mobly

tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_device_info tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_instantiation
tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_build_info tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_cat_adb_log tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_change_log_path tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_change_log_path_no_log_exists tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_change_log_path_with_existing_file tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_change_log_path_with_service tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_debug_tag tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_load_snippet tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_load_snippet_dup_attribute_name tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_load_snippet_dup_package tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_load_snippet_dup_snippet_name tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_load_snippet_start_app_fails tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_snippet_cleanup tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_take_bug_report tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_take_bug_report_fail tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_take_bug_report_fallback tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_take_bug_report_with_destination tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_take_logcat tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_take_logcat_with_user_param tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_update_serial tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_AndroidDevice_update_serial_with_service_running tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_create_with_dict_list tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_create_with_empty_config tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_create_with_no_valid_config tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_create_with_not_list_config tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_create_with_pickup_all tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_create_with_string_list tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_create_with_usb_id tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_get_device_no_match tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_get_device_success_with_serial tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_get_device_success_with_serial_and_extra_field tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_get_device_too_many_matches tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_get_devices_no_match tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_get_devices_success_with_extra_field tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_start_services_on_ads tests/mobly/controllers/android_device_test.py::AndroidDeviceTest::test_start_services_on_ads_skip_logcat
mobly/controllers/android_device.py
mobly/controllers/android_device.py