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