1#
2# Copyright (C) 2017 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17import json
18
19from host_controller.tfc import device_info
20
21
22class RemoteOperationException(Exception):
23    """Raised when remote operation fails."""
24    pass
25
26
27class RemoteOperation(object):
28    """The operation sent to TradeFed remote manager.
29
30    Args:
31        _obj: A JSON object with at least 2 entries, "type" and "version".
32    """
33    CURRENT_PROTOCOL_VERSION = 8
34
35    def __init__(self, type, **kwargs):
36        """Initializes a remote operation.
37
38        Args:
39            type: A string, the type of the operation.
40            **kwargs: The arguments which are specific to the operation type.
41        """
42        self._obj = kwargs
43        self._obj["type"] = type
44        if "version" not in self._obj:
45            self._obj["version"] = self.CURRENT_PROTOCOL_VERSION
46
47    def ParseResponse(self, response_str):
48        """Parses the response to the operation.
49
50        Args:
51            response_str: A JSON string.
52
53        Returns:
54            A JSON object.
55
56        Raises:
57            RemoteOperationException if the response is an error.
58        """
59        response = json.loads(response_str)
60        if "error" in response:
61            raise RemoteOperationException(response["error"])
62        return response
63
64    @property
65    def type(self):
66        """Returns the type of this operation."""
67        return self._obj["type"]
68
69    def __str__(self):
70        """Converts the JSON object to string."""
71        return json.dumps(self._obj)
72
73
74def ListDevices():
75    """Creates an operation of listing devices."""
76    return RemoteOperation("LIST_DEVICES")
77
78
79def ParseListDevicesResponse(json_obj):
80    """Parses ListDevices response to a list of DeviceInfo.
81
82    Sample response:
83    {"serials": [
84        {"product": "unknown", "battery": "0", "variant": "unknown",
85         "stub": True, "state": "Available", "build": "unknown",
86         "serial": "emulator-5554", "sdk": "unknown"},
87    ]}
88
89    Args:
90        json_obj: A JSON object, the response to ListDevices.
91
92    Returns:
93        A list of DeviceInfo object.
94    """
95    dev_infos = []
96    for dev_obj in json_obj["serials"]:
97        if dev_obj["product"] == dev_obj["variant"]:
98            run_target = dev_obj["product"]
99        else:
100            run_target = dev_obj["product"] + ":" + dev_obj["variant"]
101        dev_info = device_info.DeviceInfo(
102                battery_level=dev_obj["battery"],
103                build_id=dev_obj["build"],
104                device_serial=dev_obj["serial"],
105                product=dev_obj["product"],
106                product_variant=dev_obj["variant"],
107                run_target=run_target,
108                sdk_version=dev_obj["sdk"],
109                state=dev_obj["state"],
110                stub=dev_obj["stub"])
111        dev_infos.append(dev_info)
112    return dev_infos
113
114
115def AllocateDevice(serial):
116    """Creates an operation of allocating a device.
117
118    Args:
119        serial: The serial number of the device.
120    """
121    return RemoteOperation("ALLOCATE_DEVICE", serial=serial)
122
123
124def FreeDevice(serial):
125    """Creates an operation of freeing a device.
126
127    Args:
128        serial: The serial number of the device.
129    """
130    return RemoteOperation("FREE_DEVICE", serial=serial)
131
132
133def Close():
134    """Creates an operation of stopping the remote manager."""
135    return RemoteOperation("CLOSE")
136
137
138def AddCommand(time, *command_args):
139    """Creates an operation of adding a command to the queue.
140
141    Args:
142        time: The time in ms that the command has been executing for. The value
143              is non-zero in handover situation.
144        command_args: The command to execute.
145    """
146    return RemoteOperation("ADD_COMMAND", time=time, commandArgs=command_args)
147
148
149def ExecuteCommand(serial, *command_args):
150    """Creates an operation of executing a command on a device.
151
152    Args:
153        serial: The serial number of the device.
154        command_args: The command to execute.
155    """
156    return RemoteOperation(
157            "EXEC_COMMAND", serial=serial, commandArgs=command_args)
158
159
160def GetLastCommandResult(serial):
161    """Creates an operation of getting last EXEC_COMMAND result on a device.
162
163    Sample response:
164    {"status": "INVOCATION_ERROR",
165     "invocation_error": "java.lang.NullPointerException",
166     "free_device_state": "AVAILABLE"
167    }
168
169    Args:
170        serial: The serial number of the device.
171    """
172    return RemoteOperation("GET_LAST_COMMAND_RESULT", serial=serial)
173