1 /*
2 * Copyright (C) 2025 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 <cstddef>
18 #include <cstdint>
19 #include <cstdlib>
20 #include <cstring>
21
22 #include "chre/util/system/service_helpers.h"
23
24 namespace chre::message {
25
26 namespace {
27
28 //! Legacy format is: chre.nanoapp_0x<nanoappId>.service_0x<serviceId>
29 //! All IDs are in hexadecimal
30 constexpr char kPrefix[] = "chre.nanoapp_0x";
31 constexpr size_t kPrefixLength = sizeof(kPrefix) - 1;
32 constexpr char kSeparator[] = ".service_0x";
33 constexpr size_t kSeparatorLength = sizeof(kSeparator) - 1;
34 constexpr size_t kEncodingLength = 16;
35 constexpr size_t kBase = 16;
36 constexpr size_t kServiceDescriptorLength =
37 kPrefixLength + kEncodingLength + kSeparatorLength + kEncodingLength;
38
39 //! Converts a string containing a 16-character hexadecimal encoding to a
40 //! uint64_t. We are using this instead of directly using strtoull because
41 //! some of our platforms do not support this function.
42 //! @return the converted uint64_t
convertEncodedIdToUint64(const char * str)43 uint64_t convertEncodedIdToUint64(const char *str) {
44 constexpr size_t kHalfEncodingLength = kEncodingLength / 2;
45 char buffer[kHalfEncodingLength + 1];
46 buffer[kHalfEncodingLength] = '\0';
47
48 // Convert the first half (upper 32 bits) of the encoding to a uint64_t
49 memcpy(buffer, str, kHalfEncodingLength);
50 uint64_t resultFirst = strtoul(buffer, nullptr, kBase);
51
52 // Convert the second half (lower 32 bits) of the encoding to a uint64_t
53 memcpy(buffer, str + kHalfEncodingLength, kHalfEncodingLength);
54 uint64_t resultSecond = strtoul(buffer, nullptr, kBase);
55
56 // Combine the two halves into a single uint64_t
57 return (resultFirst << 32) | resultSecond;
58 }
59
60 } // anonymous namespace
61
extractNanoappIdAndServiceId(const char * serviceDescriptor,uint64_t & nanoappId,uint64_t & serviceId)62 bool extractNanoappIdAndServiceId(const char *serviceDescriptor,
63 uint64_t &nanoappId, uint64_t &serviceId) {
64 // Reject null service descriptors
65 if (serviceDescriptor == nullptr) {
66 return false;
67 }
68
69 // Check the service descriptor length
70 if (strlen(serviceDescriptor) != kServiceDescriptorLength) {
71 return false;
72 }
73
74 // Check if the service descriptor starts with the legacy prefix
75 if (strstr(serviceDescriptor, kPrefix) != serviceDescriptor) {
76 return false;
77 }
78
79 // Check if the service descriptor contains the separator in the correct
80 // location
81 const char *separatorIndex =
82 strstr(serviceDescriptor + kPrefixLength, kSeparator);
83 if (separatorIndex == nullptr ||
84 (reinterpret_cast<uintptr_t>(separatorIndex) -
85 reinterpret_cast<uintptr_t>(serviceDescriptor)) *
86 sizeof(char) !=
87 kPrefixLength + kEncodingLength) {
88 return false;
89 }
90
91 // Convert the encoded strings for the IDs to uint64_t
92 nanoappId = convertEncodedIdToUint64(serviceDescriptor + kPrefixLength);
93 serviceId = convertEncodedIdToUint64(separatorIndex + kSeparatorLength);
94 return true;
95 }
96
97 } // namespace chre::message
98