| syntax = "proto2"; |
| |
| package offworld; |
| |
| // Offworld is a protocol implemented by the Android Emulator to enable |
| // controlling features of the emulator from the guest OS. |
| // |
| // The protocol is implemented on top of qemu pipe service, and the underlying |
| // encoding of the pipe is a stream of protobufs, with the length of each |
| // message encoded as a little-endian uint32 immediately before it: |
| // |
| // <uint32 length> <length bytes of binary-serialized protobuf> |
| // |
| // Upon receiving each message, the protobuf is deserialized from its binary |
| // form and dispatched. |
| // |
| // On connect, the guest is expected to first send a ConnectHandshake. For |
| // notational purposes, assume that the protobuf has been serialized with the |
| // above encoding. The guest then waits for the host to respond with a |
| // ConnectHandshakeResponse message. |
| // |
| // guest->host: ConnectHandshake { version: 1 } |
| // host->guest: ConnectHandshakeResponse { result: OK } |
| // |
| // The ConnectHandshakeResponse will either contain Result.OK or an error. |
| // If an error value is returned the host will not handle any further guest |
| // messages. |
| // |
| // After the connection is established, the guest may send Request messages, and |
| // will receive synchronous replies with a Response message. The response may |
| // include a pending_async_id, in which case there may be additional messages |
| // with an AsyncResponse payload corresponding to that async_id. |
| // |
| // For synchronous messages, the flow is: |
| // |
| // guest->host: Request { snapshot { create_checkpoint { |
| // snapshot_name: "Test" } } } |
| // host->guest: Response { result: OK, snapshot { create_checkpoint { ... } } } |
| // |
| // |
| // For asynchronous messages, a synchronous response is immediately returned |
| // with a pending_async_id, followed by one or more AsyncResponse messages with |
| // a matching async_id. Multiple async messages may be generated as a stream; |
| // to determine when the stream is complete check AsyncResponse.complete. |
| // |
| // guest->host: Request { automation { replay { event: "..." } } } |
| // host->guest: Response { result: OK, pending_async_id: 1 } } |
| // ... |
| // host->guest: Response { async { async_id: 1, complete: true, automation { |
| // replay_complete { } } } } |
| |
| message ConnectHandshake { |
| optional uint32 version = 1; |
| } |
| |
| message ConnectHandshakeResponse { |
| enum Result { |
| RESULT_NO_ERROR = 0; |
| RESULT_ERROR_UNKNOWN = 1; |
| RESULT_ERROR_VERSION_MISMATCH = 2; |
| } |
| |
| optional Result result = 1; |
| } |
| |
| // |
| // Requests |
| // |
| |
| message Request { |
| oneof module { |
| SnapshotRequest snapshot = 1; |
| AutomationRequest automation = 2; |
| VideoInjectionRequest video_injection = 3; |
| SensorMockRequest sensor_mock = 4; |
| } |
| } |
| |
| message SnapshotRequest { |
| message CreateCheckpoint { |
| optional string snapshot_name = 1; |
| } |
| message GotoCheckpoint { |
| enum ShareMode { |
| UNKNOWN = 0; |
| UNCHANGED = 1; |
| WRITABLE = 2; |
| READ_ONLY = 3; |
| }; |
| optional string snapshot_name = 1; |
| optional bytes metadata = 2; |
| optional ShareMode share_mode = 3; |
| } |
| message ForkReadOnlyInstances { |
| optional int32 num_instances = 1; |
| } |
| message DoneInstance { |
| optional bytes metadata = 1; |
| } |
| |
| oneof function { |
| CreateCheckpoint create_checkpoint = 1; |
| GotoCheckpoint goto_checkpoint = 2; |
| ForkReadOnlyInstances fork_read_only_instances = 3; |
| DoneInstance done_instance = 4; |
| } |
| } |
| |
| message AutomationRequest { |
| message ReplayInitialState { |
| optional string state = 1; |
| } |
| |
| message Replay { |
| optional string event = 1; |
| } |
| |
| message Listen {} |
| message StopListening {} |
| |
| oneof function { |
| ReplayInitialState replay_initial_state = 1; |
| Replay replay = 2; |
| Listen listen = 3; |
| StopListening stop_listening = 4; |
| } |
| } |
| |
| message VideoInjectionRequest { |
| optional uint32 sequence_id = 1; |
| |
| message Load { |
| optional bytes video_data = 1; |
| optional DatasetInfo dataset_info = 2; |
| } |
| |
| message Play { |
| optional float offset_in_seconds = 1; |
| optional bool looping = 2; |
| optional float speed_factor = 3; |
| } |
| |
| message Pause { |
| optional float offset_in_seconds = 1; |
| } |
| |
| message Stop { |
| optional float delay_in_seconds = 1; |
| } |
| |
| message DisplayDefaultFrame {} |
| |
| oneof function { |
| Load load = 50; |
| Play play = 51; |
| Pause pause = 52; |
| Stop stop = 53; |
| DisplayDefaultFrame display_default_frame = 54; |
| } |
| } |
| |
| message DatasetInfo { |
| optional DataStreamInfo location = 1; |
| optional DataStreamInfo accelerometer = 2; |
| optional DataStreamInfo gyroscope = 3; |
| optional DataStreamInfo magnetic_field = 4; |
| optional DataStreamInfo video_metadata = 5; |
| } |
| |
| message DataStreamInfo { |
| optional uint32 stream_index = 1; |
| oneof packet_info { |
| SensorDataPacketInfo sensor_packet = 2; |
| LocationDataPacketInfo location_packet = 3; |
| VideoMetadataPacketInfo video_metadata_packet = 4; |
| } |
| |
| } |
| |
| message SensorDataPacketInfo { |
| optional FieldInfo timestamp = 1; |
| repeated FieldInfo value = 2; |
| } |
| |
| |
| message LocationDataPacketInfo { |
| optional FieldInfo timestamp = 1; |
| optional FieldInfo latitude = 2; |
| optional FieldInfo longitude = 3; |
| optional FieldInfo meters_elevation = 4; |
| optional FieldInfo knots_speed = 5; |
| optional FieldInfo degrees_heading = 6; |
| optional FieldInfo num_satellites = 7; |
| } |
| |
| message VideoMetadataPacketInfo { |
| optional FieldInfo timestamp = 1; |
| optional FieldInfo frame_number = 2; |
| } |
| |
| message FieldInfo { |
| enum Type { |
| UNDEF = 0; |
| INT_32 = 1; |
| INT_64 = 2; |
| FLOAT = 3; |
| DOUBLE = 4; |
| } |
| |
| optional uint32 offset = 1; |
| optional Type type = 2; |
| } |
| |
| message LocationData { |
| optional double latitude = 1; |
| optional double longitude = 2; |
| optional double meters_elevation = 3; |
| optional double knots_speed = 4; |
| optional double degrees_heading = 5; |
| optional uint32 num_satellites = 6; |
| } |
| |
| message SensorMockRequest { |
| optional uint64 timestamp_us = 1; |
| |
| |
| message LocationMock { |
| optional LocationData location_data = 1; |
| } |
| |
| oneof function { |
| LocationMock mock_location = 50; |
| } |
| } |
| |
| |
| // |
| // Responses |
| // |
| |
| message Response { |
| enum Result { |
| RESULT_NO_ERROR = 0; |
| RESULT_ERROR_UNKNOWN = 1; |
| RESULT_ERROR_ACCESS_DENIED = 2; |
| RESULT_ERROR_NOT_IMPLEMENTED = 3; |
| } |
| |
| optional Result result = 1; |
| optional string error_string = 2; |
| |
| // Indicates that this is an async messages and there will be additional |
| // messages with a matching module.async.async_id. |
| optional uint32 pending_async_id = 3; |
| |
| oneof module { |
| // Sync. |
| SnapshotResponse snapshot = 100; |
| AutomationResponse automation = 101; |
| VideoInjectionResponse video_injection = 102; |
| |
| // Async. |
| // Async response. |
| AsyncResponse async = 201; |
| } |
| } |
| |
| message AsyncResponse { |
| // An async id corresponding to the async_id from the original synchronous |
| // response. |
| optional uint32 async_id = 1; |
| // True if there will be no further messages with this async_id. |
| optional bool complete = 2; |
| |
| oneof module { |
| AutomationAsyncResponse automation = 100; |
| VideoInjectionAsyncResponse video_injection = 101; |
| } |
| } |
| |
| message SnapshotResponse { |
| message CreateCheckpoint { |
| optional bytes metadata = 1; |
| } |
| message GotoCheckpoint {} |
| message ForkReadOnlyInstances { |
| optional int32 instance_id = 1; |
| optional bytes metadata = 2; |
| } |
| message DoneInstance {} |
| |
| oneof function { |
| CreateCheckpoint create_checkpoint = 1; |
| GotoCheckpoint goto_checkpoint = 2; |
| ForkReadOnlyInstances fork_read_only_instances = 3; |
| DoneInstance done_instance = 4; |
| } |
| } |
| |
| message AutomationResponse { |
| message Listen { |
| // An text-encoded protobuf containing the initial state of the system. |
| optional string initial_state = 1; |
| } |
| |
| oneof function { |
| Listen listen = 1; |
| } |
| } |
| |
| message VideoInjectionResponse { |
| optional uint32 sequence_id = 1; |
| } |
| |
| message AutomationAsyncResponse { |
| message ReplayComplete {} |
| |
| message EventGenerated { |
| // A text-encoded protobuf containing a replayable event. |
| optional string event = 1; |
| } |
| |
| oneof function { |
| ReplayComplete replay_complete = 1; |
| EventGenerated event_generated = 2; |
| } |
| } |
| |
| message VideoInjectionAsyncResponse { |
| optional uint32 sequence_id = 1; |
| } |