• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 #include "session_backup_n_exporter.h"
16 
17 #include <functional>
18 #include <memory>
19 
20 #include "b_error/b_error.h"
21 #include "b_filesystem/b_file.h"
22 #include "b_resources/b_constants.h"
23 #include "b_session_backup.h"
24 #include "backup_kit_inner.h"
25 #include "directory_ex.h"
26 #include "filemgmt_libhilog.h"
27 #include "general_callbacks.h"
28 #include "service_proxy.h"
29 
30 namespace OHOS::FileManagement::Backup {
31 using namespace std;
32 using namespace LibN;
33 
34 struct BackupEntity {
35     unique_ptr<BSessionBackup> session;
36     shared_ptr<GeneralCallbacks> callbacks;
37 };
38 
OnFileReady(weak_ptr<GeneralCallbacks> pCallbacks,const BFileInfo & fileInfo,UniqueFd fd)39 static void OnFileReady(weak_ptr<GeneralCallbacks> pCallbacks, const BFileInfo &fileInfo, UniqueFd fd)
40 {
41     if (pCallbacks.expired()) {
42         HILOGI("callbacks is unbound");
43         return;
44     }
45     auto callbacks = pCallbacks.lock();
46     if (!callbacks) {
47         HILOGI("callback function onFileReady has already been released");
48         return;
49     }
50     if (!bool(callbacks->onFileReady)) {
51         HILOGI("callback function onFileReady is undefined");
52         return;
53     }
54 
55     auto cbCompl = [bundleName {fileInfo.owner}, fileName {fileInfo.fileName},
56                     fd {make_shared<UniqueFd>(fd.Release())}](napi_env env, NError err) -> NVal {
57         if (err) {
58             return {env, err.GetNapiErr(env)};
59         }
60         NVal obj = NVal::CreateObject(env);
61         obj.AddProp({NVal::DeclareNapiProperty("bundleName", NVal::CreateUTF8String(env, bundleName).val_),
62                      NVal::DeclareNapiProperty("uri", NVal::CreateUTF8String(env, fileName).val_),
63                      NVal::DeclareNapiProperty("fd", NVal::CreateInt32(env, fd->Release()).val_)});
64 
65         return {obj};
66     };
67 
68     callbacks->onFileReady.ThreadSafeSchedule(cbCompl);
69 }
70 
onBundleBegin(weak_ptr<GeneralCallbacks> pCallbacks,ErrCode err,const BundleName name)71 static void onBundleBegin(weak_ptr<GeneralCallbacks> pCallbacks, ErrCode err, const BundleName name)
72 {
73     if (pCallbacks.expired()) {
74         HILOGI("callbacks is unbound");
75         return;
76     }
77     auto callbacks = pCallbacks.lock();
78     if (!callbacks) {
79         HILOGI("callback function onBundleBegin has already been released");
80         return;
81     }
82     if (!bool(callbacks->onBundleBegin)) {
83         HILOGI("callback function onBundleBegin is undefined");
84         return;
85     }
86 
87     auto cbCompl = [name {name}](napi_env env, NError err) -> NVal {
88         return err ? NVal {env, err.GetNapiErr(env)} : NVal::CreateUTF8String(env, name);
89     };
90 
91     callbacks->onBundleBegin.ThreadSafeSchedule(cbCompl);
92 }
93 
onBundleEnd(weak_ptr<GeneralCallbacks> pCallbacks,ErrCode err,const BundleName name)94 static void onBundleEnd(weak_ptr<GeneralCallbacks> pCallbacks, ErrCode err, const BundleName name)
95 {
96     if (pCallbacks.expired()) {
97         HILOGI("callbacks is unbound");
98         return;
99     }
100     auto callbacks = pCallbacks.lock();
101     if (!callbacks) {
102         HILOGI("callback function onBundleEnd has already been released");
103         return;
104     }
105     if (!bool(callbacks->onBundleEnd)) {
106         HILOGI("callback function onBundleEnd is undefined");
107         return;
108     }
109 
110     auto cbCompl = [name {name}](napi_env env, NError err) -> NVal {
111         return err ? NVal {env, err.GetNapiErr(env)} : NVal::CreateUTF8String(env, name);
112     };
113 
114     callbacks->onBundleEnd.ThreadSafeSchedule(cbCompl);
115 }
116 
onAllBundlesEnd(weak_ptr<GeneralCallbacks> pCallbacks,ErrCode err)117 static void onAllBundlesEnd(weak_ptr<GeneralCallbacks> pCallbacks, ErrCode err)
118 {
119     if (pCallbacks.expired()) {
120         HILOGI("callbacks is unbound");
121         return;
122     }
123     auto callbacks = pCallbacks.lock();
124     if (!callbacks) {
125         HILOGI("callback function onAllBundlesEnd has already been released");
126         return;
127     }
128     if (!bool(callbacks->onAllBundlesEnd)) {
129         HILOGI("callback function onAllBundlesEnd is undefined");
130         return;
131     }
132 
133     auto cbCompl = [](napi_env env, NError err) -> NVal {
134         return err ? NVal {env, err.GetNapiErr(env)} : NVal::CreateUndefined(env);
135     };
136 
137     callbacks->onAllBundlesEnd.ThreadSafeSchedule(cbCompl);
138 }
139 
OnBackupServiceDied(weak_ptr<GeneralCallbacks> pCallbacks)140 static void OnBackupServiceDied(weak_ptr<GeneralCallbacks> pCallbacks)
141 {
142     if (pCallbacks.expired()) {
143         HILOGI("callbacks is unbound");
144         return;
145     }
146     auto callbacks = pCallbacks.lock();
147     if (!callbacks) {
148         HILOGI("js callback function onBackupServiceDied has already been released");
149         return;
150     }
151     if (!bool(callbacks->onBackupServiceDied)) {
152         HILOGI("callback function onBackupServiceDied is undefined");
153         return;
154     }
155 
156     auto cbCompl = [](napi_env env, NError err) -> NVal {
157         return err ? NVal {env, err.GetNapiErr(env)} : NVal::CreateUndefined(env);
158     };
159 
160     callbacks->onBackupServiceDied.ThreadSafeSchedule(cbCompl);
161 }
162 
Constructor(napi_env env,napi_callback_info cbinfo)163 napi_value SessionBackupNExporter::Constructor(napi_env env, napi_callback_info cbinfo)
164 {
165     HILOGI("called SessionBackup::Constructor begin");
166     NFuncArg funcArg(env, cbinfo);
167     if (!funcArg.InitArgs(NARG_CNT::ONE)) {
168         HILOGE("Number of arguments unmatched");
169         NError(EINVAL).ThrowErr(env);
170         return nullptr;
171     }
172 
173     NVal callbacks(env, funcArg[NARG_POS::FIRST]);
174     if (!callbacks.TypeIs(napi_object)) {
175         HILOGE("First argument is not an object.");
176         NError(EINVAL).ThrowErr(env);
177         return nullptr;
178     }
179 
180     NVal ptr(env, funcArg.GetThisVar());
181     auto backupEntity = std::make_unique<BackupEntity>();
182     backupEntity->callbacks = make_shared<GeneralCallbacks>(env, ptr, callbacks);
183     backupEntity->session = BSessionBackup::Init(BSessionBackup::Callbacks {
184         .onFileReady = bind(OnFileReady, backupEntity->callbacks, placeholders::_1, placeholders::_2),
185         .onBundleStarted = bind(onBundleBegin, backupEntity->callbacks, placeholders::_1, placeholders::_2),
186         .onBundleFinished = bind(onBundleEnd, backupEntity->callbacks, placeholders::_1, placeholders::_2),
187         .onAllBundlesFinished = bind(onAllBundlesEnd, backupEntity->callbacks, placeholders::_1),
188         .onBackupServiceDied = bind(OnBackupServiceDied, backupEntity->callbacks)});
189     if (!backupEntity->session) {
190         NError(BError(BError::Codes::SDK_INVAL_ARG, "Failed to init backup").GetCode()).ThrowErr(env);
191         return nullptr;
192     }
193     if (!NClass::SetEntityFor<BackupEntity>(env, funcArg.GetThisVar(), move(backupEntity))) {
194         HILOGE("Failed to set BackupEntity entity");
195         NError(EINVAL).ThrowErr(env);
196         return nullptr;
197     }
198 
199     HILOGI("called SessionBackup::Constructor end");
200     return funcArg.GetThisVar();
201 }
202 
AppendBundles(napi_env env,napi_callback_info cbinfo)203 napi_value SessionBackupNExporter::AppendBundles(napi_env env, napi_callback_info cbinfo)
204 {
205     HILOGI("called SessionBackup::AppendBundles begin");
206     NFuncArg funcArg(env, cbinfo);
207     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
208         HILOGE("Number of arguments unmatched");
209         NError(EINVAL).ThrowErr(env);
210         return nullptr;
211     }
212 
213     NVal jsBundles(env, funcArg[NARG_POS::FIRST]);
214     auto [succ, bundles, ignore] = jsBundles.ToStringArray();
215     if (!succ) {
216         HILOGE("First argument is not bundles array.");
217         NError(EINVAL).ThrowErr(env);
218         return nullptr;
219     }
220 
221     auto backupEntity = NClass::GetEntityOf<BackupEntity>(env, funcArg.GetThisVar());
222     if (!(backupEntity && backupEntity->session)) {
223         HILOGE("Failed to get backupSession entity.");
224         NError(EPERM).ThrowErr(env);
225         return nullptr;
226     }
227 
228     auto cbExec = [session {backupEntity->session.get()}, bundles {bundles}]() -> NError {
229         if (!session) {
230             return NError(BError(BError::Codes::SDK_INVAL_ARG, "backup session is nullptr").GetCode());
231         }
232         return NError(session->AppendBundles(bundles));
233     };
234     auto cbCompl = [](napi_env env, NError err) -> NVal {
235         return err ? NVal {env, err.GetNapiErr(env)} : NVal::CreateUndefined(env);
236     };
237 
238     HILOGE("Called SessionBackup::AppendBundles end.");
239 
240     NVal thisVar(env, funcArg.GetThisVar());
241     if (funcArg.GetArgc() == NARG_CNT::ONE) {
242         return NAsyncWorkPromise(env, thisVar).Schedule(className, cbExec, cbCompl).val_;
243     } else {
244         NVal cb(env, funcArg[NARG_POS::SECOND]);
245         return NAsyncWorkCallback(env, thisVar, cb).Schedule(className, cbExec, cbCompl).val_;
246     }
247 }
248 
Export()249 bool SessionBackupNExporter::Export()
250 {
251     HILOGI("called SessionBackupNExporter::Export begin");
252     vector<napi_property_descriptor> props = {NVal::DeclareNapiFunction("appendBundles", AppendBundles)};
253 
254     auto [succ, classValue] = NClass::DefineClass(exports_.env_, className, Constructor, std::move(props));
255     if (!succ) {
256         HILOGE("Failed to define class");
257         NError(EIO).ThrowErr(exports_.env_);
258         return false;
259     }
260     succ = NClass::SaveClass(exports_.env_, className, classValue);
261     if (!succ) {
262         HILOGE("Failed to save class");
263         NError(EIO).ThrowErr(exports_.env_);
264         return false;
265     }
266 
267     HILOGI("called SessionBackupNExporter::Export end");
268     return exports_.AddProp(className, classValue);
269 }
270 
GetClassName()271 string SessionBackupNExporter::GetClassName()
272 {
273     return SessionBackupNExporter::className;
274 }
275 
SessionBackupNExporter(napi_env env,napi_value exports)276 SessionBackupNExporter::SessionBackupNExporter(napi_env env, napi_value exports) : NExporter(env, exports) {}
277 
~SessionBackupNExporter()278 SessionBackupNExporter::~SessionBackupNExporter() {}
279 } // namespace OHOS::FileManagement::Backup