Minor fixes for jsonrpc client. (#718)

* Use `abc` instead.
* Fix a warning in a unit test.
diff --git a/mobly/controllers/android_device_lib/jsonrpc_client_base.py b/mobly/controllers/android_device_lib/jsonrpc_client_base.py
index d1509a7..352aa65 100644
--- a/mobly/controllers/android_device_lib/jsonrpc_client_base.py
+++ b/mobly/controllers/android_device_lib/jsonrpc_client_base.py
@@ -39,8 +39,6 @@
   }
 """
 
-from builtins import str
-
 # When the Python library `socket.create_connection` call is made, it indirectly
 # calls `import encodings.idna` through the `socket.getaddrinfo` method.
 # However, this chain of function calls is apparently not thread-safe in
@@ -53,6 +51,7 @@
   # encoding, so ignore import failures based on that.
   pass
 
+import abc
 import json
 import socket
 import sys
@@ -108,7 +107,7 @@
   CONTINUE = 'continue'
 
 
-class JsonRpcClientBase(object):
+class JsonRpcClientBase(abc.ABC):
   """Base class for jsonrpc clients that connect to remote servers.
 
   Connects to a remote device running a jsonrpc-compatible app. Before opening
@@ -160,14 +159,12 @@
     Raises:
       AppStartError: When the app was not able to be started.
     """
-    raise NotImplementedError()
 
   def stop_app(self):
     """Kills any running instance of the app.
 
     Must be implemented by subclasses.
     """
-    raise NotImplementedError()
 
   def restore_app_connection(self, port=None):
     """Reconnects to the app after device USB was disconnected.
@@ -188,7 +185,6 @@
       AppRestoreConnectionError: When the app was not able to be
       reconnected.
     """
-    raise NotImplementedError()
 
   def _start_event_client(self):
     """Starts a separate JsonRpc client to the same session for propagating
@@ -201,7 +197,6 @@
       A JsonRpc Client object that connects to the same session as the
       one on which this function is called.
     """
-    raise NotImplementedError()
 
   # Rest of the client methods.
 
diff --git a/mobly/controllers/android_device_lib/services/base_service.py b/mobly/controllers/android_device_lib/services/base_service.py
index a284581..4739797 100644
--- a/mobly/controllers/android_device_lib/services/base_service.py
+++ b/mobly/controllers/android_device_lib/services/base_service.py
@@ -53,18 +53,15 @@
   @property
   def is_alive(self):
     """True if the service is active; False otherwise."""
-    pass
 
   def start(self):
     """Starts the service."""
-    pass
 
   def stop(self):
     """Stops the service and cleans up all resources.
 
     This method should handle any error and not throw.
     """
-    pass
 
   def pause(self):
     """Pauses a service temporarily.
diff --git a/tests/mobly/controllers/android_device_lib/snippet_client_test.py b/tests/mobly/controllers/android_device_lib/snippet_client_test.py
index 4cfb603..7b209a0 100755
--- a/tests/mobly/controllers/android_device_lib/snippet_client_test.py
+++ b/tests/mobly/controllers/android_device_lib/snippet_client_test.py
@@ -172,7 +172,10 @@
               'SnippetClient.disconnect')
   def test_snippet_stop_app_raises(self, mock_disconnect,
                                    mock_create_connection):
-    mock_disconnect.side_effect = Exception('ha')
+    # Explicitly making the second side_effect noop to avoid uncaught exception
+    # when `__del__` is called after the test is done, which triggers
+    # `disconnect`.
+    mock_disconnect.side_effect = [Exception('ha'), None]
     adb_proxy = mock.MagicMock()
     adb_proxy.shell.return_value = b'OK (0 tests)'
     client = self._make_client(adb_proxy)