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