1#!/usr/bin/env python3
2#
3# Copyright (C) 2009 Google Inc.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may not
6# use this file except in compliance with the License. You may obtain a copy of
7# 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, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations under
15# the License.
16
17from acts.controllers.sl4a_lib.rpc_connection import RpcConnection
18import json
19import os
20import socket
21import threading
22
23HOST = os.environ.get('AP_HOST', None)
24PORT = os.environ.get('AP_PORT', 9999)
25
26
27class SL4NException(Exception):
28    pass
29
30
31class SL4NAPIError(SL4NException):
32    """Raised when remote API reports an error."""
33
34
35class SL4NProtocolError(SL4NException):
36    """Raised when there is an error exchanging data with the device server."""
37    NO_RESPONSE_FROM_HANDSHAKE = "No response from handshake."
38    NO_RESPONSE_FROM_SERVER = "No response from server."
39    MISMATCHED_API_ID = "Mismatched API id."
40
41
42def IDCounter():
43    i = 0
44    while True:
45        yield i
46        i += 1
47
48
49class NativeAndroid(RpcConnection):
50    COUNTER = IDCounter()
51
52    def _rpc(self, method, *args):
53        with self._lock:
54            apiid = next(self._counter)
55        data = {'id': apiid, 'method': method, 'params': args}
56        request = json.dumps(data)
57        self.client.write(request.encode("utf8") + b'\n')
58        self.client.flush()
59        response = self.client.readline()
60        if not response:
61            raise SL4NProtocolError(SL4NProtocolError.NO_RESPONSE_FROM_SERVER)
62        #TODO: (tturney) fix the C side from sending \x00 char over the socket.
63        result = json.loads(
64            str(response, encoding="utf8").rstrip().replace("\x00", ""))
65        if result['error']:
66            raise SL4NAPIError(result['error'])
67        if result['id'] != apiid:
68            raise SL4NProtocolError(SL4NProtocolError.MISMATCHED_API_ID)
69        return result['result']
70