1/*
2 * Copyright (c) 2021 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
16#include "device_info_stub.h"
17
18#include <chrono>
19#include <thread>
20
21#include "beget_ext.h"
22#include "idevice_info.h"
23#include "ipc_skeleton.h"
24#include "accesstoken_kit.h"
25#include "parcel.h"
26#include "string_ex.h"
27#include "if_system_ability_manager.h"
28#include "iservice_registry.h"
29#include "system_ability_definition.h"
30#include "param_comm.h"
31#include "parameter.h"
32#include "sysparam_errno.h"
33#include "init_utils.h"
34#include "deviceinfoservice_ipc_interface_code.h"
35
36namespace OHOS {
37using namespace Security;
38using namespace Security::AccessToken;
39
40namespace device_info {
41REGISTER_SYSTEM_ABILITY_BY_ID(DeviceInfoService, SYSPARAM_DEVICE_SERVICE_ID, true)
42
43static std::mutex g_lock;
44static struct timespec g_lastTime;
45#ifndef STARTUP_INIT_TEST
46static const int DEVICE_INFO_EXIT_TIMEOUT_S = 60;
47#else
48static const int DEVICE_INFO_EXIT_TIMEOUT_S = 3;
49#endif
50static const int DEVICE_INFO_EXIT_WAITTIMES = 12;
51
52
53static int UnloadDeviceInfoSa(void)
54{
55    {
56        std::unique_lock<std::mutex> lock(g_lock);
57        struct timespec currTimer = {0};
58        (void)clock_gettime(CLOCK_MONOTONIC, &currTimer);
59        if (IntervalTime(&g_lastTime, &currTimer) < DEVICE_INFO_EXIT_TIMEOUT_S) {
60            return 0;
61        }
62    }
63    DINFO_LOGI("DeviceInfoService::UnloadDeviceInfoSa");
64    auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
65    DINFO_CHECK(sam != nullptr, return 0, "GetSystemAbilityManager return null");
66
67    int32_t ret = sam->UnloadSystemAbility(SYSPARAM_DEVICE_SERVICE_ID);
68    DINFO_CHECK(ret == ERR_OK, return 0, "UnLoadSystemAbility deviceinfo sa failed");
69    return 1;
70}
71
72int32_t DeviceInfoStub::OnRemoteRequest(uint32_t code,
73    MessageParcel &data, MessageParcel &reply, MessageOption &option)
74{
75    std::u16string myDescriptor = IDeviceInfo::GetDescriptor();
76    std::u16string remoteDescriptor = data.ReadInterfaceToken();
77    DINFO_CHECK(myDescriptor == remoteDescriptor, return ERR_FAIL, "Invalid remoteDescriptor");
78
79    {
80        std::unique_lock<std::mutex> lock(g_lock);
81        (void)clock_gettime(CLOCK_MONOTONIC, &g_lastTime);
82    }
83
84    int ret = ERR_FAIL;
85    switch (code) {
86        case static_cast<uint32_t> (DeviceInfoInterfaceCode::COMMAND_GET_UDID): {
87            if (!CheckPermission(data, "ohos.permission.sec.ACCESS_UDID")) {
88                return SYSPARAM_PERMISSION_DENIED;
89            }
90            char localDeviceInfo[UDID_LEN] = {0};
91            ret = GetDevUdid_(localDeviceInfo, UDID_LEN);
92            DINFO_CHECK(ret == 0, break, "Failed to get dev udid");
93            reply.WriteString16(Str8ToStr16(localDeviceInfo));
94            break;
95        }
96        case static_cast<uint32_t> (DeviceInfoInterfaceCode::COMMAND_GET_SERIAL_ID): {
97            if (!CheckPermission(data, "ohos.permission.sec.ACCESS_UDID")) {
98                return SYSPARAM_PERMISSION_DENIED;
99            }
100            const char *serialNumber = GetSerial_();
101            DINFO_CHECK(serialNumber != nullptr, break, "Failed to get serialNumber");
102            reply.WriteString16(Str8ToStr16(serialNumber));
103            ret = ERR_NONE;
104            break;
105        }
106        default: {
107            return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
108        }
109    }
110    return ret;
111}
112
113bool DeviceInfoStub::CheckPermission(MessageParcel &data, const std::string &permission)
114{
115    AccessTokenID callerToken = IPCSkeleton::GetCallingTokenID();
116    int32_t result = TypePermissionState::PERMISSION_GRANTED;
117    int32_t tokenType = AccessTokenKit::GetTokenTypeFlag(callerToken);
118    if (tokenType == TOKEN_INVALID) {
119        DINFO_LOGE("AccessToken type:%d, permission:%d denied!", tokenType, callerToken);
120        return false;
121    } else {
122        result = AccessTokenKit::VerifyAccessToken(callerToken, permission);
123    }
124    if (result == TypePermissionState::PERMISSION_DENIED) {
125        DINFO_LOGE("permission:%s denied!", permission.c_str());
126        return false;
127    }
128    return true;
129}
130
131int32_t DeviceInfoService::GetUdid(std::string& result)
132{
133    return 0;
134}
135int32_t DeviceInfoService::GetSerialID(std::string& result)
136{
137    return 0;
138}
139
140void DeviceInfoService::OnStart(void)
141{
142    int level = GetIntParameter(INIT_DEBUG_LEVEL, (int)INIT_INFO);
143    SetInitLogLevel((InitLogLevel)level);
144    DINFO_LOGI("DeviceInfoService OnStart");
145    bool res = Publish(this);
146    if (!res) {
147        DINFO_LOGE("DeviceInfoService Publish failed");
148    }
149    threadStarted_ = true;
150    std::thread([this] {this->ThreadForUnloadSa();}).detach();
151    return;
152}
153
154void DeviceInfoService::OnStop(void)
155{
156    threadStarted_ = false;
157    DINFO_LOGI("DeviceInfoService OnStop");
158}
159
160int DeviceInfoService::Dump(int fd, const std::vector<std::u16string>& args)
161{
162    (void)args;
163    DINFO_LOGI("DeviceInfoService Dump");
164    DINFO_CHECK(fd >= 0, return -1, "Invalid fd for dump %d", fd);
165    return dprintf(fd, "%s\n", "No information to dump for this service");
166}
167
168void DeviceInfoService::ThreadForUnloadSa(void)
169{
170    while (1) {
171        std::this_thread::sleep_for(std::chrono::seconds(DEVICE_INFO_EXIT_TIMEOUT_S / DEVICE_INFO_EXIT_WAITTIMES));
172        if (!threadStarted_) {
173            break;
174        }
175        if (UnloadDeviceInfoSa() == 1) {
176            break;
177        }
178    }
179}
180} // namespace device_info
181} // namespace OHOS
182