blob: 4ae9c09213b4d646272712287a34ba65d7215d44 [file] [log] [blame]
Arthur Ishiguroa257b782021-08-04 10:40:29 -07001/*
2 * Copyright (C) 2021 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
17#include "contexthub-impl/ContextHub.h"
18
Matthew Sedam92c2bd82024-11-11 19:52:30 +000019#ifndef LOG_TAG
20#define LOG_TAG "CHRE"
21#endif
22
23#include <inttypes.h>
24#include <log/log.h>
Arthur Ishiguroa257b782021-08-04 10:40:29 -070025
Arthur Ishiguro070f47d2022-01-06 22:42:10 +000026using ::ndk::ScopedAStatus;
27
Matthew Sedam92c2bd82024-11-11 19:52:30 +000028namespace aidl::android::hardware::contexthub {
29
30namespace {
31
32constexpr uint64_t kMockVendorHubId = 0x1234567812345678;
33constexpr uint64_t kMockVendorHub2Id = 0x0EADBEEFDEADBEEF;
34
35// Mock endpoints for the default implementation.
36// These endpoints just echo back any messages sent to them.
37constexpr size_t kMockEndpointCount = 4;
38const EndpointInfo kMockEndpointInfos[kMockEndpointCount] = {
39 {
40 .id = {.hubId = kMockVendorHubId, .id = UINT64_C(0x1)},
41 .type = EndpointInfo::EndpointType::GENERIC,
42 .name = "Mock Endpoint 1",
43 .version = 1,
44 },
45 {
46 .id = {.hubId = kMockVendorHubId, .id = UINT64_C(0x2)},
47 .type = EndpointInfo::EndpointType::GENERIC,
48 .name = "Mock Endpoint 2",
49 .version = 2,
50 },
51 {
52 .id = {.hubId = kMockVendorHub2Id, .id = UINT64_C(0x1)},
53 .type = EndpointInfo::EndpointType::GENERIC,
54 .name = "Mock Endpoint 3",
55 .version = 1,
56 },
57 {
58 .id = {.hubId = kMockVendorHub2Id, .id = UINT64_C(0x2)},
59 .type = EndpointInfo::EndpointType::GENERIC,
60 .name = "Mock Endpoint 4",
61 .version = 2,
62 },
63};
64
65} // anonymous namespace
66
Arthur Ishiguro070f47d2022-01-06 22:42:10 +000067ScopedAStatus ContextHub::getContextHubs(std::vector<ContextHubInfo>* out_contextHubInfos) {
Arthur Ishiguro94e1aa22021-10-26 17:25:19 +000068 ContextHubInfo hub = {};
69 hub.name = "Mock Context Hub";
70 hub.vendor = "AOSP";
71 hub.toolchain = "n/a";
72 hub.id = kMockHubId;
73 hub.peakMips = 1;
74 hub.maxSupportedMessageLengthBytes = 4096;
75 hub.chrePlatformId = UINT64_C(0x476f6f6754000000);
76 hub.chreApiMajorVersion = 1;
77 hub.chreApiMinorVersion = 6;
Matthew Sedamadfd5572023-11-21 05:53:00 -080078 hub.supportsReliableMessages = false;
Arthur Ishiguroa257b782021-08-04 10:40:29 -070079
Arthur Ishiguro94e1aa22021-10-26 17:25:19 +000080 out_contextHubInfos->push_back(hub);
81
Matthew Sedamadfd5572023-11-21 05:53:00 -080082 return ScopedAStatus::ok();
Arthur Ishiguroa257b782021-08-04 10:40:29 -070083}
84
Arthur Ishiguro94e1aa22021-10-26 17:25:19 +000085// We don't expose any nanoapps for the default impl, therefore all nanoapp-related APIs fail.
Arthur Ishiguro070f47d2022-01-06 22:42:10 +000086ScopedAStatus ContextHub::loadNanoapp(int32_t /* in_contextHubId */,
87 const NanoappBinary& /* in_appBinary */,
88 int32_t /* in_transactionId */) {
89 return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
90}
91
92ScopedAStatus ContextHub::unloadNanoapp(int32_t /* in_contextHubId */, int64_t /* in_appId */,
93 int32_t /* in_transactionId */) {
94 return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
95}
96
97ScopedAStatus ContextHub::disableNanoapp(int32_t /* in_contextHubId */, int64_t /* in_appId */,
98 int32_t /* in_transactionId */) {
99 return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
100}
101
102ScopedAStatus ContextHub::enableNanoapp(int32_t /* in_contextHubId */, int64_t /* in_appId */,
103 int32_t /* in_transactionId */) {
104 return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
105}
106
107ScopedAStatus ContextHub::onSettingChanged(Setting /* in_setting */, bool /*in_enabled */) {
Matthew Sedamadfd5572023-11-21 05:53:00 -0800108 return ScopedAStatus::ok();
Arthur Ishiguroa257b782021-08-04 10:40:29 -0700109}
110
Arthur Ishiguro070f47d2022-01-06 22:42:10 +0000111ScopedAStatus ContextHub::queryNanoapps(int32_t in_contextHubId) {
Arthur Ishiguro94e1aa22021-10-26 17:25:19 +0000112 if (in_contextHubId == kMockHubId && mCallback != nullptr) {
113 std::vector<NanoappInfo> nanoapps;
114 mCallback->handleNanoappInfo(nanoapps);
Matthew Sedamadfd5572023-11-21 05:53:00 -0800115 return ScopedAStatus::ok();
Arthur Ishiguro94e1aa22021-10-26 17:25:19 +0000116 } else {
Arthur Ishiguro070f47d2022-01-06 22:42:10 +0000117 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
Arthur Ishiguro94e1aa22021-10-26 17:25:19 +0000118 }
Arthur Ishiguroa257b782021-08-04 10:40:29 -0700119}
120
Matthew Sedamd70f84d2023-03-06 18:34:24 +0000121ScopedAStatus ContextHub::getPreloadedNanoappIds(int32_t /* in_contextHubId */,
122 std::vector<int64_t>* out_preloadedNanoappIds) {
Arthur Ishigurofd5e65c2022-11-08 16:49:47 +0000123 if (out_preloadedNanoappIds == nullptr) {
124 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
125 }
126
127 for (uint64_t i = 0; i < 10; ++i) {
128 out_preloadedNanoappIds->push_back(i);
129 }
Matthew Sedamadfd5572023-11-21 05:53:00 -0800130 return ScopedAStatus::ok();
Arthur Ishigurofd5e65c2022-11-08 16:49:47 +0000131}
132
Anthony Stange7fba1002023-03-02 21:45:20 +0000133ScopedAStatus ContextHub::onNanSessionStateChanged(const NanSessionStateUpdate& /*in_update*/) {
Matthew Sedamadfd5572023-11-21 05:53:00 -0800134 return ScopedAStatus::ok();
Anthony Stange7344af92022-12-22 14:21:31 +0000135}
136
Arthur Ishiguro070f47d2022-01-06 22:42:10 +0000137ScopedAStatus ContextHub::registerCallback(int32_t in_contextHubId,
138 const std::shared_ptr<IContextHubCallback>& in_cb) {
Arthur Ishiguro94e1aa22021-10-26 17:25:19 +0000139 if (in_contextHubId == kMockHubId) {
140 mCallback = in_cb;
Matthew Sedamadfd5572023-11-21 05:53:00 -0800141 return ScopedAStatus::ok();
Arthur Ishiguro94e1aa22021-10-26 17:25:19 +0000142 } else {
Arthur Ishiguro070f47d2022-01-06 22:42:10 +0000143 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
Arthur Ishiguro94e1aa22021-10-26 17:25:19 +0000144 }
Arthur Ishiguroa257b782021-08-04 10:40:29 -0700145}
146
Arthur Ishiguro070f47d2022-01-06 22:42:10 +0000147ScopedAStatus ContextHub::sendMessageToHub(int32_t in_contextHubId,
148 const ContextHubMessage& /* in_message */) {
Arthur Ishiguro94e1aa22021-10-26 17:25:19 +0000149 if (in_contextHubId == kMockHubId) {
150 // Return true here to indicate that the HAL has accepted the message.
151 // Successful delivery of the message to a nanoapp should be handled at
152 // a higher level protocol.
Matthew Sedamadfd5572023-11-21 05:53:00 -0800153 return ScopedAStatus::ok();
Arthur Ishiguro94e1aa22021-10-26 17:25:19 +0000154 } else {
Arthur Ishiguro070f47d2022-01-06 22:42:10 +0000155 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
Arthur Ishiguro94e1aa22021-10-26 17:25:19 +0000156 }
Arthur Ishiguroa257b782021-08-04 10:40:29 -0700157}
158
Matthew Sedam92c2bd82024-11-11 19:52:30 +0000159ScopedAStatus ContextHub::setTestMode(bool enable) {
160 if (enable) {
161 std::unique_lock<std::mutex> lock(mEndpointMutex);
162 mEndpoints.clear();
163 mEndpointSessions.clear();
164 mEndpointCallback = nullptr;
165 }
Matthew Sedamadfd5572023-11-21 05:53:00 -0800166 return ScopedAStatus::ok();
Matthew Sedamc8ce4d52023-01-09 20:18:21 +0000167}
168
Arthur Ishiguro070f47d2022-01-06 22:42:10 +0000169ScopedAStatus ContextHub::onHostEndpointConnected(const HostEndpointInfo& in_info) {
Arthur Ishiguro065a9a52021-11-19 00:24:45 +0000170 mConnectedHostEndpoints.insert(in_info.hostEndpointId);
171
Matthew Sedamadfd5572023-11-21 05:53:00 -0800172 return ScopedAStatus::ok();
Arthur Ishiguro065a9a52021-11-19 00:24:45 +0000173}
174
Arthur Ishiguro070f47d2022-01-06 22:42:10 +0000175ScopedAStatus ContextHub::onHostEndpointDisconnected(char16_t in_hostEndpointId) {
Arthur Ishiguro065a9a52021-11-19 00:24:45 +0000176 if (mConnectedHostEndpoints.count(in_hostEndpointId) > 0) {
177 mConnectedHostEndpoints.erase(in_hostEndpointId);
Arthur Ishiguro065a9a52021-11-19 00:24:45 +0000178 }
Arthur Ishigurobb1d8bf2022-07-06 15:29:13 +0000179
Matthew Sedamadfd5572023-11-21 05:53:00 -0800180 return ScopedAStatus::ok();
Arthur Ishiguro065a9a52021-11-19 00:24:45 +0000181}
182
Matthew Sedamadfd5572023-11-21 05:53:00 -0800183ScopedAStatus ContextHub::sendMessageDeliveryStatusToHub(
184 int32_t /* in_contextHubId */,
185 const MessageDeliveryStatus& /* in_messageDeliveryStatus */) {
186 return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
187}
188
Yifei Zhang51eba2e2024-10-24 15:11:54 -0700189ScopedAStatus ContextHub::getHubs(std::vector<HubInfo>* _aidl_return) {
Matthew Sedam92c2bd82024-11-11 19:52:30 +0000190 if (_aidl_return == nullptr) {
191 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
192 }
193
Yifei Zhang51eba2e2024-10-24 15:11:54 -0700194 ContextHubInfo hub = {};
195 hub.name = "Mock Context Hub";
196 hub.vendor = "AOSP";
197 hub.toolchain = "n/a";
198 hub.id = kMockHubId;
199 hub.peakMips = 1;
200 hub.maxSupportedMessageLengthBytes = 4096;
201 hub.chrePlatformId = UINT64_C(0x476f6f6754000000);
202 hub.chreApiMajorVersion = 1;
203 hub.chreApiMinorVersion = 6;
204 hub.supportsReliableMessages = false;
205
206 HubInfo hubInfo1 = {};
207 hubInfo1.hubId = hub.chrePlatformId;
208 hubInfo1.hubDetails = HubInfo::HubDetails::make<HubInfo::HubDetails::Tag::contextHubInfo>(hub);
209
210 VendorHubInfo vendorHub = {};
211 vendorHub.name = "Mock Vendor Hub";
212 vendorHub.version = 42;
213
214 HubInfo hubInfo2 = {};
Matthew Sedam92c2bd82024-11-11 19:52:30 +0000215 hubInfo2.hubId = kMockVendorHubId;
Yifei Zhang3c265802024-11-04 15:00:05 -0800216 hubInfo2.hubDetails =
Yifei Zhang51eba2e2024-10-24 15:11:54 -0700217 HubInfo::HubDetails::make<HubInfo::HubDetails::Tag::vendorHubInfo>(vendorHub);
218
Matthew Sedam92c2bd82024-11-11 19:52:30 +0000219 VendorHubInfo vendorHub2 = {};
220 vendorHub2.name = "Mock Vendor Hub 2";
221 vendorHub2.version = 24;
222
223 HubInfo hubInfo3 = {};
224 hubInfo3.hubId = kMockVendorHub2Id;
225 hubInfo3.hubDetails =
226 HubInfo::HubDetails::make<HubInfo::HubDetails::Tag::vendorHubInfo>(vendorHub2);
227
Yifei Zhang51eba2e2024-10-24 15:11:54 -0700228 _aidl_return->push_back(hubInfo1);
229 _aidl_return->push_back(hubInfo2);
Matthew Sedam92c2bd82024-11-11 19:52:30 +0000230 _aidl_return->push_back(hubInfo3);
Yifei Zhang51eba2e2024-10-24 15:11:54 -0700231
232 return ScopedAStatus::ok();
233};
234
Matthew Sedam92c2bd82024-11-11 19:52:30 +0000235ScopedAStatus ContextHub::getEndpoints(std::vector<EndpointInfo>* _aidl_return) {
236 if (_aidl_return == nullptr) {
237 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
238 }
239
240 Service echoService;
241 echoService.format = Service::RpcFormat::CUSTOM;
242 echoService.serviceDescriptor = "ECHO";
243 echoService.majorVersion = 1;
244 echoService.minorVersion = 0;
245
246 for (const EndpointInfo& endpoint : kMockEndpointInfos) {
247 EndpointInfo endpointWithService(endpoint);
248 endpointWithService.services.push_back(echoService);
249 _aidl_return->push_back(std::move(endpointWithService));
250 }
251
252 return ScopedAStatus::ok();
Yifei Zhang51eba2e2024-10-24 15:11:54 -0700253};
254
Matthew Sedam92c2bd82024-11-11 19:52:30 +0000255ScopedAStatus ContextHub::registerEndpoint(const EndpointInfo& in_endpoint) {
256 std::unique_lock<std::mutex> lock(mEndpointMutex);
257
258 for (const EndpointInfo& endpoint : mEndpoints) {
259 if ((endpoint.id.id == in_endpoint.id.id && endpoint.id.hubId == in_endpoint.id.hubId) ||
260 endpoint.name == in_endpoint.name) {
261 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
262 }
263 }
264 mEndpoints.push_back(in_endpoint);
265 return ScopedAStatus::ok();
Yifei Zhang51eba2e2024-10-24 15:11:54 -0700266};
267
Matthew Sedam92c2bd82024-11-11 19:52:30 +0000268ScopedAStatus ContextHub::unregisterEndpoint(const EndpointInfo& in_endpoint) {
269 std::unique_lock<std::mutex> lock(mEndpointMutex);
270
271 for (auto it = mEndpoints.begin(); it != mEndpoints.end(); ++it) {
272 if (it->id.id == in_endpoint.id.id && it->id.hubId == in_endpoint.id.hubId) {
273 mEndpoints.erase(it);
274 return ScopedAStatus::ok();
275 }
276 }
277 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
Yifei Zhang51eba2e2024-10-24 15:11:54 -0700278};
279
280ScopedAStatus ContextHub::registerEndpointCallback(
Matthew Sedam92c2bd82024-11-11 19:52:30 +0000281 const std::shared_ptr<IEndpointCallback>& in_callback) {
282 std::unique_lock<std::mutex> lock(mEndpointMutex);
283
284 mEndpointCallback = in_callback;
285 return ScopedAStatus::ok();
Yifei Zhang51eba2e2024-10-24 15:11:54 -0700286};
287
Matthew Sedam92c2bd82024-11-11 19:52:30 +0000288ScopedAStatus ContextHub::requestSessionIdRange(int32_t in_size,
289 std::vector<int32_t>* _aidl_return) {
290 constexpr int32_t kMaxSize = 1024;
291 if (in_size > kMaxSize || _aidl_return == nullptr) {
292 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
293 }
294
295 {
296 std::lock_guard<std::mutex> lock(mEndpointMutex);
297 mMaxValidSessionId = in_size;
298 }
299
300 _aidl_return->push_back(0);
301 _aidl_return->push_back(in_size);
302 return ScopedAStatus::ok();
Yifei Zhang51eba2e2024-10-24 15:11:54 -0700303};
304
305ScopedAStatus ContextHub::openEndpointSession(
Matthew Sedam92c2bd82024-11-11 19:52:30 +0000306 int32_t in_sessionId, const EndpointId& in_destination, const EndpointId& in_initiator,
307 const std::optional<std::string>& in_serviceDescriptor) {
308 // We are not calling onCloseEndpointSession on failure because the remote endpoints (our
309 // mock endpoints) always accept the session.
310
311 std::shared_ptr<IEndpointCallback> callback = nullptr;
312 {
313 std::unique_lock<std::mutex> lock(mEndpointMutex);
314 if (in_sessionId > mMaxValidSessionId) {
315 ALOGE("openEndpointSession: session ID %" PRId32 " is invalid", in_sessionId);
316 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
317 }
318
319 for (const EndpointSession& session : mEndpointSessions) {
320 bool sessionAlreadyExists =
321 (session.initiator == in_destination && session.peer == in_initiator) ||
322 (session.peer == in_destination && session.initiator == in_initiator);
323 if (sessionAlreadyExists) {
324 ALOGD("openEndpointSession: session ID %" PRId32 " already exists", in_sessionId);
325 return (session.sessionId == in_sessionId &&
326 session.serviceDescriptor == in_serviceDescriptor)
327 ? ScopedAStatus::ok()
328 : ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
329 } else if (session.sessionId == in_sessionId) {
330 ALOGE("openEndpointSession: session ID %" PRId32 " is invalid: endpoint mismatch",
331 in_sessionId);
332 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
333 }
334 }
335
336 // Verify the initiator and destination are valid endpoints
337 bool initiatorIsValid = findEndpoint(in_initiator, mEndpoints.begin(), mEndpoints.end());
338 if (!initiatorIsValid) {
339 ALOGE("openEndpointSession: initiator %" PRIu64 ":%" PRIu64 " is invalid",
340 in_initiator.id, in_initiator.hubId);
341 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
342 }
343 bool destinationIsValid = findEndpoint(in_destination, &kMockEndpointInfos[0],
344 &kMockEndpointInfos[kMockEndpointCount]);
345 if (!destinationIsValid) {
346 ALOGE("openEndpointSession: destination %" PRIu64 ":%" PRIu64 " is invalid",
347 in_destination.id, in_destination.hubId);
348 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
349 }
350
351 mEndpointSessions.push_back({
352 .sessionId = in_sessionId,
353 .initiator = in_initiator,
354 .peer = in_destination,
355 .serviceDescriptor = in_serviceDescriptor,
356 });
357
358 if (mEndpointCallback != nullptr) {
359 callback = mEndpointCallback;
360 }
361 }
362
363 if (callback != nullptr) {
364 callback->onEndpointSessionOpenComplete(in_sessionId);
365 }
366 return ScopedAStatus::ok();
Yifei Zhang51eba2e2024-10-24 15:11:54 -0700367};
368
Matthew Sedam92c2bd82024-11-11 19:52:30 +0000369ScopedAStatus ContextHub::sendMessageToEndpoint(int32_t in_sessionId, const Message& in_msg) {
370 bool foundSession = false;
371 std::shared_ptr<IEndpointCallback> callback = nullptr;
372 {
373 std::unique_lock<std::mutex> lock(mEndpointMutex);
374
375 for (const EndpointSession& session : mEndpointSessions) {
376 if (session.sessionId == in_sessionId) {
377 foundSession = true;
378 break;
379 }
380 }
381
382 if (mEndpointCallback != nullptr) {
383 callback = mEndpointCallback;
384 }
385 }
386
387 if (!foundSession) {
388 ALOGE("sendMessageToEndpoint: session ID %" PRId32 " is invalid", in_sessionId);
389 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
390 }
391
392 if (callback != nullptr) {
393 if (in_msg.flags & Message::FLAG_REQUIRES_DELIVERY_STATUS) {
394 MessageDeliveryStatus msgStatus = {};
395 msgStatus.messageSequenceNumber = in_msg.sequenceNumber;
396 msgStatus.errorCode = ErrorCode::OK;
397 callback->onMessageDeliveryStatusReceived(in_sessionId, msgStatus);
398 }
399
400 // Echo the message back
401 callback->onMessageReceived(in_sessionId, in_msg);
402 }
403 return ScopedAStatus::ok();
Yifei Zhang51eba2e2024-10-24 15:11:54 -0700404};
405
406ScopedAStatus ContextHub::sendMessageDeliveryStatusToEndpoint(
407 int32_t /* in_sessionId */, const MessageDeliveryStatus& /* in_msgStatus */) {
Matthew Sedam92c2bd82024-11-11 19:52:30 +0000408 return ScopedAStatus::ok();
Yifei Zhang51eba2e2024-10-24 15:11:54 -0700409};
410
Matthew Sedam92c2bd82024-11-11 19:52:30 +0000411ScopedAStatus ContextHub::closeEndpointSession(int32_t in_sessionId, Reason /* in_reason */) {
412 std::unique_lock<std::mutex> lock(mEndpointMutex);
413
414 for (auto it = mEndpointSessions.begin(); it != mEndpointSessions.end(); ++it) {
415 if (it->sessionId == in_sessionId) {
416 mEndpointSessions.erase(it);
417 return ScopedAStatus::ok();
418 }
419 }
420 ALOGE("closeEndpointSession: session ID %" PRId32 " is invalid", in_sessionId);
421 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
Yifei Zhang51eba2e2024-10-24 15:11:54 -0700422};
423
424ScopedAStatus ContextHub::endpointSessionOpenComplete(int32_t /* in_sessionId */) {
Matthew Sedam92c2bd82024-11-11 19:52:30 +0000425 return ScopedAStatus::ok();
Yifei Zhang51eba2e2024-10-24 15:11:54 -0700426};
427
Matthew Sedamadfd5572023-11-21 05:53:00 -0800428} // namespace aidl::android::hardware::contexthub