• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2  * Copyright (c) 2025 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 "ani_file_share.h"
17 
18 #include <ani.h>
19 #include <iostream>
20 #include <vector>
21 #include "ability.h"
22 #include "datashare_helper.h"
23 #include "datashare_values_bucket.h"
24 #include "ipc_skeleton.h"
25 #include "log.h"
26 #include "n_error.h"
27 #include "remote_uri.h"
28 #include "tokenid_kit.h"
29 #include "uri.h"
30 #include "uri_permission_manager_client.h"
31 #include "want.h"
32 
33 using namespace OHOS::DataShare;
34 using namespace OHOS::DistributedFS::ModuleRemoteUri;
35 using namespace OHOS::FileManagement::LibN;
36 
37 namespace OHOS {
38 namespace AppFileService {
39 namespace ModuleFileShare {
40 
ParseObjToStr(ani_env * env,ani_string stringObj)41 static std::string ParseObjToStr(ani_env *env, ani_string stringObj)
42 {
43     ani_size  strSize;
44     env->String_GetUTF8Size(stringObj, &strSize);
45     std::vector<char> buffer(strSize + 1);
46     char* utf8Buffer = buffer.data();
47 
48     ani_size byteswritten = 0;
49     env->String_GetUTF8(stringObj, utf8Buffer, strSize + 1, &byteswritten);
50 
51     if (byteswritten <= strSize) {
52         utf8Buffer[byteswritten] = '\0';
53     } else {
54         utf8Buffer[strSize] = '\0';
55     }
56     std::string path = std::string(utf8Buffer);
57     return path;
58 }
59 
ParseEnumToInt(ani_env * env,ani_enum_item enumItem)60 static ani_int ParseEnumToInt(ani_env *env, ani_enum_item enumItem)
61 {
62     ani_int intValue = -1;
63     if (ANI_OK != env->EnumItem_GetValue_Int(enumItem, &intValue)) {
64         LOGE("%{public}s: EnumItem_GetValue_Int FAILD.", __func__);
65         return -1;
66     }
67     LOGD("%{public}s: Enum Value: %{public}d.", __func__, intValue);
68     return intValue;
69 }
70 
ThrowBusinessError(ani_env * env,int errCode,std::string && errMsg)71 static void ThrowBusinessError(ani_env *env, int errCode, std::string&& errMsg)
72 {
73     LOGD("Begin ThrowBusinessError.");
74     static const char *errorClsName = "L@ohos/base/BusinessError;";
75     ani_class cls {};
76     if (ANI_OK != env->FindClass(errorClsName, &cls)) {
77         LOGE("find class BusinessError %{public}s failed", errorClsName);
78         return;
79     }
80     ani_method ctor;
81     if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", ":V", &ctor)) {
82         LOGE("find method BusinessError.constructor failed");
83         return;
84     }
85     ani_object errorObject;
86     if (ANI_OK != env->Object_New(cls, ctor, &errorObject)) {
87         LOGE("create BusinessError object failed");
88         return;
89     }
90     ani_double aniErrCode = static_cast<ani_double>(errCode);
91     ani_string errMsgStr;
92     if (ANI_OK != env->String_NewUTF8(errMsg.c_str(), errMsg.size(), &errMsgStr)) {
93         LOGE("convert errMsg to ani_string failed");
94         return;
95     }
96     if (ANI_OK != env->Object_SetFieldByName_Double(errorObject, "code", aniErrCode)) {
97         LOGE("set error code failed");
98         return;
99     }
100     if (ANI_OK != env->Object_SetPropertyByName_Ref(errorObject, "message", errMsgStr)) {
101         LOGE("set error message failed");
102         return;
103     }
104     env->ThrowError(static_cast<ani_error>(errorObject));
105     return;
106 }
107 
IsSystemApp()108 static bool IsSystemApp()
109 {
110     uint64_t fullTokenId = OHOS::IPCSkeleton::GetCallingFullTokenID();
111     return OHOS::Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(fullTokenId);
112 }
113 
GetIdFromUri(string uri)114 static int32_t GetIdFromUri(string uri)
115 {
116     std::replace(uri.begin(), uri.end(), '/', ' ');
117     std::stringstream ss(uri);
118     std::string tmp;
119     int fileId = -1;
120     ss >> tmp >> tmp >> tmp >> fileId;
121     return fileId;
122 }
123 
CheckValidPublicUri(const std::string & inputUri)124 static bool CheckValidPublicUri(const std::string &inputUri)
125 {
126     Uri uri(inputUri);
127     std::string scheme = uri.GetScheme();
128     if (scheme != FILE_SCHEME) {
129         return false;
130     }
131 
132     std::string authority = uri.GetAuthority();
133     if (authority != MEDIA_AUTHORITY && authority != FILE_MANAGER_AUTHORITY) {
134         return false;
135     }
136 
137     return true;
138 }
139 
GetModeFromFlag(unsigned int flag)140 static std::string GetModeFromFlag(unsigned int flag)
141 {
142     std::string mode = "";
143     if (flag & OHOS::AAFwk::Want::FLAG_AUTH_READ_URI_PERMISSION) {
144         mode += "r";
145     }
146     if (flag & OHOS::AAFwk::Want::FLAG_AUTH_WRITE_URI_PERMISSION) {
147         mode += "w";
148     }
149     return mode;
150 }
151 
GetMediaTypeAndApiFromUri(const std::string & uri,bool & isApi10)152 static int32_t GetMediaTypeAndApiFromUri(const std::string &uri, bool &isApi10)
153 {
154     if (uri.find(MEDIA_FILE_URI_PHOTO_PREFIX) == 0) {
155         isApi10 = true;
156         return MediaFileTable::PHOTO_TABLE;
157     } else if (uri.find(MEDIA_FILE_URI_VIDEO_PREFIX) == 0 ||
158         uri.find(MEDIA_FILE_URI_IMAGE_PREFIX) == 0) {
159         return MediaFileTable::PHOTO_TABLE;
160     } else if (uri.find(MEDIA_FILE_URI_AUDIO_PREFIX) == 0) {
161         isApi10 = true;
162         return MediaFileTable::AUDIO_TABLE;
163     } else if (uri.find(MEDIA_FILE_URI_AUDIO_PREFIX_L) == 0) {
164         return MediaFileTable::AUDIO_TABLE;
165     } else if (uri.find(MEDIA_FILE_URI_FILE_PREFIX) == 0) {
166         return MediaFileTable::FILE_TABLE;
167     }
168 
169     return MediaFileTable::FILE_TABLE;
170 }
171 
InitValuesBucket(const UriPermissionInfo & uriPermInfo,Uri & uri,bool & isApi10,DataShareValuesBucket & valuesBucket)172 static int InitValuesBucket(const UriPermissionInfo &uriPermInfo, Uri &uri, bool &isApi10,
173     DataShareValuesBucket &valuesBucket)
174 {
175     int32_t fileId = GetIdFromUri(uriPermInfo.uri);
176     if (fileId == -1) {
177         LOGE("%{public}s: get fileId parameter failed!", __func__);
178         return -EINVAL;
179     }
180 
181     int32_t filesType = GetMediaTypeAndApiFromUri(uri.ToString(), isApi10);
182     valuesBucket.Put(PERMISSION_FILE_ID, fileId);
183     valuesBucket.Put(PERMISSION_BUNDLE_NAME, uriPermInfo.bundleName);
184     valuesBucket.Put(PERMISSION_MODE, uriPermInfo.mode);
185     valuesBucket.Put(PERMISSION_TABLE_TYPE, filesType);
186     return 0;
187 }
188 
InsertByDatashare(const DataShareValuesBucket & valuesBucket,bool isApi10)189 static int InsertByDatashare(const DataShareValuesBucket &valuesBucket, bool isApi10)
190 {
191     int ret = -1;
192     std::shared_ptr<DataShare::DataShareHelper> dataShareHelper = nullptr;
193     sptr<FileShareGrantToken> remote = new (std::nothrow) IRemoteStub<FileShareGrantToken>();
194     if (remote == nullptr) {
195         LOGE("%{public}s: get remoteObject failed!", __func__);
196         return -ret;
197     }
198 
199     dataShareHelper = DataShare::DataShareHelper::Creator(remote->AsObject(), MEDIALIBRARY_DATA_URI);
200     if (!dataShareHelper) {
201         LOGE("%{public}s: connect to datashare failed!", __func__);
202         return ret;
203     }
204     string uriStr = MEDIA_GRANT_URI_PERMISSION;
205     if (isApi10) {
206         uriStr +=  MEDIA_API_VERSION_10;
207     }
208 
209     Uri uri(uriStr);
210     ret = dataShareHelper->Insert(uri, valuesBucket);
211     if (ret < 0) {
212         LOGE("%{public}s: insert failed with error code %{public}d!", __func__, ret);
213         return ret;
214     }
215     return ret;
216 }
217 
GrantInMediaLibrary(const UriPermissionInfo & uriPermInfo,Uri & uri)218 static int GrantInMediaLibrary(const UriPermissionInfo &uriPermInfo, Uri &uri)
219 {
220     bool isApi10 = false;
221     DataShareValuesBucket valuesBucket;
222     int ret = InitValuesBucket(uriPermInfo, uri, isApi10, valuesBucket);
223     if (ret < 0) {
224         LOGE("%{public}s: InitValuesBucket failed!", __func__);
225         return ret;
226     }
227 
228     ret = InsertByDatashare(valuesBucket, isApi10);
229     if (ret < 0) {
230         LOGE("%{public}s: InsertByDatashare failed!", __func__);
231         return ret;
232     }
233     return 0;
234 }
235 
DoGrantUriPermission(const UriPermissionInfo & uriPermInfo)236 static int DoGrantUriPermission(const UriPermissionInfo &uriPermInfo)
237 {
238     Uri uri(uriPermInfo.uri);
239     std::string authority = uri.GetAuthority();
240     std::string path = uri.GetPath();
241     if (authority == MEDIA_AUTHORITY && path.find(".") == string::npos) {
242         return GrantInMediaLibrary(uriPermInfo, uri);
243     } else {
244         auto& uriPermissionClient = OHOS::AAFwk::UriPermissionManagerClient::GetInstance();
245         int ret =  uriPermissionClient.GrantUriPermission(uri, uriPermInfo.flag, uriPermInfo.bundleName);
246         if (ret != 0) {
247             LOGD("%{public}s: uriPermissionClient.GrantUriPermission by uri permission client failed!", __func__);
248             return GrantInMediaLibrary(uriPermInfo, uri);
249         }
250     }
251 
252     return 0;
253 }
254 
GrantUriPermission(ani_env * env,ani_string uri,ani_string bundleName,ani_object enumIndex)255 static void GrantUriPermission(ani_env *env, ani_string uri, ani_string bundleName, ani_object enumIndex)
256 {
257     LOGD("Enter GrantUriPermission.");
258     if (!IsSystemApp()) {
259         LOGE("%{public}s: GrantUriPermission is not System App!", __func__);
260         ThrowBusinessError(env, E_PERMISSION_SYS, "FileShare::GrantUriPermission is not System App!");
261         return;
262     }
263 
264     UriPermissionInfo uriPermInfo;
265     std::string uriStr = ParseObjToStr(env, uri);
266     if (!CheckValidPublicUri(uriStr)) {
267         LOGE("%{public}s: GrantUriPermission uri is not valid!", __func__);
268         ThrowBusinessError(env, EINVAL, "GrantUriPermission uri is not valid!");
269         return;
270     }
271     uriPermInfo.uri = uriStr;
272     std::string bundleNameStr = ParseObjToStr(env, bundleName);
273     uriPermInfo.bundleName = bundleNameStr;
274 
275     ani_int wantConstantFlag = ParseEnumToInt(env, static_cast<ani_enum_item>(enumIndex));
276     if (wantConstantFlag < 0) {
277         LOGE("%{public}s: GrantUriPermission ParseEnumToInt Faild!", __func__);
278         ThrowBusinessError(env, EINVAL, "GrantUriPermission is not System App!");
279         return;
280     }
281     uriPermInfo.flag = static_cast<uint32_t>(wantConstantFlag);
282     uriPermInfo.mode = GetModeFromFlag(wantConstantFlag);
283     LOGD("GrantUriPermission uri: %{public}s, bundleName: %{public}s, flag: %{public}d, mode: %{public}s",
284         uriStr.c_str(), bundleNameStr.c_str(), wantConstantFlag, uriPermInfo.mode.c_str());
285 
286     int ret = DoGrantUriPermission(uriPermInfo);
287     if (ret < 0) {
288         LOGE("FileShare::GrantUriPermission DoGrantUriPermission failed with %{public}d", ret);
289         ThrowBusinessError(env, -ret, "GrantUriPermission failed");
290         return;
291     }
292     LOGD("FileShare::GrantUriPermission DoGrantUriPermission successfully!");
293 }
294 } // namespace ModuleFileShare
295 } // namespace AppFileService
296 } // namespace OHOS
297 
ANI_Constructor(ani_vm * vm,uint32_t * result)298 ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result)
299 {
300     LOGD("Enter ANI_Constructor.");
301     ani_env *env;
302     if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) {
303         LOGE("Unsupported ANI_VERSION_1");
304         return ANI_ERROR;
305     }
306 
307     static const char *nsName = "L@ohos/fileshare/fileShare;";
308     ani_namespace ns;
309     if (ANI_OK != env->FindNamespace(nsName, &ns)) {
310         LOGE("Not found namespace %{public}s.", nsName);
311         return ANI_NOT_FOUND;
312     }
313     std::array nsMethods = {
314         ani_native_function {"grantUriPermissionInner", nullptr,
315             reinterpret_cast<void *>(OHOS::AppFileService::ModuleFileShare::GrantUriPermission)},
316     };
317     if (ANI_OK != env->Namespace_BindNativeFunctions(ns, nsMethods.data(), nsMethods.size())) {
318         LOGE("Cannot bind native methods to namespace %{public}s.", nsName);
319         return ANI_ERROR;
320     };
321 
322     *result = ANI_VERSION_1;
323     return ANI_OK;
324 }
325