1 /*
2 * Copyright (c) 2020 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 "bundle_daemon_client.h"
17
18 #include <cstring>
19 #include <string>
20
21 #include "adapter.h"
22 #include "bundle_daemon_interface.h"
23 #include "bundle_log.h"
24 #include "iproxy_client.h"
25 #include "ohos_errno.h"
26 #include "samgr_lite.h"
27 #include "utils.h"
28 #include "rpc_errno.h"
29
30 namespace OHOS {
31 namespace {
32 constexpr unsigned SLEEP_TIME = 200000;
33 }
34 #ifdef __LINUX__
Notify(IOwner owner,int code,IpcIo * reply)35 int BundleDaemonClient::Notify(IOwner owner, int code, IpcIo *reply)
36 {
37 if ((reply == nullptr) || (owner == nullptr)) {
38 HILOG_ERROR(HILOG_MODULE_APP, "BundleManager Notify ipc is nullptr");
39 return OHOS_FAILURE;
40 }
41 BundleDaemonClient *client = reinterpret_cast<BundleDaemonClient *>(owner);
42 if (client == nullptr) {
43 return EC_INVALID;
44 }
45 ReadInt32(reply, &(client->result_));
46 int value;
47 sem_getvalue(&client->sem_, &value);
48 if (value <= 0) {
49 sem_post(&client->sem_);
50 }
51 return EC_SUCCESS;
52 }
53 #else
BundleDaemonCallback(uint32_t code,IpcIo * data,IpcIo * reply,MessageOption option)54 int32_t BundleDaemonClient::BundleDaemonCallback(uint32_t code, IpcIo* data, IpcIo* reply, MessageOption option)
55 {
56 BundleDaemonClient *client = reinterpret_cast<BundleDaemonClient *>(option.args);
57 if (client == nullptr) {
58 return EC_INVALID;
59 }
60
61 ReadInt32(data, &(client->result_));
62 int value;
63 sem_getvalue(&client->sem_, &value);
64 if (value <= 0) {
65 sem_post(&client->sem_);
66 }
67 return EC_SUCCESS;
68 }
69 #endif
70
DeathCallback(void * arg)71 void BundleDaemonClient::DeathCallback(void* arg)
72 {
73 pthread_t pid;
74
75 if (pthread_create(&pid, nullptr, RegisterDeathCallback, arg) != 0) {
76 BundleDaemonClient *client = reinterpret_cast<BundleDaemonClient *>(arg);
77 if (client != nullptr) {
78 client->result_ = EC_CANCELED;
79 int value;
80 sem_getvalue(&client->sem_, &value);
81 if (value <= 0) {
82 sem_post(&client->sem_);
83 }
84 }
85 }
86 }
87
~BundleDaemonClient()88 BundleDaemonClient::~BundleDaemonClient()
89 {
90 if (initialized_) {
91 RemoveDeathRecipient(bdsSvcIdentity_, cbid_);
92 bdsClient_->Release(reinterpret_cast<IUnknown *>(bdsClient_));
93 bdsClient_ = nullptr;
94 sem_destroy(&sem_);
95 }
96 }
97
Initialize()98 bool BundleDaemonClient::Initialize()
99 {
100 if (initialized_) {
101 PRINTI("BundleDaemonClient", "already initialized");
102 return true;
103 }
104 if (sem_init(&sem_, 0, 0) != 0) {
105 PRINTE("BundleDaemonClient", "sem_init fail");
106 return false;
107 }
108
109 while (bdsClient_ == nullptr) {
110 IUnknown *iUnknown = SAMGR_GetInstance()->GetDefaultFeatureApi(BDS_SERVICE);
111 if (iUnknown == nullptr) {
112 usleep(SLEEP_TIME);
113 continue;
114 }
115
116 (void)iUnknown->QueryInterface(iUnknown, CLIENT_PROXY_VER, (void **)&bdsClient_);
117 }
118
119 // register bundle_daemon callback
120 #ifndef __LINUX__
121 objectStub_.func = BundleDaemonClient::BundleDaemonCallback;
122 objectStub_.args = this;
123 objectStub_.isRemote = false;
124
125 svcIdentity_.handle = IPC_INVALID_HANDLE;
126 svcIdentity_.token = SERVICE_TYPE_ANONYMOUS;
127 svcIdentity_.cookie = (uintptr_t)&objectStub_;
128 #endif
129 if (RegisterCallback() != ERR_NONE) {
130 PRINTE("BundleDaemonClient", "register bundle_daemon callback fail");
131 sem_destroy(&sem_);
132 return false;
133 }
134
135 // register bundle_daemon death callback
136 bdsSvcIdentity_ = SAMGR_GetRemoteIdentity(BDS_SERVICE, nullptr);
137 if (::AddDeathRecipient(bdsSvcIdentity_, &BundleDaemonClient::DeathCallback, this, &cbid_) != ERR_NONE) {
138 PRINTW("BundleDaemonClient", "register bundle_daemon death callback fail");
139 // Keep running if register death callback fail
140 }
141
142 initialized_ = true;
143 return true;
144 }
145
RegisterDeathCallback(void * arg)146 void *BundleDaemonClient::RegisterDeathCallback(void *arg)
147 {
148 BundleDaemonClient *client = reinterpret_cast<BundleDaemonClient *>(arg);
149 if (client == nullptr) {
150 return nullptr;
151 }
152 client->result_ = EC_CANCELED;
153 int value;
154 sem_getvalue(&client->sem_, &value);
155 if (value <= 0) {
156 sem_post(&client->sem_);
157 }
158 // Register invoke callback and death callback again
159 Lock<Mutex> lock(client->mutex_);
160 client->RegisterCallback();
161 RemoveDeathRecipient(client->bdsSvcIdentity_, client->cbid_);
162
163 client->cbid_ = INVALID_INDEX;
164 client->bdsSvcIdentity_.handle = INVALID_INDEX;
165 client->bdsSvcIdentity_.token = INVALID_INDEX;
166
167 client->bdsSvcIdentity_ = SAMGR_GetRemoteIdentity(BDS_SERVICE, nullptr);
168 if (::AddDeathRecipient(client->bdsSvcIdentity_, &BundleDaemonClient::DeathCallback,
169 client, &client->cbid_) != ERR_NONE) {
170 PRINTW("BundleDeamonClient", "register death callback fail");
171 // Keep running if register death callback fail
172 }
173
174 return nullptr;
175 }
176
WaitResultSync(int32_t result)177 int32_t BundleDaemonClient::WaitResultSync(int32_t result)
178 {
179 if (result == EC_SUCCESS) {
180 sem_wait(&sem_);
181 result = result_;
182 result_ = EC_FAILURE;
183 }
184 return result;
185 }
186
RegisterCallback()187 int32_t BundleDaemonClient::RegisterCallback()
188 {
189 IpcIo request;
190 char data[MAX_IO_SIZE];
191 IpcIoInit(&request, data, MAX_IO_SIZE, 1);
192 bool writeRemote = WriteRemoteObject(&request, &svcIdentity_);
193 if (!writeRemote) {
194 return EC_FAILURE;
195 }
196 #ifdef __LINUX__
197 while (bdsClient_->Invoke(bdsClient_, REGISTER_CALLBACK, &request, this, Notify) != EC_SUCCESS) {
198 #else
199 while (bdsClient_->Invoke(bdsClient_, REGISTER_CALLBACK, &request, nullptr, nullptr) != EC_SUCCESS) {
200 #endif
201 PRINTI("BundleDaemonClient", "register bundle_daemon callback fail");
202 usleep(SLEEP_TIME);
203 }
204 return WaitResultSync(EC_SUCCESS);
205 }
206
207 int32_t BundleDaemonClient::CallClientInvoke(int32_t funcId, const char *firstPath, const char *secondPath,
208 bool keepData)
209 {
210 IpcIo request;
211 char data[MAX_IO_SIZE];
212 IpcIoInit(&request, data, MAX_IO_SIZE, 0);
213 std::string innerStr = firstPath;
214 innerStr += secondPath;
215 WriteString(&request, innerStr.c_str());
216
217 WriteUint16(&request, strlen(firstPath));
218
219 if (funcId == REMOVE_INSTALL_DIRECTORY) {
220 WriteBool(&request, keepData);
221 }
222
223 Lock<Mutex> lock(mutex_);
224 #ifdef __LINUX__
225 return WaitResultSync(bdsClient_->Invoke(bdsClient_, funcId, &request, this, Notify));
226 #else
227 return WaitResultSync(bdsClient_->Invoke(bdsClient_, funcId, &request, nullptr, nullptr));
228 #endif
229 }
230
231 int32_t BundleDaemonClient::ExtractHap(const char *hapFile, const char *codePath)
232 {
233 if (!initialized_) {
234 return EC_NOINIT;
235 }
236 if (hapFile == nullptr || codePath == nullptr) {
237 PRINTE("BundleDaemonClient", "invalid params: hapFile or codePath is nullptr");
238 return EC_INVALID;
239 }
240
241 return CallClientInvoke(EXTRACT_HAP, hapFile, codePath);
242 }
243
244 int32_t BundleDaemonClient::RenameFile(const char *oldFile, const char *newFile)
245 {
246 if (!initialized_) {
247 return EC_NOINIT;
248 }
249 if (oldFile == nullptr || newFile == nullptr) {
250 PRINTE("BundleDaemonClient", "invalid params: oldDir or newDir is nullptr");
251 return EC_INVALID;
252 }
253
254 return CallClientInvoke(RENAME_DIR, oldFile, newFile);
255 }
256
257 int32_t BundleDaemonClient::CreatePermissionDir()
258 {
259 if (!initialized_) {
260 return EC_NOINIT;
261 }
262 Lock<Mutex> lock(mutex_);
263 #ifdef __LINUX__
264 return WaitResultSync(bdsClient_->Invoke(bdsClient_, CREATE_PERMISSION_DIR, nullptr, this, Notify));
265 #else
266 return WaitResultSync(bdsClient_->Invoke(bdsClient_, CREATE_PERMISSION_DIR, nullptr, nullptr, nullptr));
267 #endif
268 }
269
270 int32_t BundleDaemonClient::CreateDataDirectory(const char *dataPath, int32_t uid, int32_t gid, bool isChown)
271 {
272 if (!initialized_) {
273 return EC_NOINIT;
274 }
275 if (dataPath == nullptr) {
276 PRINTE("BundleDaemonClient", "invalid params: bundleName is nullptr");
277 return EC_INVALID;
278 }
279 IpcIo request;
280 char data[MAX_IO_SIZE];
281 IpcIoInit(&request, data, MAX_IO_SIZE, 0);
282 WriteString(&request, dataPath);
283 WriteInt32(&request, uid);
284 WriteInt32(&request, gid);
285 WriteBool(&request, isChown);
286 PRINTI("BundleDaemonClient", "uid is %{public}d, isChown is %{public}d", uid, isChown);
287 Lock<Mutex> lock(mutex_);
288 #ifdef __LINUX__
289 return WaitResultSync(bdsClient_->Invoke(bdsClient_, CREATE_DATA_DIRECTORY, &request, this, Notify));
290 #else
291 return WaitResultSync(bdsClient_->Invoke(bdsClient_, CREATE_DATA_DIRECTORY, &request, nullptr, nullptr));
292 #endif
293 }
294
295 int32_t BundleDaemonClient::StoreContentToFile(const char *file, const void *buffer, uint32_t size)
296 {
297 if (!initialized_) {
298 return EC_NOINIT;
299 }
300 if (file == nullptr || buffer == nullptr || size == 0) {
301 PRINTE("BundleDaemonClient", "invalid params");
302 return EC_INVALID;
303 }
304 IpcIo request;
305 char data[MAX_IO_SIZE];
306
307 IpcIoInit(&request, data, MAX_IO_SIZE, 0);
308
309 WriteString(&request, file);
310 WriteString(&request, static_cast<const char *>(buffer));
311 Lock<Mutex> lock(mutex_);
312 #ifdef __LINUX__
313 return WaitResultSync(bdsClient_->Invoke(bdsClient_, STORE_CONTENT_TO_FILE, &request, this, Notify));
314 #else
315 return WaitResultSync(bdsClient_->Invoke(bdsClient_, STORE_CONTENT_TO_FILE, &request, nullptr, nullptr));
316 #endif
317 }
318
319 int32_t BundleDaemonClient::MoveFile(const char *oldFile, const char *newFile)
320 {
321 if (!initialized_) {
322 return EC_NOINIT;
323 }
324 if ((oldFile == nullptr) || (newFile == nullptr)) {
325 PRINTE("BundleDaemonClient", "invalid params");
326 return EC_INVALID;
327 }
328 IpcIo request;
329 char data[MAX_IO_SIZE];
330 IpcIoInit(&request, data, MAX_IO_SIZE, 0);
331 WriteString(&request, oldFile);
332 WriteString(&request, newFile);
333
334 Lock<Mutex> lock(mutex_);
335 #ifdef __LINUX__
336 return WaitResultSync(bdsClient_->Invoke(bdsClient_, MOVE_FILE, &request, this, Notify));
337 #else
338 return WaitResultSync(bdsClient_->Invoke(bdsClient_, MOVE_FILE, &request, nullptr, nullptr));
339 #endif
340 }
341
342 int32_t BundleDaemonClient::RemoveFile(const char *file)
343 {
344 if (!initialized_) {
345 return EC_NOINIT;
346 }
347 if (file == nullptr) {
348 PRINTE("BundleDaemonClient", "invalid params");
349 return EC_INVALID;
350 }
351 IpcIo request;
352 char data[MAX_IO_SIZE];
353 IpcIoInit(&request, data, MAX_IO_SIZE, 0);
354 WriteString(&request, file);
355
356 Lock<Mutex> lock(mutex_);
357 #ifdef __LINUX__
358 return WaitResultSync(bdsClient_->Invoke(bdsClient_, REMOVE_FILE, &request, this, Notify));
359 #else
360 return WaitResultSync(bdsClient_->Invoke(bdsClient_, REMOVE_FILE, &request, nullptr, nullptr));
361 #endif
362 }
363
364 int32_t BundleDaemonClient::RemoveInstallDirectory(const char *codePath, const char *dataPath, bool keepData)
365 {
366 if (!initialized_) {
367 return EC_NOINIT;
368 }
369 if (codePath == nullptr || dataPath == nullptr) {
370 PRINTE("BundleDaemonClient", "invalid params: bundleName is nullptr");
371 return EC_INVALID;
372 }
373
374 return CallClientInvoke(REMOVE_INSTALL_DIRECTORY, codePath, dataPath, keepData);
375 }
376 } // OHOS
377