1 /*
2  * Copyright (c) 2021-2024 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 "data_ability_impl.h"
17 
18 #include "abs_shared_result_set.h"
19 #include "accesstoken_kit.h"
20 #include "data_ability_operation.h"
21 #include "data_ability_predicates.h"
22 #include "hilog_tag_wrapper.h"
23 #include "ipc_skeleton.h"
24 #include "values_bucket.h"
25 
26 namespace OHOS {
27 namespace AppExecFwk {
28 namespace {
29 const std::string READ = "r";
30 const std::string WRITE = "w";
31 }
32 using AbilityManagerClient = OHOS::AAFwk::AbilityManagerClient;
33 using OHOS::Security::AccessToken::AccessTokenKit;
HandleAbilityTransaction(const Want & want,const AAFwk::LifeCycleStateInfo & targetState,sptr<AAFwk::SessionInfo> sessionInfo)34 void DataAbilityImpl::HandleAbilityTransaction(const Want &want, const AAFwk::LifeCycleStateInfo &targetState,
35     sptr<AAFwk::SessionInfo> sessionInfo)
36 {
37     TAG_LOGI(AAFwkTag::DATA_ABILITY,
38         "sourceState:%{public}d; targetState:%{public}d; isNewWant:%{public}d", lifecycleState_,
39         targetState.state, targetState.isNewWant);
40     if ((lifecycleState_ == targetState.state) && !targetState.isNewWant) {
41         TAG_LOGE(AAFwkTag::DATA_ABILITY, "lifeCycleState equals");
42         return;
43     }
44 
45     switch (targetState.state) {
46         case AAFwk::ABILITY_STATE_ACTIVE: {
47             if (lifecycleState_ == AAFwk::ABILITY_STATE_INITIAL) {
48                 SetUriString(targetState.caller.deviceId + "/" + targetState.caller.bundleName + "/" +
49                              targetState.caller.abilityName);
50                 Start(want);
51             } else {
52                 return;
53             }
54             break;
55         }
56         default: {
57             TAG_LOGE(AAFwkTag::DATA_ABILITY, "state error");
58             return;
59         }
60     }
61 
62     AbilityManagerClient::GetInstance()->AbilityTransitionDone(token_, targetState.state, GetRestoreData());
63 }
64 
65 /**
66  * @brief Obtains the MIME types of files supported.
67  *
68  * @param uri Indicates the path of the files to obtain.
69  * @param mimeTypeFilter Indicates the MIME types of the files to obtain. This parameter cannot be null.
70  *
71  * @return Returns the matched MIME types. If there is no match, null is returned.
72  */
GetFileTypes(const Uri & uri,const std::string & mimeTypeFilter)73 std::vector<std::string> DataAbilityImpl::GetFileTypes(const Uri &uri, const std::string &mimeTypeFilter)
74 {
75     std::vector<std::string> types;
76     if (ability_ == nullptr) {
77         TAG_LOGE(AAFwkTag::DATA_ABILITY, "null ability_");
78         return types;
79     }
80 
81     types = ability_->GetFileTypes(uri, mimeTypeFilter);
82     return types;
83 }
84 
85 /**
86  * @brief Opens a file in a specified remote path.
87  *
88  * @param uri Indicates the path of the file to open.
89  * @param mode Indicates the file open mode, which can be "r" for read-only access, "w" for write-only access
90  * (erasing whatever data is currently in the file), "wt" for write access that truncates any existing file,
91  * "wa" for write-only access to append to any existing data, "rw" for read and write access on any existing data,
92  *  or "rwt" for read and write access that truncates any existing file.
93  *
94  * @return Returns the file descriptor.
95  */
OpenFile(const Uri & uri,const std::string & mode)96 int DataAbilityImpl::OpenFile(const Uri &uri, const std::string &mode)
97 {
98     int fd = -1;
99     if (ability_ == nullptr) {
100         TAG_LOGE(AAFwkTag::DATA_ABILITY, "null ability_");
101         return fd;
102     }
103 
104     if (!CheckOpenFilePermission(mode)) {
105         return fd;
106     }
107 
108     fd = ability_->OpenFile(uri, mode);
109     return fd;
110 }
111 
112 /**
113  * @brief This is like openFile, open a file that need to be able to return sub-sections of files,often assets
114  * inside of their .hap.
115  *
116  * @param uri Indicates the path of the file to open.
117  * @param mode Indicates the file open mode, which can be "r" for read-only access, "w" for write-only access
118  * (erasing whatever data is currently in the file), "wt" for write access that truncates any existing file,
119  * "wa" for write-only access to append to any existing data, "rw" for read and write access on any existing
120  * data, or "rwt" for read and write access that truncates any existing file.
121  *
122  * @return Returns the RawFileDescriptor object containing file descriptor.
123  */
OpenRawFile(const Uri & uri,const std::string & mode)124 int DataAbilityImpl::OpenRawFile(const Uri &uri, const std::string &mode)
125 {
126     int fd = -1;
127     if (ability_ == nullptr) {
128         TAG_LOGE(AAFwkTag::DATA_ABILITY, "null ability_");
129         return fd;
130     }
131 
132     if (!CheckOpenFilePermission(mode)) {
133         return fd;
134     }
135 
136     fd = ability_->OpenRawFile(uri, mode);
137     return fd;
138 }
139 
140 /**
141  * @brief Inserts a single data record into the database.
142  *
143  * @param uri Indicates the path of the data to operate.
144  * @param value  Indicates the data record to insert. If this parameter is null, a blank row will be inserted.
145  *
146  * @return Returns the index of the inserted data record.
147  */
Insert(const Uri & uri,const NativeRdb::ValuesBucket & value)148 int DataAbilityImpl::Insert(const Uri &uri, const NativeRdb::ValuesBucket &value)
149 {
150     int index = -1;
151     if (ability_ == nullptr) {
152         TAG_LOGE(AAFwkTag::DATA_ABILITY, "null ability_");
153         return index;
154     }
155 
156     if (!CheckReadAndWritePermission(WRITE)) {
157         TAG_LOGW(AAFwkTag::DATA_ABILITY, "no write permission");
158         return index;
159     }
160 
161     index = ability_->Insert(uri, value);
162     return index;
163 }
164 
165 /**
166  * @brief Updates data records in the database.
167  *
168  * @param uri Indicates the path of data to update.
169  * @param value Indicates the data to update. This parameter can be null.
170  * @param predicates Indicates filter criteria. You should define the processing logic when this parameter is null.
171  *
172  * @return Returns the number of data records updated.
173  */
Update(const Uri & uri,const NativeRdb::ValuesBucket & value,const NativeRdb::DataAbilityPredicates & predicates)174 int DataAbilityImpl::Update(
175     const Uri &uri, const NativeRdb::ValuesBucket &value, const NativeRdb::DataAbilityPredicates &predicates)
176 {
177     int index = -1;
178     if (ability_ == nullptr) {
179         TAG_LOGE(AAFwkTag::DATA_ABILITY, "null ability_");
180         return index;
181     }
182 
183     if (!CheckReadAndWritePermission(WRITE)) {
184         TAG_LOGW(AAFwkTag::DATA_ABILITY, "no write permission");
185         return index;
186     }
187 
188     index = ability_->Update(uri, value, predicates);
189     return index;
190 }
191 
192 /**
193  * @brief Deletes one or more data records from the database.
194  *
195  * @param uri Indicates the path of the data to operate.
196  * @param predicates Indicates filter criteria. You should define the processing logic when this parameter is null.
197  *
198  * @return Returns the number of data records deleted.
199  */
Delete(const Uri & uri,const NativeRdb::DataAbilityPredicates & predicates)200 int DataAbilityImpl::Delete(const Uri &uri, const NativeRdb::DataAbilityPredicates &predicates)
201 {
202     int index = -1;
203     if (ability_ == nullptr) {
204         TAG_LOGE(AAFwkTag::DATA_ABILITY, "null ability_");
205         return index;
206     }
207 
208     if (!CheckReadAndWritePermission(WRITE)) {
209         TAG_LOGW(AAFwkTag::DATA_ABILITY, "no write permission");
210         return index;
211     }
212 
213     index = ability_->Delete(uri, predicates);
214     return index;
215 }
216 
217 /**
218  * @brief Deletes one or more data records from the database.
219  *
220  * @param uri Indicates the path of data to query.
221  * @param columns Indicates the columns to query. If this parameter is null, all columns are queried.
222  * @param predicates Indicates filter criteria. You should define the processing logic when this parameter is null.
223  *
224  * @return Returns the query result.
225  */
Query(const Uri & uri,std::vector<std::string> & columns,const NativeRdb::DataAbilityPredicates & predicates)226 std::shared_ptr<NativeRdb::AbsSharedResultSet> DataAbilityImpl::Query(
227     const Uri &uri, std::vector<std::string> &columns, const NativeRdb::DataAbilityPredicates &predicates)
228 {
229     if (ability_ == nullptr) {
230         TAG_LOGE(AAFwkTag::DATA_ABILITY, "null ability_");
231         return nullptr;
232     }
233 
234     if (!CheckReadAndWritePermission(READ)) {
235         TAG_LOGW(AAFwkTag::DATA_ABILITY, "no read permission");
236         return nullptr;
237     }
238 
239     return ability_->Query(uri, columns, predicates);
240 }
241 
Call(const Uri & uri,const std::string & method,const std::string & arg,const AppExecFwk::PacMap & pacMap)242 std::shared_ptr<AppExecFwk::PacMap> DataAbilityImpl::Call(
243     const Uri &uri, const std::string &method, const std::string &arg, const AppExecFwk::PacMap &pacMap)
244 {
245     if (ability_ == nullptr) {
246         TAG_LOGE(AAFwkTag::DATA_ABILITY, "null ability_");
247         return nullptr;
248     }
249 
250     return ability_->Call(uri, method, arg, pacMap);
251 }
252 
253 /**
254  * @brief Obtains the MIME type matching the data specified by the URI of the Data ability. This method should be
255  * implemented by a Data ability. Data abilities supports general data types, including text, HTML, and JPEG.
256  *
257  * @param uri Indicates the URI of the data.
258  *
259  * @return Returns the MIME type that matches the data specified by uri.
260  */
GetType(const Uri & uri)261 std::string DataAbilityImpl::GetType(const Uri &uri)
262 {
263     std::string type;
264     if (ability_ == nullptr) {
265         TAG_LOGE(AAFwkTag::DATA_ABILITY, "null ability_");
266         return type;
267     }
268     type = ability_->GetType(uri);
269     return type;
270 }
271 
272 /**
273  * @brief Reloads data in the database.
274  *
275  * @param uri Indicates the position where the data is to reload. This parameter is mandatory.
276  * @param extras Indicates the PacMap object containing the additional parameters to be passed in this call. This
277  * parameter can be null. If a custom Sequenceable object is put in the PacMap object and will be transferred across
278  * processes, you must call BasePacMap.setClassLoader(ClassLoader) to set a class loader for the custom object.
279  *
280  * @return Returns true if the data is successfully reloaded; returns false otherwise.
281  */
Reload(const Uri & uri,const PacMap & extras)282 bool DataAbilityImpl::Reload(const Uri &uri, const PacMap &extras)
283 {
284     bool ret = false;
285     if (ability_ == nullptr) {
286         TAG_LOGE(AAFwkTag::DATA_ABILITY, "null ability_");
287         return ret;
288     }
289     ret = ability_->Reload(uri, extras);
290     return ret;
291 }
292 
293 /**
294  * @brief Inserts multiple data records into the database.
295  *
296  * @param uri Indicates the path of the data to operate.
297  * @param values Indicates the data records to insert.
298  *
299  * @return Returns the number of data records inserted.
300  */
BatchInsert(const Uri & uri,const std::vector<NativeRdb::ValuesBucket> & values)301 int DataAbilityImpl::BatchInsert(const Uri &uri, const std::vector<NativeRdb::ValuesBucket> &values)
302 {
303     int ret = -1;
304     if (ability_ == nullptr) {
305         TAG_LOGE(AAFwkTag::DATA_ABILITY, "null ability_");
306         return ret;
307     }
308 
309     if (!CheckReadAndWritePermission(WRITE)) {
310         TAG_LOGW(AAFwkTag::DATA_ABILITY, "no write permission");
311         return ret;
312     }
313 
314     ret = ability_->BatchInsert(uri, values);
315     return ret;
316 }
317 /**
318  * @brief Converts the given uri that refer to the Data ability into a normalized URI. A normalized URI can be used
319  * across devices, persisted, backed up, and restored. It can refer to the same item in the Data ability even if the
320  * context has changed. If you implement URI normalization for a Data ability, you must also implement
321  * denormalizeUri(ohos.utils.net.Uri) to enable URI denormalization. After this feature is enabled, URIs passed to any
322  * method that is called on the Data ability must require normalization verification and denormalization. The default
323  * implementation of this method returns null, indicating that this Data ability does not support URI normalization.
324  *
325  * @param uri Indicates the Uri object to normalize.
326  *
327  * @return Returns the normalized Uri object if the Data ability supports URI normalization; returns null otherwise.
328  */
NormalizeUri(const Uri & uri)329 Uri DataAbilityImpl::NormalizeUri(const Uri &uri)
330 {
331     Uri urivalue("");
332     if (ability_ == nullptr) {
333         TAG_LOGE(AAFwkTag::DATA_ABILITY, "null ability_");
334         return urivalue;
335     }
336 
337     if (!CheckReadAndWritePermission(READ)) {
338         TAG_LOGW(AAFwkTag::DATA_ABILITY, "no read permission");
339         return urivalue;
340     }
341 
342     urivalue = ability_->NormalizeUri(uri);
343     return urivalue;
344 }
345 
346 /**
347  * @brief Converts the given uri that refer to the Data ability into a normalized URI. A normalized URI can be used
348  * across devices, persisted, backed up, and restored. It can refer to the same item in the Data ability even if the
349  * context has changed. If you implement URI normalization for a Data ability, you must also implement
350  * denormalizeUri(ohos.utils.net.Uri) to enable URI denormalization. After this feature is enabled, URIs passed to any
351  * method that is called on the Data ability must require normalization verification and denormalization. The default
352  * implementation of this method returns null, indicating that this Data ability does not support URI normalization.
353  *
354  * @param uri Indicates the Uri object to normalize.
355  *
356  * @return Returns the normalized Uri object if the Data ability supports URI normalization; returns null otherwise.
357  */
DenormalizeUri(const Uri & uri)358 Uri DataAbilityImpl::DenormalizeUri(const Uri &uri)
359 {
360     Uri urivalue("");
361     if (ability_ == nullptr) {
362         TAG_LOGE(AAFwkTag::DATA_ABILITY, "null ability_");
363         return urivalue;
364     }
365 
366     if (!CheckReadAndWritePermission(READ)) {
367         TAG_LOGE(AAFwkTag::DATA_ABILITY, "no read permission");
368         return urivalue;
369     }
370 
371     urivalue = ability_->DenormalizeUri(uri);
372     return urivalue;
373 }
374 
ExecuteBatch(const std::vector<std::shared_ptr<DataAbilityOperation>> & operations)375 std::vector<std::shared_ptr<DataAbilityResult>> DataAbilityImpl::ExecuteBatch(
376     const std::vector<std::shared_ptr<DataAbilityOperation>> &operations)
377 {
378     TAG_LOGI(AAFwkTag::DATA_ABILITY, "start");
379     std::vector<std::shared_ptr<DataAbilityResult>> results;
380     if (ability_ == nullptr) {
381         TAG_LOGE(AAFwkTag::DATA_ABILITY, "null ability_");
382         results.clear();
383         return results;
384     }
385 
386     if (!CheckExecuteBatchPermission(operations)) {
387         results.clear();
388         return results;
389     }
390 
391     results = ability_->ExecuteBatch(operations);
392     TAG_LOGI(AAFwkTag::DATA_ABILITY, "end, results size:%{public}zu", results.size());
393     return results;
394 }
395 
CheckExecuteBatchPermission(const std::vector<std::shared_ptr<DataAbilityOperation>> & operations) const396 bool DataAbilityImpl::CheckExecuteBatchPermission(
397     const std::vector<std::shared_ptr<DataAbilityOperation>> &operations) const
398 {
399     bool needCheckReadPermission = false;
400     bool needCheckWritePermission = false;
401 
402     size_t size = operations.size();
403     for (size_t i = 0; i < size; i++) {
404         std::shared_ptr<DataAbilityOperation> operation = operations[i];
405         if (operation == nullptr) {
406             TAG_LOGE(AAFwkTag::DATA_ABILITY, "null operation, index: %{public}d", static_cast<int32_t>(i));
407             return false;
408         }
409         if (operation->IsInsertOperation() || operation->IsUpdateOperation() || operation->IsDeleteOperation()) {
410             needCheckWritePermission = true;
411         } else if (operation->IsAssertOperation()) {
412             needCheckReadPermission = true;
413         }
414         if (needCheckReadPermission && needCheckWritePermission) {
415             break;
416         }
417     }
418 
419     if (needCheckReadPermission) {
420         if (!CheckReadAndWritePermission(READ)) {
421             TAG_LOGW(AAFwkTag::DATA_ABILITY, "no read permission");
422             return false;
423         }
424     }
425 
426     if (needCheckWritePermission) {
427         if (!CheckReadAndWritePermission(WRITE)) {
428             TAG_LOGW(AAFwkTag::DATA_ABILITY, "no write permission");
429             return false;
430         }
431     }
432 
433     return true;
434 }
435 
CheckOpenFilePermission(const std::string & mode) const436 bool DataAbilityImpl::CheckOpenFilePermission(const std::string &mode) const
437 {
438     if (mode.find(READ) != string::npos) {
439         if (!CheckReadAndWritePermission(READ)) {
440             TAG_LOGW(AAFwkTag::DATA_ABILITY, "no read permission");
441             return false;
442         }
443     } else if (mode.find(WRITE) != string::npos) {
444         if (!CheckReadAndWritePermission(WRITE)) {
445             TAG_LOGW(AAFwkTag::DATA_ABILITY, "no write permission");
446             return false;
447         }
448     }
449 
450     return true;
451 }
452 
CheckReadAndWritePermission(const std::string & permissionType) const453 bool DataAbilityImpl::CheckReadAndWritePermission(const std::string &permissionType) const
454 {
455     std::string permission = GetPermissionInfo(permissionType);
456     if (permission.empty()) {
457         TAG_LOGD(AAFwkTag::DATA_ABILITY, "empty permission");
458         return true;
459     }
460 
461     auto tokenId = IPCSkeleton::GetCallingTokenID();
462     int checkReadPermission = AccessTokenKit::VerifyAccessToken(tokenId, permission);
463     if (checkReadPermission != ERR_OK) {
464         std::shared_ptr<AbilityInfo> abilityInfo = ability_->GetAbilityInfo();
465         TAG_LOGD(AAFwkTag::DATA_ABILITY, "no permission, bundleName: %{public}s", abilityInfo->bundleName.c_str());
466         return false;
467     }
468 
469     return true;
470 }
471 
GetPermissionInfo(const std::string & permissionType) const472 std::string DataAbilityImpl::GetPermissionInfo(const std::string &permissionType) const
473 {
474     TAG_LOGD(AAFwkTag::DATA_ABILITY, "permissionType:%{public}s", permissionType.c_str());
475     std::shared_ptr<AbilityInfo> abilityInfo = ability_->GetAbilityInfo();
476     if (abilityInfo == nullptr) {
477         TAG_LOGW(AAFwkTag::DATA_ABILITY, "null abilityInfo");
478         return "";
479     }
480     if (permissionType == READ) {
481         return abilityInfo->readPermission;
482     } else if (permissionType == WRITE) {
483         return abilityInfo->writePermission;
484     } else {
485         TAG_LOGI(AAFwkTag::DATA_ABILITY, "invalid permissionType:%{public}s", permissionType.c_str());
486         return "";
487     }
488 }
489 }  // namespace AppExecFwk
490 }  // namespace OHOS
491