1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include "oaid_service.h"
16#include <mutex>
17#include <openssl/rand.h>
18#include <singleton.h>
19#include <string>
20#include <unistd.h>
21#include "oaid_common.h"
22#include "oaid_file_operator.h"
23#include "system_ability.h"
24#include "system_ability_definition.h"
25#include "oaid_service_stub.h"
26#include "oaid_service_define.h"
27#include "oaid_observer_manager.h"
28
29using namespace std::chrono;
30
31namespace OHOS {
32namespace Cloud {
33const std::string OAID_VIRTUAL_STR = "-****-****-****-************";
34namespace {
35char HexToChar(uint8_t hex)
36{
37    static const uint8_t MAX_SINGLE_DIGIT = 9;  // 9 is the largest single digit
38    return (hex > MAX_SINGLE_DIGIT) ? (hex + 0x57) : (hex + 0x30);
39}
40
41/**
42 * Get v4 uuid.
43 *
44 * @return std::string, uuid.
45 */
46std::string GetUUID()
47{
48    static const int8_t UUID_LENGTH = 16;    // The UUID is 128 bits, that is 16 bytes.
49    static const int8_t VERSION_INDEX = 6;   // Obtain the seventh byte of the randomly generated UUID, that is uuid[6].
50    static const int8_t CHAR_LOW_WIDTH = 4;  // Lower 4 bits of the char type
51    static const int8_t N_INDEX = 8;         // Reset the ninth byte of the UUID, that is UUID[8].
52    unsigned char uuid[UUID_LENGTH] = {0};
53    int re = RAND_bytes(uuid, sizeof(uuid));
54    if (re == 0) {
55        return "";
56    }
57
58    /**
59     * xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
60     * M is uuid version: 4
61     * N is 8,9,a,b
62     */
63    uuid[VERSION_INDEX] = (uuid[VERSION_INDEX] & 0x0F) | 0x40;
64    int minN = 0x8;
65    int maxN = 0xb;
66    unsigned char randNumber[1] = {minN};
67    RAND_bytes(randNumber, sizeof(randNumber));
68    unsigned char num = static_cast<unsigned char>(randNumber[0] % (maxN - minN + 1) + minN);
69    uuid[N_INDEX] = (uuid[N_INDEX] & 0x0F) | (num << CHAR_LOW_WIDTH);
70
71    static const size_t LINE_INDEX_MAX = 10;  // until i=10
72    static const size_t LINE_INDEX_MIN = 4;   // Add a hyphen (-) every two bytes starting from i=4.
73    static const size_t EVEN_FACTOR = 2;  // the even factor is assigned to 2, and all even numbers are divisible by 2.
74    std::string formatUuid = "";
75    for (size_t i = 0; i < sizeof(uuid); i++) {
76        unsigned char value = uuid[i];
77        if (i >= LINE_INDEX_MIN && i <= LINE_INDEX_MAX && i % EVEN_FACTOR == 0) {
78            formatUuid += "-";
79        }
80        formatUuid += HexToChar(value >> CHAR_LOW_WIDTH);
81        unsigned char highValue = value & 0xF0;
82        if (highValue == 0) {
83            formatUuid += HexToChar(value);
84        } else {
85            formatUuid += HexToChar(value % (value & highValue));
86        }
87    }
88    return formatUuid;
89}
90}  // namespace
91
92REGISTER_SYSTEM_ABILITY_BY_ID(OAIDService, OAID_SYSTME_ID, true);
93std::mutex OAIDService::mutex_;
94sptr<OAIDService> OAIDService::instance_;
95
96OAIDService::OAIDService(int32_t systemAbilityId, bool runOnCreate)
97    : SystemAbility(systemAbilityId, runOnCreate), state_(ServiceRunningState::STATE_NOT_START)
98{
99    OAID_HILOGI(OAID_MODULE_SERVICE, "Start.");
100}
101
102OAIDService::OAIDService() : state_(ServiceRunningState::STATE_NOT_START)
103{}
104
105OAIDService::~OAIDService(){};
106
107sptr<OAIDService> OAIDService::GetInstance()
108{
109    if (instance_ == nullptr) {
110        std::lock_guard<std::mutex> autoLock(mutex_);
111        if (instance_ == nullptr) {
112            OAID_HILOGI(OAID_MODULE_SERVICE, "Instance success.");
113            instance_ = new OAIDService;
114        }
115    }
116    return instance_;
117}
118
119void OAIDService::OnStart()
120{
121    if (state_ == ServiceRunningState::STATE_RUNNING) {
122        OAID_HILOGE(OAID_MODULE_SERVICE, " OAIDService is already running.");
123        return;
124    }
125
126    if (Init() != ERR_OK) {
127        OAID_HILOGE(OAID_MODULE_SERVICE, "Init failed, Try again 10s later.");
128        return;
129    }
130    AddSystemAbilityListener(OAID_SYSTME_ID);
131
132    OAID_HILOGI(OAID_MODULE_SERVICE, "Start OAID service success.");
133    return;
134}
135
136int32_t OAIDService::Init()
137{
138    bool ret = Publish(this);
139    if (!ret) {
140        OAID_HILOGE(OAID_MODULE_SERVICE, "OAID service init failed.");
141        return ERR_SYSYTEM_ERROR;
142    }
143
144    OAID_HILOGI(OAID_MODULE_SERVICE, "OAID service init Success.");
145    state_ = ServiceRunningState::STATE_RUNNING;
146    return ERR_OK;
147}
148
149void OAIDService::OnStop()
150{
151    if (state_ != ServiceRunningState::STATE_RUNNING) {
152        return;
153    }
154
155    state_ = ServiceRunningState::STATE_NOT_START;
156    OAID_HILOGI(OAID_MODULE_SERVICE, "Stop success.");
157}
158
159bool OAIDService::InitOaidKvStore()
160{
161    DistributedKv::DistributedKvDataManager manager;
162    DistributedKv::Options options;
163
164    DistributedKv::AppId appId;
165    appId.appId = OAID_DATA_BASE_APP_ID;
166
167    options.createIfMissing = true;
168    options.encrypt = true;
169    options.autoSync = false;
170    options.kvStoreType = DistributedKv::KvStoreType::SINGLE_VERSION;
171    options.area = DistributedKv::EL1;
172    options.baseDir = OAID_DATA_BASE_DIR + appId.appId;
173    options.securityLevel = DistributedKv::SecurityLevel::S1;
174
175    DistributedKv::StoreId storeId;
176    storeId.storeId = OAID_DATA_BASE_STORE_ID;
177    DistributedKv::Status status = DistributedKv::Status::SUCCESS;
178
179    if (oaidKvStore_ == nullptr) {
180        uint32_t retries = 0;
181        do {
182            OAID_HILOGI(OAID_MODULE_SERVICE, "InitOaidKvStore: retries=%{public}u!", retries);
183            status = manager.GetSingleKvStore(options, appId, storeId, oaidKvStore_);
184            if (status == DistributedKv::Status::STORE_NOT_FOUND) {
185                OAID_HILOGE(OAID_MODULE_SERVICE, "InitOaidKvStore: STORE_NOT_FOUND!");
186            }
187
188            if ((status == DistributedKv::Status::SUCCESS) || (status == DistributedKv::Status::STORE_NOT_FOUND)) {
189                break;
190            } else {
191                OAID_HILOGE(OAID_MODULE_SERVICE, "Kvstore Connect failed! Retrying.");
192                retries++;
193                usleep(KVSTORE_CONNECT_RETRY_DELAY_TIME);
194            }
195        } while (retries <= KVSTORE_CONNECT_RETRY_COUNT);
196    }
197
198    if (oaidKvStore_ == nullptr) {
199        if (status == DistributedKv::Status::STORE_NOT_FOUND) {
200            OAID_HILOGI(OAID_MODULE_SERVICE, "First Boot: Create OaidKvStore");
201            options.createIfMissing = true;
202            // [create and] open and initialize kvstore instance.
203            status = manager.GetSingleKvStore(options, appId, storeId, oaidKvStore_);
204            if (status == DistributedKv::Status::SUCCESS) {
205                OAID_HILOGE(OAID_MODULE_SERVICE, "Create OaidKvStore success!");
206            } else {
207                OAID_HILOGE(OAID_MODULE_SERVICE, "Create OaidKvStore Failed!");
208            }
209        }
210    }
211
212    if (oaidKvStore_ == nullptr) {
213        OAID_HILOGE(OAID_MODULE_SERVICE, "InitOaidKvStore: Failed!");
214        return false;
215    }
216
217    return true;
218}
219
220void OAIDService::OnAddSystemAbility(int32_t systemAbilityId, const std::string &deviceId)
221{
222    OAID_HILOGI(OAID_MODULE_SERVICE, "OnAddSystemAbility OAIDService");
223    bool result = false;
224    switch (systemAbilityId) {
225        case OAID_SYSTME_ID:
226            OAID_HILOGI(OAID_MODULE_SERVICE, "OnAddSystemAbility kv data service start");
227            result = InitOaidKvStore();
228            OAID_HILOGI(OAID_MODULE_SERVICE, "OnAddSystemAbility InitOaidKvStore is %{public}d", result);
229            break;
230        default:
231            OAID_HILOGI(OAID_MODULE_SERVICE, "OnAddSystemAbility unhandled sysabilityId:%{public}d", systemAbilityId);
232            break;
233    }
234}
235
236bool OAIDService::CheckKvStore()
237{
238    if (oaidKvStore_ != nullptr) {
239        return true;
240    }
241
242    bool result = InitOaidKvStore();
243    OAID_HILOGI(OAID_MODULE_SERVICE, "InitOaidKvStore: %{public}s", result == true ? "success" : "failed");
244    return result;
245}
246
247bool OAIDService::ReadValueFromKvStore(const std::string &kvStoreKey, std::string &kvStoreValue)
248{
249    std::lock_guard<std::mutex> lock(mutex_);
250
251    if (!CheckKvStore()) {
252        OAID_HILOGE(OAID_MODULE_SERVICE, "ReadValueFromKvStore:oaidKvStore_ is nullptr");
253        return false;
254    }
255
256    DistributedKv::Key key(kvStoreKey);
257    DistributedKv::Value value;
258    DistributedKv::Status status = oaidKvStore_->Get(key, value);
259    if (status == DistributedKv::Status::SUCCESS) {
260        OAID_HILOGI(OAID_MODULE_SERVICE, "%{public}d get value from kvStore", status);
261    } else {
262        OAID_HILOGE(OAID_MODULE_SERVICE, "%{public}d get value from kvStore failed", status);
263        return false;
264    }
265    kvStoreValue = value.ToString();
266
267    return true;
268}
269
270bool OAIDService::WriteValueToKvStore(const std::string &kvStoreKey, const std::string &kvStoreValue)
271{
272    std::lock_guard<std::mutex> lock(mutex_);
273
274    if (!CheckKvStore()) {
275        OAID_HILOGE(OAID_MODULE_SERVICE, "WriteValueToKvStore:oaidKvStore_ is nullptr");
276        return false;
277    }
278
279    DistributedKv::Key key(kvStoreKey);
280    DistributedKv::Value value(kvStoreValue);
281    DistributedKv::Status status = oaidKvStore_->Put(key, value);
282    if (status == DistributedKv::Status::SUCCESS) {
283        OAID_HILOGI(OAID_MODULE_SERVICE, "%{public}d updated to kvStore", status);
284    } else {
285        OAID_HILOGE(OAID_MODULE_SERVICE, "%{public}d update to kvStore failed", status);
286        return false;
287    }
288
289    return true;
290}
291
292std::string OAIDService::GainOAID()
293{
294    OAID_HILOGI(OAID_MODULE_SERVICE, "Gain OAID Begin.");
295    std::string oaidKvStoreStr = OAID_ALLZERO_STR;
296    updateMutex_.lock();
297    if (OAIDFileOperator::IsFileExsit(OAID_UPDATE)) {
298        OAIDFileOperator::OpenAndReadFile(OAID_UPDATE, oaidKvStoreStr);
299        OAIDFileOperator::ClearFile(OAID_UPDATE);
300        std::string oaid;
301        cJSON *root = cJSON_Parse(oaidKvStoreStr.c_str());
302        if (root != nullptr && !cJSON_IsInvalid(root)) {
303            cJSON *oaidObj = cJSON_GetObjectItem(root, "oaid");
304            if (cJSON_IsString(oaidObj)) {
305                oaid = oaidObj->valuestring;
306            }
307        }
308        cJSON_Delete(root);
309        oaid_ = oaid;
310        bool update = WriteValueToKvStore(OAID_KVSTORE_KEY, oaid_);
311        OAID_HILOGI(OAID_MODULE_SERVICE, "update oaid %{public}s", update ? "success" : "failed");
312        updateMutex_.unlock();
313        return oaid_;
314    }
315    updateMutex_.unlock();
316    bool result = ReadValueFromKvStore(OAID_KVSTORE_KEY, oaidKvStoreStr);
317    OAID_HILOGI(OAID_MODULE_SERVICE, "ReadValueFromKvStore %{public}s", result ? "success" : "failed");
318
319    if (oaidKvStoreStr != OAID_ALLZERO_STR && !oaidKvStoreStr.empty()) {
320        if (oaid_.empty()) {
321            oaid_ = oaidKvStoreStr;
322            OAID_HILOGI(OAID_MODULE_SERVICE, "The Oaid in the memory is empty, it get oaid from kvdb successfully");
323        }
324        return oaid_;
325    } else {
326        if (oaid_.empty()) {
327            oaid_ = GetUUID();
328            OAID_HILOGI(OAID_MODULE_SERVICE, "The oaid has been regenerated.");
329        }
330    }
331    result = WriteValueToKvStore(OAID_KVSTORE_KEY, oaid_);
332    OAID_HILOGI(OAID_MODULE_SERVICE, "WriteValueToKvStore %{public}s", result == true ? "success" : "failed");
333    OAID_HILOGI(OAID_MODULE_SERVICE, "Gain OAID Finish.");
334    return oaid_;
335}
336
337std::string OAIDService::GetOAID()
338{
339    OAID_HILOGI(OAID_MODULE_SERVICE, "Begin.");
340
341    std::string oaid = GainOAID();
342    std::string target = oaid.substr(0, 9).append(OAID_VIRTUAL_STR);
343    OAID_HILOGI(OAID_MODULE_SERVICE, "getOaid success oaid is: %{public}s", target.c_str());
344    OAID_HILOGI(OAID_MODULE_SERVICE, "End.");
345    return oaid;
346}
347
348int32_t OAIDService::ResetOAID()
349{
350    OAID_HILOGI(OAID_MODULE_SERVICE, "ResetOAID.");
351    std::string resetOaid = GetUUID();
352    oaid_ = resetOaid;
353    bool result = WriteValueToKvStore(OAID_KVSTORE_KEY, resetOaid);
354    OAID_HILOGI(OAID_MODULE_SERVICE, "ResetOAID WriteValueToKvStore %{public}s", result == true ? "success" : "failed");
355    std::string target = resetOaid.substr(0, 9).append(OAID_VIRTUAL_STR);
356    OAID_HILOGI(OAID_MODULE_SERVICE, "resetOaid success oaid is: %{public}s", target.c_str());
357    // 调用单例对象的oberser->OnUpdateOaid
358    DelayedSingleton<OaidObserverManager>::GetInstance()->OnUpdateOaid(resetOaid);
359    return ERR_OK;
360}
361}  // namespace Cloud
362}  // namespace OHOS
363