autotest: Use abstract ChameleonConnection instead ServerProxy

We should rely on ChameleonConnection as it handles chameleon reboot with
a automatic reconnection.
- Change the use of chameleon proxy to ChameleonConnection in
audio_board. The ChameleonConnection will handle the socket error and
try to reconnect, which should help to alleviate the issue that
sometimes DUT loses connection to Chameleon and causes the test to fail.
- Throw ChameleonConnectionError instead of socket.error if the RPC call
still fails after reconnection. This will make the test stop with Error
status instead of Fail caused by unhandled error.

BUG=b:146034535
TEST=Run audio tests and verify they still pass

Change-Id: I07fea8099b77747dad7dfec23256807230d8beab
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/autotest/+/1961849
Reviewed-by: Yu-Hsuan Hsu <yuhsuan@chromium.org>
Commit-Queue: En-Shuo Hsu <enshuo@chromium.org>
Tested-by: En-Shuo Hsu <enshuo@chromium.org>
diff --git a/client/cros/chameleon/audio_board.py b/client/cros/chameleon/audio_board.py
index dca9b5c..66ae2bf 100644
--- a/client/cros/chameleon/audio_board.py
+++ b/client/cros/chameleon/audio_board.py
@@ -117,7 +117,7 @@
 
         """
         self.bus_index = bus_index
-        self._chameleond_proxy = chameleon_connection.chameleond_proxy
+        self._chameleond_proxy = chameleon_connection
         self._connected_endpoints = set()
 
     def _get_endpoint_name(self, port_id):
@@ -228,7 +228,7 @@
             this audio board.
 
         """
-        self._chameleond_proxy = chameleon_connection.chameleond_proxy
+        self._chameleond_proxy = chameleon_connection
         if not self._chameleond_proxy.AudioBoardHasJackPlugger():
             raise AudioJackPluggerException(
                     'There is no jack plugger on audio board. '
@@ -259,7 +259,7 @@
         @param chameleon_connection: A ChameleonConnection object.
 
         """
-        self._chameleond_proxy = chameleon_connection.chameleond_proxy
+        self._chameleond_proxy = chameleon_connection
 
     def reset(self):
         """Resets the bluetooth module."""
diff --git a/client/cros/chameleon/chameleon.py b/client/cros/chameleon/chameleon.py
index 3c4bc04..898cc56 100644
--- a/client/cros/chameleon/chameleon.py
+++ b/client/cros/chameleon/chameleon.py
@@ -139,7 +139,7 @@
         self._proxy_generator = proxy_generator or self._create_server_proxy
 
         self._ready_test_name = ready_test_name
-        self.chameleond_proxy = None
+        self._chameleond_proxy = None
 
 
     def _create_server_proxy(self):
@@ -168,7 +168,7 @@
 
     def _reconnect(self):
         """Reconnect to chameleond."""
-        self.chameleond_proxy = self._proxy_generator()
+        self._chameleond_proxy = self._proxy_generator()
 
 
     def __call_server(self, name, *args, **kwargs):
@@ -181,15 +181,22 @@
 
         @return: the result returned by the remote method.
 
+        @raise ChameleonConnectionError if the call failed after a reconnection.
+
         """
         try:
-            return getattr(self.chameleond_proxy, name)(*args, **kwargs)
+            return getattr(self._chameleond_proxy, name)(*args, **kwargs)
         except (AttributeError, socket.error):
             # Reconnect and invoke the method again.
             logging.info('Reconnecting chameleond proxy: %s', name)
             self._reconnect()
-            return getattr(self.chameleond_proxy, name)(*args, **kwargs)
-
+            try:
+                return getattr(self._chameleond_proxy, name)(*args, **kwargs)
+            except (socket.error) as e:
+                raise ChameleonConnectionError(
+                        ("The RPC call %s still failed with %s"
+                         " after a reconnection.") % (name, e))
+        return None
 
     def __getattr__(self, name):
         """Get the callable _Method object.
@@ -608,12 +615,12 @@
         @param edid: An Edid object or NO_EDID.
         """
         if edid is edid_lib.NO_EDID:
-          self.chameleond_proxy.ApplyEdid(self.port_id, self._EDID_ID_DISABLE)
+            self.chameleond_proxy.ApplyEdid(self.port_id, self._EDID_ID_DISABLE)
         else:
-          edid_binary = xmlrpclib.Binary(edid.data)
-          edid_id = self.chameleond_proxy.CreateEdid(edid_binary)
-          self.chameleond_proxy.ApplyEdid(self.port_id, edid_id)
-          self.chameleond_proxy.DestroyEdid(edid_id)
+            edid_binary = xmlrpclib.Binary(edid.data)
+            edid_id = self.chameleond_proxy.CreateEdid(edid_binary)
+            self.chameleond_proxy.ApplyEdid(self.port_id, edid_id)
+            self.chameleond_proxy.DestroyEdid(edid_id)
 
     def set_edid_from_file(self, filename, check_video_input=True):
         """Sets EDID from a file.