prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Snippets are not compatible with UIAutomator
  'am instrument' only sets up a UiAutomationConnection in -w mode (I don't know why). Snippets are not run in wait mode, so UiAutomationConnection is null. This crashes uiautomator, which needs that proxy object for privileged operations back to the shell.
  
  We need to start the snippets in -w mode, using something like `start_standing_subprocess`.
  
  </issue>
  <code>
  [start of mobly/controllers/android_device_lib/snippet_client.py]
  1 #/usr/bin/env python3.4
  2 #
  3 # Copyright 2016 Google Inc.
  4 # 
  5 # Licensed under the Apache License, Version 2.0 (the "License");
  6 # you may not use this file except in compliance with the License.
  7 # You may obtain a copy of the License at
  8 # 
  9 #     http://www.apache.org/licenses/LICENSE-2.0
  10 # 
  11 # Unless required by applicable law or agreed to in writing, software
  12 # distributed under the License is distributed on an "AS IS" BASIS,
  13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 # See the License for the specific language governing permissions and
  15 # limitations under the License.
  16 """JSON RPC interface to Mobly Snippet Lib."""
  17 import logging
  18 import re
  19 
  20 from mobly.controllers.android_device_lib import adb
  21 from mobly.controllers.android_device_lib import jsonrpc_client_base
  22 
  23 _INSTRUMENTATION_RUNNER_PACKAGE = 'com.google.android.mobly.snippet.SnippetRunner'
  24 
  25 _LAUNCH_CMD = 'am instrument -e action start -e port %s %s/' + _INSTRUMENTATION_RUNNER_PACKAGE
  26 
  27 _STOP_CMD = 'am instrument -w -e action stop %s/' + _INSTRUMENTATION_RUNNER_PACKAGE
  28 
  29 
  30 class Error(Exception):
  31     pass
  32 
  33 
  34 class SnippetClient(jsonrpc_client_base.JsonRpcClientBase):
  35     """A client for interacting with snippet APKs using Mobly Snippet Lib.
  36 
  37     See superclass documentation for a list of public attributes.
  38     """
  39 
  40     def __init__(self, package, host_port, adb_proxy, log=logging.getLogger()):
  41         """Initializes a SnippetClient.
  42   
  43         Args:
  44             package: (str) The package name of the apk where the snippets are
  45                      defined.
  46             host_port: (int) The port at which to start the snippet client. Note
  47                        that the same port will currently be used for both the
  48                        device and host side of the connection.
  49             adb_proxy: (adb.AdbProxy) The adb proxy to use to start the app.
  50         """
  51         # TODO(adorokhine): Don't assume that a free host-side port is free on
  52         # the device as well. Both sides should allocate a unique port.
  53         super(SnippetClient, self).__init__(
  54             host_port=host_port,
  55             device_port=host_port,
  56             app_name=package,
  57             adb_proxy=adb_proxy,
  58             log=log)
  59         self.package = package
  60         self.log = log
  61         self._serial = self._adb.serial
  62 
  63     def _do_start_app(self):
  64         """Overrides superclass."""
  65         cmd = _LAUNCH_CMD % (self.device_port, self.package)
  66         # Use info here so people know exactly what's happening here, which is
  67         # helpful since they need to create their own instrumentations and
  68         # manifest.
  69         self.log.info('Launching snippet apk %s', self.package)
  70         self._adb.shell(cmd)
  71 
  72     def stop_app(self):
  73         """Overrides superclass."""
  74         cmd = _STOP_CMD % self.package
  75         self.log.debug('Stopping snippet apk %s', self.package)
  76         out = self._adb.shell(_STOP_CMD % self.package).decode('utf-8')
  77         if 'OK (0 tests)' not in out:
  78             raise Error('Failed to stop existing apk. Unexpected output: %s' %
  79                         out)
  80 
  81     def check_app_installed(self):
  82         """Overrides superclass."""
  83         # Check that the Mobly Snippet app is installed.
  84         if not self._adb_grep_wrapper(
  85                 r'pm list package | tr -d "\r" | grep "^package:%s$"' %
  86                 self.package):
  87             raise jsonrpc_client_base.AppStartError(
  88                 '%s is not installed on %s' % (self.package, self._serial))
  89         # Check that the app is instrumented.
  90         out = self._adb_grep_wrapper(
  91             r'pm list instrumentation | tr -d "\r" | grep ^instrumentation:%s/%s'
  92             % (self.package, _INSTRUMENTATION_RUNNER_PACKAGE))
  93         if not out:
  94             raise jsonrpc_client_base.AppStartError(
  95                 '%s is installed on %s, but it is not instrumented.' %
  96                 (self.package, self._serial))
  97         match = re.search(r'^instrumentation:(.*)\/(.*) \(target=(.*)\)$', out)
  98         target_name = match.group(3)
  99         # Check that the instrumentation target is installed if it's not the
  100         # same as the snippet package.
  101         if target_name != self.package:
  102             out = self._adb_grep_wrapper(
  103                 r'pm list package | tr -d "\r" | grep ^package:%s$' %
  104                 target_name)
  105             if not out:
  106                 raise jsonrpc_client_base.AppStartError(
  107                     'Instrumentation target %s is not installed on %s' %
  108                     (target_name, self._serial))
  109 
  110     def _start_event_client(self):
  111         event_client = SnippetClient(
  112             package=self.package,
  113             host_port=self.host_port,
  114             adb_proxy=self._adb,
  115             log=self.log)
  116         event_client.connect(self.uid,
  117                              jsonrpc_client_base.JsonRpcCommand.CONTINUE)
  118         return event_client
  119
  [end of mobly/controllers/android_device_lib/snippet_client.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/mobly/controllers/android_device_lib/snippet_client.py b/mobly/controllers/android_device_lib/snippet_client.py
  --- a/mobly/controllers/android_device_lib/snippet_client.py
  +++ b/mobly/controllers/android_device_lib/snippet_client.py
  @@ -17,14 +17,18 @@
   import logging
   import re
   
  -from mobly.controllers.android_device_lib import adb
  +from mobly import utils
   from mobly.controllers.android_device_lib import jsonrpc_client_base
   
  -_INSTRUMENTATION_RUNNER_PACKAGE = 'com.google.android.mobly.snippet.SnippetRunner'
  +_INSTRUMENTATION_RUNNER_PACKAGE = (
  +    'com.google.android.mobly.snippet.SnippetRunner')
   
  -_LAUNCH_CMD = 'am instrument -e action start -e port %s %s/' + _INSTRUMENTATION_RUNNER_PACKAGE
  +_LAUNCH_CMD = (
  +    'am instrument -w -e action start -e port %s %s/' +
  +    _INSTRUMENTATION_RUNNER_PACKAGE)
   
  -_STOP_CMD = 'am instrument -w -e action stop %s/' + _INSTRUMENTATION_RUNNER_PACKAGE
  +_STOP_CMD = (
  +    'am instrument -w -e action stop %s/' + _INSTRUMENTATION_RUNNER_PACKAGE)
   
   
   class Error(Exception):
  @@ -59,6 +63,7 @@
           self.package = package
           self.log = log
           self._serial = self._adb.serial
  +        self._proc = None
   
       def _do_start_app(self):
           """Overrides superclass."""
  @@ -67,11 +72,18 @@
           # helpful since they need to create their own instrumentations and
           # manifest.
           self.log.info('Launching snippet apk %s', self.package)
  -        self._adb.shell(cmd)
  +        adb_cmd = ['adb', '-s', self._adb.serial, 'shell', cmd]
  +        self._proc = utils.start_standing_subprocess(adb_cmd, shell=False)
   
       def stop_app(self):
           """Overrides superclass."""
  -        cmd = _STOP_CMD % self.package
  +        # Kill the pending 'adb shell am instrument -w' process if there is one.
  +        # Although killing the snippet apk would abort this process anyway, we
  +        # want to call stop_standing_subprocess() to perform a health check,
  +        # print the failure stack trace if there was any, and reap it from the
  +        # process table.
  +        if self._proc:
  +          utils.stop_standing_subprocess(self._proc)
           self.log.debug('Stopping snippet apk %s', self.package)
           out = self._adb.shell(_STOP_CMD % self.package).decode('utf-8')
           if 'OK (0 tests)' not in out:
  
verification_info: {"golden_diff": "diff --git a/mobly/controllers/android_device_lib/snippet_client.py b/mobly/controllers/android_device_lib/snippet_client.py\n--- a/mobly/controllers/android_device_lib/snippet_client.py\n+++ b/mobly/controllers/android_device_lib/snippet_client.py\n@@ -17,14 +17,18 @@\n import logging\n import re\n \n-from mobly.controllers.android_device_lib import adb\n+from mobly import utils\n from mobly.controllers.android_device_lib import jsonrpc_client_base\n \n-_INSTRUMENTATION_RUNNER_PACKAGE = 'com.google.android.mobly.snippet.SnippetRunner'\n+_INSTRUMENTATION_RUNNER_PACKAGE = (\n+    'com.google.android.mobly.snippet.SnippetRunner')\n \n-_LAUNCH_CMD = 'am instrument -e action start -e port %s %s/' + _INSTRUMENTATION_RUNNER_PACKAGE\n+_LAUNCH_CMD = (\n+    'am instrument -w -e action start -e port %s %s/' +\n+    _INSTRUMENTATION_RUNNER_PACKAGE)\n \n-_STOP_CMD = 'am instrument -w -e action stop %s/' + _INSTRUMENTATION_RUNNER_PACKAGE\n+_STOP_CMD = (\n+    'am instrument -w -e action stop %s/' + _INSTRUMENTATION_RUNNER_PACKAGE)\n \n \n class Error(Exception):\n@@ -59,6 +63,7 @@\n         self.package = package\n         self.log = log\n         self._serial = self._adb.serial\n+        self._proc = None\n \n     def _do_start_app(self):\n         \"\"\"Overrides superclass.\"\"\"\n@@ -67,11 +72,18 @@\n         # helpful since they need to create their own instrumentations and\n         # manifest.\n         self.log.info('Launching snippet apk %s', self.package)\n-        self._adb.shell(cmd)\n+        adb_cmd = ['adb', '-s', self._adb.serial, 'shell', cmd]\n+        self._proc = utils.start_standing_subprocess(adb_cmd, shell=False)\n \n     def stop_app(self):\n         \"\"\"Overrides superclass.\"\"\"\n-        cmd = _STOP_CMD % self.package\n+        # Kill the pending 'adb shell am instrument -w' process if there is one.\n+        # Although killing the snippet apk would abort this process anyway, we\n+        # want to call stop_standing_subprocess() to perform a health check,\n+        # print the failure stack trace if there was any, and reap it from the\n+        # process table.\n+        if self._proc:\n+          utils.stop_standing_subprocess(self._proc)\n         self.log.debug('Stopping snippet apk %s', self.package)\n         out = self._adb.shell(_STOP_CMD % self.package).decode('utf-8')\n         if 'OK (0 tests)' not in out:\n", "issue": "Snippets are not compatible with UIAutomator\n'am instrument' only sets up a UiAutomationConnection in -w mode (I don't know why). Snippets are not run in wait mode, so UiAutomationConnection is null. This crashes uiautomator, which needs that proxy object for privileged operations back to the shell.\r\n\r\nWe need to start the snippets in -w mode, using something like `start_standing_subprocess`.\n", "before_files": [{"content": "#/usr/bin/env python3.4\n#\n# Copyright 2016 Google Inc.\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#     http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\"JSON RPC interface to Mobly Snippet Lib.\"\"\"\nimport logging\nimport re\n\nfrom mobly.controllers.android_device_lib import adb\nfrom mobly.controllers.android_device_lib import jsonrpc_client_base\n\n_INSTRUMENTATION_RUNNER_PACKAGE = 'com.google.android.mobly.snippet.SnippetRunner'\n\n_LAUNCH_CMD = 'am instrument -e action start -e port %s %s/' + _INSTRUMENTATION_RUNNER_PACKAGE\n\n_STOP_CMD = 'am instrument -w -e action stop %s/' + _INSTRUMENTATION_RUNNER_PACKAGE\n\n\nclass Error(Exception):\n    pass\n\n\nclass SnippetClient(jsonrpc_client_base.JsonRpcClientBase):\n    \"\"\"A client for interacting with snippet APKs using Mobly Snippet Lib.\n\n    See superclass documentation for a list of public attributes.\n    \"\"\"\n\n    def __init__(self, package, host_port, adb_proxy, log=logging.getLogger()):\n        \"\"\"Initializes a SnippetClient.\n  \n        Args:\n            package: (str) The package name of the apk where the snippets are\n                     defined.\n            host_port: (int) The port at which to start the snippet client. Note\n                       that the same port will currently be used for both the\n                       device and host side of the connection.\n            adb_proxy: (adb.AdbProxy) The adb proxy to use to start the app.\n        \"\"\"\n        # TODO(adorokhine): Don't assume that a free host-side port is free on\n        # the device as well. Both sides should allocate a unique port.\n        super(SnippetClient, self).__init__(\n            host_port=host_port,\n            device_port=host_port,\n            app_name=package,\n            adb_proxy=adb_proxy,\n            log=log)\n        self.package = package\n        self.log = log\n        self._serial = self._adb.serial\n\n    def _do_start_app(self):\n        \"\"\"Overrides superclass.\"\"\"\n        cmd = _LAUNCH_CMD % (self.device_port, self.package)\n        # Use info here so people know exactly what's happening here, which is\n        # helpful since they need to create their own instrumentations and\n        # manifest.\n        self.log.info('Launching snippet apk %s', self.package)\n        self._adb.shell(cmd)\n\n    def stop_app(self):\n        \"\"\"Overrides superclass.\"\"\"\n        cmd = _STOP_CMD % self.package\n        self.log.debug('Stopping snippet apk %s', self.package)\n        out = self._adb.shell(_STOP_CMD % self.package).decode('utf-8')\n        if 'OK (0 tests)' not in out:\n            raise Error('Failed to stop existing apk. Unexpected output: %s' %\n                        out)\n\n    def check_app_installed(self):\n        \"\"\"Overrides superclass.\"\"\"\n        # Check that the Mobly Snippet app is installed.\n        if not self._adb_grep_wrapper(\n                r'pm list package | tr -d \"\\r\" | grep \"^package:%s$\"' %\n                self.package):\n            raise jsonrpc_client_base.AppStartError(\n                '%s is not installed on %s' % (self.package, self._serial))\n        # Check that the app is instrumented.\n        out = self._adb_grep_wrapper(\n            r'pm list instrumentation | tr -d \"\\r\" | grep ^instrumentation:%s/%s'\n            % (self.package, _INSTRUMENTATION_RUNNER_PACKAGE))\n        if not out:\n            raise jsonrpc_client_base.AppStartError(\n                '%s is installed on %s, but it is not instrumented.' %\n                (self.package, self._serial))\n        match = re.search(r'^instrumentation:(.*)\\/(.*) \\(target=(.*)\\)$', out)\n        target_name = match.group(3)\n        # Check that the instrumentation target is installed if it's not the\n        # same as the snippet package.\n        if target_name != self.package:\n            out = self._adb_grep_wrapper(\n                r'pm list package | tr -d \"\\r\" | grep ^package:%s$' %\n                target_name)\n            if not out:\n                raise jsonrpc_client_base.AppStartError(\n                    'Instrumentation target %s is not installed on %s' %\n                    (target_name, self._serial))\n\n    def _start_event_client(self):\n        event_client = SnippetClient(\n            package=self.package,\n            host_port=self.host_port,\n            adb_proxy=self._adb,\n            log=self.log)\n        event_client.connect(self.uid,\n                             jsonrpc_client_base.JsonRpcCommand.CONTINUE)\n        return event_client\n", "path": "mobly/controllers/android_device_lib/snippet_client.py"}]}