1 /*
2  * Copyright (c) 2022 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 "datashare_connection.h"
17 
18 #include "ams_mgr_proxy.h"
19 #include "datashare_errno.h"
20 #include "datashare_log.h"
21 #include "datashare_proxy.h"
22 #include "datashare_radar_reporter.h"
23 #include "datashare_string_utils.h"
24 
25 namespace OHOS {
26 namespace DataShare {
27 using namespace AppExecFwk;
28 /**
29  * @brief This method is called back to receive the connection result after an ability calls the
30  * ConnectAbility method to connect it to an extension ability.
31  *
32  * @param element: Indicates information about the connected extension ability.
33  * @param remote: Indicates the remote proxy object of the extension ability.
34  * @param resultCode: Indicates the connection result code. The value 0 indicates a successful connection, and any
35  * other value indicates a connection failure.
36  */
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)37 void DataShareConnection::OnAbilityConnectDone(
38     const AppExecFwk::ElementName &element, const sptr<IRemoteObject> &remoteObject, int resultCode)
39 {
40     LOG_INFO("on connect done, req uri:%{public}s, rev uri:%{public}s, ret=%{public}d",
41         DataShareStringUtils::Change(uri_.ToString()).c_str(),
42         DataShareStringUtils::Change(element.GetURI()).c_str(), resultCode);
43     if (remoteObject == nullptr) {
44         LOG_ERROR("remote is nullptr");
45         condition_.condition.notify_all();
46         return;
47     }
48     {
49         std::lock_guard<std::mutex> lock(mutex_);
50         sptr<DataShareProxy> proxy = new (std::nothrow) DataShareProxy(remoteObject);
51         dataShareProxy_ = std::shared_ptr<DataShareProxy>(proxy.GetRefPtr(), [holder = proxy](const auto *) {});
52         condition_.condition.notify_all();
53     }
54     if (isInvalid_.load()) {
55         LOG_ERROR("connect is invalid, req uri:%{public}s, rev uri:%{public}s, ret=%{public}d",
56             DataShareStringUtils::Change(uri_.ToString()).c_str(),
57             DataShareStringUtils::Change(element.GetURI()).c_str(), resultCode);
58         Disconnect();
59     }
60 }
61 
62 /**
63  * @brief This method is called back to receive the disconnection result after the connected extension ability crashes
64  * or is killed. If the extension ability exits unexpectedly, all its connections are disconnected, and each ability
65  * previously connected to it will call onAbilityDisconnectDone.
66  *
67  * @param element: Indicates information about the disconnected extension ability.
68  * @param resultCode: Indicates the disconnection result code. The value 0 indicates a successful disconnection, and
69  * any other value indicates a disconnection failure.
70  */
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)71 void DataShareConnection::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode)
72 {
73     LOG_INFO("on disconnect done, req uri:%{public}s, rev uri:%{public}s, ret=%{public}d",
74         DataShareStringUtils::Change(uri_.ToString()).c_str(),
75         DataShareStringUtils::Change(element.GetURI()).c_str(), resultCode);
76     std::string uri;
77     {
78         std::lock_guard<std::mutex> lock(mutex_);
79         dataShareProxy_ = nullptr;
80         uri = uri_.ToString();
81     }
82     if (uri.empty()) {
83         return;
84     }
85     if (pool_ == nullptr) {
86         std::lock_guard<std::mutex> lock(mutex_);
87         if (pool_ == nullptr) {
88             pool_ = std::make_shared<ExecutorPool>(MAX_THREADS, MIN_THREADS);
89         }
90     }
91     ReconnectExtAbility(uri);
92 }
93 
ReconnectExtAbility(const std::string & uri)94 void DataShareConnection::ReconnectExtAbility(const std::string &uri)
95 {
96     if (reConnects_.count == 0) {
97         AmsMgrProxy* instance = AmsMgrProxy::GetInstance();
98         if (instance == nullptr) {
99             LOG_ERROR("get proxy failed uri:%{public}s", DataShareStringUtils::Change(uri_.ToString()).c_str());
100             return;
101         }
102         ErrCode ret = instance->Connect(uri, this, token_);
103         LOG_INFO("reconnect ability, uri:%{public}s, ret = %{public}d",
104             DataShareStringUtils::Change(uri).c_str(), ret);
105         if (ret == E_OK) {
106             auto curr = std::chrono::system_clock::now().time_since_epoch();
107             reConnects_.count = 1;
108             reConnects_.firstTime = std::chrono::duration_cast<std::chrono::milliseconds>(curr).count();
109             reConnects_.prevTime = std::chrono::duration_cast<std::chrono::milliseconds>(curr).count();
110         }
111         return;
112     }
113     return DelayConnectExtAbility(uri);
114 }
115 
DelayConnectExtAbility(const std::string & uri)116 void DataShareConnection::DelayConnectExtAbility(const std::string &uri)
117 {
118     int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
119         std::chrono::system_clock::now().time_since_epoch()).count();
120     if (now - reConnects_.prevTime >= MAX_RECONNECT_TIME_INTERVAL.count()) {
121         reConnects_.count = 0;
122         reConnects_.firstTime = now;
123         reConnects_.prevTime = now;
124     }
125     if (reConnects_.count >= MAX_RECONNECT) {
126         return;
127     }
128     auto delay = RECONNECT_TIME_INTERVAL;
129     if (now - reConnects_.prevTime >= RECONNECT_TIME_INTERVAL.count()) {
130         delay = std::chrono::seconds(0);
131     }
132     std::weak_ptr<DataShareConnection> self = weak_from_this();
133     auto taskid = pool_->Schedule(delay, [uri, self]() {
134         auto selfSharedPtr = self.lock();
135         if (selfSharedPtr) {
136             AmsMgrProxy* instance = AmsMgrProxy::GetInstance();
137             if (instance == nullptr) {
138                 LOG_ERROR("get proxy failed uri:%{public}s", DataShareStringUtils::Change(uri).c_str());
139                 return;
140             }
141             ErrCode ret = instance->Connect(uri, selfSharedPtr.get(), selfSharedPtr->token_);
142             LOG_INFO("reconnect ability, uri:%{public}s, ret = %{public}d",
143                 DataShareStringUtils::Change(uri).c_str(), ret);
144             if (ret == E_OK) {
145                 selfSharedPtr->reConnects_.count++;
146                 selfSharedPtr->reConnects_.prevTime = std::chrono::duration_cast<std::chrono::milliseconds>(
147                     std::chrono::system_clock::now().time_since_epoch()).count();
148             }
149         }
150     });
151     if (taskid == ExecutorPool::INVALID_TASK_ID) {
152         LOG_ERROR("create scheduler failed, over the max capacity");
153         return;
154     }
155     LOG_DEBUG("create scheduler success");
156     return;
157 }
158 
159 /**
160  * @brief connect remote ability of DataShareExtAbility.
161  */
ConnectDataShareExtAbility(const Uri & uri,const sptr<IRemoteObject> & token)162 std::shared_ptr<DataShareProxy> DataShareConnection::ConnectDataShareExtAbility(const Uri &uri,
163     const sptr<IRemoteObject> &token)
164 {
165     std::string reqUri;
166     {
167         std::lock_guard<std::mutex> lock(mutex_);
168         if (dataShareProxy_ != nullptr) {
169             return dataShareProxy_;
170         }
171         reqUri = uri_.ToString().empty() ? uri.ToString() : uri_.ToString();
172     }
173 
174     AmsMgrProxy* instance = AmsMgrProxy::GetInstance();
175     if (instance == nullptr) {
176         LOG_ERROR("get proxy failed uri:%{public}s", DataShareStringUtils::Change(reqUri).c_str());
177         return nullptr;
178     }
179     ErrCode ret = instance->Connect(reqUri, this, token);
180     LOG_INFO("connect ability, uri = %{public}s. ret = %{public}d", DataShareStringUtils::Change(reqUri).c_str(), ret);
181     if (ret != ERR_OK) {
182         return nullptr;
183     }
184     std::unique_lock<std::mutex> condLock(condition_.mutex);
185     if (condition_.condition.wait_for(condLock, std::chrono::seconds(waitTime_),
186         [this] { return dataShareProxy_ != nullptr; })) {
187         LOG_DEBUG("connect ability ended successfully uri:%{public}s", DataShareStringUtils::Change(reqUri).c_str());
188         RADAR_REPORT(__FUNCTION__, RadarReporter::CREATE_DATASHARE_HELPER,
189             RadarReporter::CONNECT_EXT, RadarReporter::SUCCESS,
190             RadarReporter::LOCAL_SESS_NAME, Str16ToStr8(token->GetObjectDescriptor()),
191             RadarReporter::PEER_SESS_NAME, DataShareStringUtils::Change(reqUri));
192     } else {
193         LOG_WARN("connect timeout uri:%{public}s", DataShareStringUtils::Change(reqUri).c_str());
194         RADAR_REPORT(__FUNCTION__, RadarReporter::CREATE_DATASHARE_HELPER,
195             RadarReporter::CONNECT_EXT, RadarReporter::FAILED,
196             RadarReporter::ERROR_CODE, RadarReporter::EXT_CONNECT_TIMEOUT_ERROR,
197             RadarReporter::LOCAL_SESS_NAME, Str16ToStr8(token->GetObjectDescriptor()),
198             RadarReporter::PEER_SESS_NAME, DataShareStringUtils::Change(reqUri));
199     }
200     return GetDataShareProxy();
201 }
202 
203 /**
204  * @brief disconnect remote ability of DataShareExtAbility.
205  */
DisconnectDataShareExtAbility()206 void DataShareConnection::DisconnectDataShareExtAbility()
207 {
208     std::string uri;
209     {
210         std::lock_guard<std::mutex> lock(mutex_);
211         uri = uri_.ToString();
212         uri_ = Uri("");
213         if (dataShareProxy_ == nullptr) {
214             return;
215         }
216     }
217 
218     ErrCode ret = Disconnect();
219     LOG_INFO("disconnect uri:%{public}s, ret = %{public}d", DataShareStringUtils::Change(uri).c_str(), ret);
220     if (ret == E_OK) {
221         RADAR_REPORT(__FUNCTION__, RadarReporter::CREATE_DATASHARE_HELPER,
222             RadarReporter::DIS_CONNECT_EXT, RadarReporter::SUCCESS,
223             RadarReporter::LOCAL_SESS_NAME, Str16ToStr8(token_->GetObjectDescriptor()),
224             RadarReporter::PEER_SESS_NAME, DataShareStringUtils::Change(uri));
225         return;
226     }
227     RADAR_REPORT(__FUNCTION__, RadarReporter::CREATE_DATASHARE_HELPER,
228         RadarReporter::DIS_CONNECT_EXT, RadarReporter::FAILED,
229         RadarReporter::ERROR_CODE, RadarReporter::EXT_DIS_CONNECT_ERROR,
230         RadarReporter::LOCAL_SESS_NAME, Str16ToStr8(token_->GetObjectDescriptor()),
231         RadarReporter::PEER_SESS_NAME, DataShareStringUtils::Change(uri));
232 }
233 
~DataShareConnection()234 DataShareConnection::~DataShareConnection()
235 {
236 }
237 
GetDataShareProxy(const Uri & uri,const sptr<IRemoteObject> & token)238 std::shared_ptr<DataShareProxy> DataShareConnection::GetDataShareProxy(const Uri &uri,
239     const sptr<IRemoteObject> &token)
240 {
241     return ConnectDataShareExtAbility(uri, token);
242 }
243 
SetConnectInvalid()244 void DataShareConnection::SetConnectInvalid()
245 {
246     isInvalid_.store(true);
247 }
248 
Disconnect()249 ErrCode DataShareConnection::Disconnect()
250 {
251     AmsMgrProxy* instance = AmsMgrProxy::GetInstance();
252     if (instance == nullptr) {
253         return -1;
254     }
255     return instance->DisConnect(this);
256 }
257 
GetDataShareProxy()258 std::shared_ptr<DataShareProxy> DataShareConnection::GetDataShareProxy()
259 {
260     std::lock_guard<std::mutex> lock(mutex_);
261     return dataShareProxy_;
262 }
263 }  // namespace DataShare
264 }  // namespace OHOS