未验证 提交 2e4fac52 编写于 作者: O openharmony_ci 提交者: Gitee

!19595 翻译已完成18990+19352+19217+18398

Merge pull request !19595 from shawn_he/18990-d
# IPC & RPC Development # IPC & RPC Development Guidelines
## When to Use ## When to Use
...@@ -11,8 +11,8 @@ Table 1 Native IPC APIs ...@@ -11,8 +11,8 @@ Table 1 Native IPC APIs
| Class| API| Description| | Class| API| Description|
| -------- | -------- | -------- | | -------- | -------- | -------- |
| [IRemoteBroker](../reference/apis/js-apis-rpc.md#iremotebroker) | sptr<IRemoteObject> AsObject() | Holder of a remote proxy object. If you call this API on the stub, the **RemoteObject** is returned; if you call this API on the proxy, the proxy object is returned.| | [IRemoteBroker](../reference/apis/js-apis-rpc.md#iremotebroker) | sptr<IRemoteObject> AsObject() | Obtains the holder of a remote proxy object. If you call this API on the stub, the **RemoteObject** is returned; if you call this API on the proxy, the proxy object is returned.|
| IRemoteStub | virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) | Callback used to process a request from the proxy and return the result. Derived classes need to override this API.| | IRemoteStub | virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) | Called to process a request from the proxy and return the result. Derived classes need to override this API.|
| IRemoteProxy | | Service proxy class, which is derived from the **IRemoteProxy** class.| | IRemoteProxy | | Service proxy class, which is derived from the **IRemoteProxy** class.|
...@@ -29,7 +29,7 @@ Table 1 Native IPC APIs ...@@ -29,7 +29,7 @@ Table 1 Native IPC APIs
external_deps = [ external_deps = [
"ipc:ipc_single", "ipc:ipc_single",
] ]
#RPC scenario #RPC scenario
external_deps = [ external_deps = [
"ipc:ipc_core", "ipc:ipc_core",
...@@ -50,12 +50,12 @@ Table 1 Native IPC APIs ...@@ -50,12 +50,12 @@ Table 1 Native IPC APIs
```c++ ```c++
#include "iremote_broker.h" #include "iremote_broker.h"
// Define message codes. // Define message codes.
const int TRANS_ID_PING_ABILITY = 5 const int TRANS_ID_PING_ABILITY = 5;
const std::string DESCRIPTOR = "test.ITestAbility"; const std::string DESCRIPTOR = "test.ITestAbility";
class ITestAbility : public IRemoteBroker { class ITestAbility : public IRemoteBroker {
public: public:
// DECLARE_INTERFACE_DESCRIPTOR is mandatory, and the input parameter is std::u16string. // DECLARE_INTERFACE_DESCRIPTOR is mandatory, and the input parameter is std::u16string.
...@@ -71,13 +71,13 @@ Table 1 Native IPC APIs ...@@ -71,13 +71,13 @@ Table 1 Native IPC APIs
```c++ ```c++
#include "iability_test.h" #include "iability_test.h"
#include "iremote_stub.h" #include "iremote_stub.h"
class TestAbilityStub : public IRemoteStub<ITestAbility> { class TestAbilityStub : public IRemoteStub<ITestAbility> {
public: public:
virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override;
int TestPingAbility(const std::u16string &dummy) override; int TestPingAbility(const std::u16string &dummy) override;
}; };
int TestAbilityStub::OnRemoteRequest(uint32_t code, int TestAbilityStub::OnRemoteRequest(uint32_t code,
MessageParcel &data, MessageParcel &reply, MessageOption &option) MessageParcel &data, MessageParcel &reply, MessageOption &option)
{ {
...@@ -98,12 +98,12 @@ Table 1 Native IPC APIs ...@@ -98,12 +98,12 @@ Table 1 Native IPC APIs
```c++ ```c++
#include "iability_server_test.h" #include "iability_server_test.h"
class TestAbility : public TestAbilityStub { class TestAbility : public TestAbilityStub {
public: public:
int TestPingAbility(const std::u16string &dummy); int TestPingAbility(const std::u16string &dummy);
} }
int TestAbility::TestPingAbility(const std::u16string &dummy) { int TestAbility::TestPingAbility(const std::u16string &dummy) {
return 0; return 0;
} }
...@@ -117,7 +117,7 @@ Table 1 Native IPC APIs ...@@ -117,7 +117,7 @@ Table 1 Native IPC APIs
#include "iability_test.h" #include "iability_test.h"
#include "iremote_proxy.h" #include "iremote_proxy.h"
#include "iremote_object.h" #include "iremote_object.h"
class TestAbilityProxy : public IRemoteProxy<ITestAbility> { class TestAbilityProxy : public IRemoteProxy<ITestAbility> {
public: public:
explicit TestAbilityProxy(const sptr<IRemoteObject> &impl); explicit TestAbilityProxy(const sptr<IRemoteObject> &impl);
...@@ -125,12 +125,12 @@ Table 1 Native IPC APIs ...@@ -125,12 +125,12 @@ Table 1 Native IPC APIs
private: private:
static inline BrokerDelegator<TestAbilityProxy> delegator_; // Use the iface_cast macro. static inline BrokerDelegator<TestAbilityProxy> delegator_; // Use the iface_cast macro.
} }
TestAbilityProxy::TestAbilityProxy(const sptr<IRemoteObject> &impl) TestAbilityProxy::TestAbilityProxy(const sptr<IRemoteObject> &impl)
: IRemoteProxy<ITestAbility>(impl) : IRemoteProxy<ITestAbility>(impl)
{ {
} }
int TestAbilityProxy::TestPingAbility(const std::u16string &dummy){ int TestAbilityProxy::TestPingAbility(const std::u16string &dummy){
MessageOption option; MessageOption option;
MessageParcel dataParcel, replyParcel; MessageParcel dataParcel, replyParcel;
...@@ -149,7 +149,7 @@ Table 1 Native IPC APIs ...@@ -149,7 +149,7 @@ Table 1 Native IPC APIs
// Register the TestAbilityStub instance with the SystemAbilityManager on the same device as the SA. // Register the TestAbilityStub instance with the SystemAbilityManager on the same device as the SA.
auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
samgr->AddSystemAbility(saId, new TestAbility()); samgr->AddSystemAbility(saId, new TestAbility());
// Register the TestAbilityStub instance with the SystemAbilityManager on a different device. // Register the TestAbilityStub instance with the SystemAbilityManager on a different device.
auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
ISystemAbilityManager::SAExtraProp saExtra; ISystemAbilityManager::SAExtraProp saExtra;
...@@ -166,10 +166,10 @@ Table 1 Native IPC APIs ...@@ -166,10 +166,10 @@ Table 1 Native IPC APIs
sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
sptr<IRemoteObject> remoteObject = samgr->GetSystemAbility(saId); sptr<IRemoteObject> remoteObject = samgr->GetSystemAbility(saId);
sptr<ITestAbility> testAbility = iface_cast<ITestAbility>(remoteObject); // Use the iface_cast macro to convert the proxy to a specific type. sptr<ITestAbility> testAbility = iface_cast<ITestAbility>(remoteObject); // Use the iface_cast macro to convert the proxy to a specific type.
// Obtain the proxy of the SA registered with any other devices. // Obtain the proxy of the SA registered with any other devices.
sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
// networkId is the device identifier and can be obtained through GetLocalNodeDeviceInfo. // networkId is the device identifier and can be obtained through GetLocalNodeDeviceInfo.
sptr<IRemoteObject> remoteObject = samgr->GetSystemAbility(saId, networkId); sptr<IRemoteObject> remoteObject = samgr->GetSystemAbility(saId, networkId);
sptr<TestAbilityProxy> proxy(new TestAbilityProxy(remoteObject)); // Construct a proxy. sptr<TestAbilityProxy> proxy(new TestAbilityProxy(remoteObject)); // Construct a proxy.
...@@ -180,59 +180,97 @@ Table 1 Native IPC APIs ...@@ -180,59 +180,97 @@ Table 1 Native IPC APIs
1. Add dependencies. 1. Add dependencies.
```ts ```ts
import rpc from "@ohos.rpc" import rpc from "@ohos.rpc";
import featureAbility from "@ohos.ability.featureAbility" // Import @ohos.ability.featureAbility only for the application developed based on the FA model.
// import featureAbility from "@ohos.ability.featureAbility";
``` ```
If you use the stage model, you need to obtain the context. The sample code is as follows:
```ts
import Ability from "@ohos.app.ability.UIAbility";
export default class MainAbility extends Ability {
onCreate(want, launchParam) {
console.log("[Demo] MainAbility onCreate");
globalThis.context = this.context;
}
onDestroy() {
console.log("[Demo] MainAbility onDestroy");
}
onWindowStageCreate(windowStage) {
// Main window is created, set main page for this ability
console.log("[Demo] MainAbility onWindowStageCreate");
}
onWindowStageDestroy() {
// Main window is destroyed, release UI related resources
console.log("[Demo] MainAbility onWindowStageDestroy");
}
onForeground() {
// Ability has brought to foreground
console.log("[Demo] MainAbility onForeground");
}
onBackground() {
// Ability has back to background
console.log("[Demo] MainAbility onBackground");
}
}
```
2. Bind the desired ability. 2. Bind the desired ability.
Construct the **want** variable, and specify the bundle name and component name of the application where the ability is located. If cross-device communication is involved, also specify the network ID of the target device, which can be obtained through **deviceManager**. Then, construct the **connect** variable, and specify the callback that is called when the binding is successful, the binding fails, or the ability is disconnected. After that, call the API provided by **featureAbility** to bind an ability. Construct the **want** variable, and specify the bundle name and component name of the application where the ability is located. If cross-device communication is involved, also specify the network ID of the target device, which can be obtained through **deviceManager**. Then, construct the **connect** variable, and specify the callback that is called when the binding is successful, the binding fails, or the ability is disconnected. If you use the FA model, call the API provided by **featureAbility** to bind an ability. If you use the stage model, obtain a service instance through **Context**, and then call the API provided by **featureAbility** to bind an ability.
```ts ```ts
import rpc from "@ohos.rpc" import rpc from "@ohos.rpc";
import featureAbility from "@ohos.ability.featureAbility" // Import @ohos.ability.featureAbility only for the application developed based on the FA model.
// import featureAbility from "@ohos.ability.featureAbility";
let proxy = null
let connectId = null let proxy = null;
let connectId = null;
// Bind the ability on a single device. // Bind the ability on a single device.
let want = { let want = {
// Enter the bundle name and ability name. // Enter the bundle name and ability name.
"bundleName": "ohos.rpc.test.server", "bundleName": "ohos.rpc.test.server",
"abilityName": "ohos.rpc.test.server.ServiceAbility", "abilityName": "ohos.rpc.test.server.ServiceAbility",
} };
let connect = { let connect = {
onConnect:function(elementName, remote) { onConnect:function(elementName, remote) {
proxy = remote proxy = remote;
}, },
onDisconnect:function(elementName) { onDisconnect:function(elementName) {
}, },
onFailed:function() { onFailed:function() {
proxy = null proxy = null;
} }
} };
connectId = featureAbility.connectAbility(want, connect) // Use this method to connect to the ability in the FA model.
// connectId = featureAbility.connectAbility(want, connect);
connectId = globalThis.context.connectServiceExtensionAbility(want,connect);
// If you're binding the ability across devices, use deviceManager to obtain the network ID of the target device. // If you're binding the ability across devices, use deviceManager to obtain the network ID of the target device.
import deviceManager from '@ohos.distributedHardware.deviceManager' import deviceManager from '@ohos.distributedHardware.deviceManager';
function deviceManagerCallback(deviceManager) { function deviceManagerCallback(deviceManager) {
let deviceList = deviceManager.getTrustedDeviceListSync() let deviceList = deviceManager.getTrustedDeviceListSync();
let networkId = deviceList[0].networkId let networkId = deviceList[0].networkId;
let want = { let want = {
"bundleName": "ohos.rpc.test.server", "bundleName": "ohos.rpc.test.server",
"abilityName": "ohos.rpc.test.service.ServiceAbility", "abilityName": "ohos.rpc.test.service.ServiceAbility",
"networkId": networkId, "networkId": networkId,
"flags": 256 "flags": 256
} };
connectId = featureAbility.connectAbility(want, connect) // The ID returned after the connection is set up must be saved. The ID will be passed for service disconnection.
// Use this method to connect to the ability in the FA model.
// connectId = featureAbility.connectAbility(want, connect);
connectId = globalThis.context.connectServiceExtensionAbility(want,connect);
} }
// The first parameter specifies the bundle name of the application, and the second parameter specifies the callback used to return the device ID obtained by using DeviceManager. // The first parameter specifies the bundle name of the application, and the second parameter specifies the callback used to return the device ID obtained by using DeviceManager.
deviceManager.createDeviceManager("ohos.rpc.test", deviceManagerCallback) deviceManager.createDeviceManager("ohos.rpc.test", deviceManagerCallback);
``` ```
3. Process requests sent from the client. 3. Process requests sent from the client.
...@@ -240,77 +278,79 @@ Table 1 Native IPC APIs ...@@ -240,77 +278,79 @@ Table 1 Native IPC APIs
```ts ```ts
onConnect(want: Want) { onConnect(want: Want) {
var robj:rpc.RemoteObject = new Stub("rpcTestAbility") var robj:rpc.RemoteObject = new Stub("rpcTestAbility");
return robj return robj;
} }
class Stub extends rpc.RemoteObject { class Stub extends rpc.RemoteObject {
constructor(descriptor) { constructor(descriptor) {
super(descriptor) super(descriptor);
} }
onRemoteMessageRequest(code, data, reply, option) { onRemoteMessageRequest(code, data, reply, option) {
// Process requests sent from the client based on the code. // Process requests sent from the client based on the code.
return true return true;
} }
} }
``` ```
4. Process responses sent from the server. 4. Process responses sent from the server.
Obtain the proxy object from the **onConnect** callback, call **sendRequestAsync** to send a request, and receive the response using a callback or a promise (an object representing the eventual completion or failure of an asynchronous operation and its result value). Obtain the proxy object from the **onConnect** callback, call **sendRequest** to send a request, and receive the response using a callback or a promise (an object representing the eventual completion or failure of an asynchronous operation and its result value).
```ts ```ts
// Use a promise. // Use a promise.
let option = new rpc.MessageOption() let option = new rpc.MessageOption();
let data = rpc.MessageParcel.create() let data = rpc.MessageParcel.create();
let reply = rpc.MessageParcel.create() let reply = rpc.MessageParcel.create();
// Write parameters to data. // Write parameters to data.
proxy.sendRequestAsync(1, data, reply, option) proxy.sendRequest(1, data, reply, option)
.then(function(result) { .then(function(result) {
if (result.errCode != 0) { if (result.errCode != 0) {
console.error("send request failed, errCode: " + result.errCode) console.error("send request failed, errCode: " + result.errCode);
return return;
} }
// Read the result from result.reply. // Read the result from result.reply.
}) })
.catch(function(e) { .catch(function(e) {
console.error("send request got exception: " + e) console.error("send request got exception: " + e);
} })
.finally(() => { .finally(() => {
data.reclaim() data.reclaim();
reply.reclaim() reply.reclaim();
}) })
// Use a callback. // Use a callback.
function sendRequestCallback(result) { function sendRequestCallback(result) {
try { try {
if (result.errCode != 0) { if (result.errCode != 0) {
console.error("send request failed, errCode: " + result.errCode) console.error("send request failed, errCode: " + result.errCode);
return return;
} }
// Read the result from result.reply. // Read the result from result.reply.
} finally { } finally {
result.data.reclaim() result.data.reclaim();
result.reply.reclaim() result.reply.reclaim();
} }
} }
let option = new rpc.MessageOption() let option = new rpc.MessageOption();
let data = rpc.MessageParcel.create() let data = rpc.MessageParcel.create();
let reply = rpc.MessageParcel.create() let reply = rpc.MessageParcel.create();
// Write parameters to data. // Write parameters to data.
proxy.sendRequest(1, data, reply, option, sendRequestCallback) proxy.sendRequest(1, data, reply, option, sendRequestCallback);
``` ```
5. Tear down the connection. 5. Tear down the connection.
Use the API provided by **featureAbility** to tear down the connection when the communication is over. If you use the FA model, call the API provided by **featureAbility** to tear down the connection when the communication is over. If you use the stage model, obtain a service instance through **Context**, and then call the API provided by **featureAbility** to tear down the connection.
```ts ```ts
import rpc from "@ohos.rpc" import rpc from "@ohos.rpc";
import featureAbility from "@ohos.ability.featureAbility" // Import @ohos.ability.featureAbility only for the application developed based on the FA model.
// import featureAbility from "@ohos.ability.featureAbility";
function disconnectCallback() { function disconnectCallback() {
console.info("disconnect ability done") console.info("disconnect ability done");
} }
featureAbility.disconnectAbility(connectId, disconnectCallback) // Use this method to disconnect from the ability in the FA model.
// featureAbility.disconnectAbility(connectId, disconnectCallback);
globalThis.context.disconnectServiceExtensionAbility(connectId);
``` ```
...@@ -3,42 +3,25 @@ ...@@ -3,42 +3,25 @@
## Basic Concepts ## Basic Concepts
The inter-process communication (IPC) and remote procedure call (RPC) mechanisms are used to implement cross-process communication. The difference between them lies in that IPC uses the Binder driver to implement cross-process communication within a device, whereas RPC uses the DSoftBus driver to implement cross-process communication across devices. The inter-process communication (IPC) and remote procedure call (RPC) mechanisms are used to implement cross-process communication. The difference between them lies in that IPC uses the Binder driver to implement cross-process communication within a device, whereas RPC uses the DSoftBus driver to implement cross-process communication across devices. The reason why cross-process communication is needed is that each process has its own independent resources and memory space and one process is not allowed to access the resources and memory space of other processes.
The reason why cross-process communication is needed is that each process has its own independent resources and memory space and one process is not allowed to access the resources and memory space of other processes. IPC and RPC usually use the client-server model, where the client (service requester, that is, the process that requests a service) obtains the proxy of the server (service provider, that is, the process that provides the service) and uses the proxy to read and write data to implement data communication across processes. More specifically, the client constructs a proxy object of the server. The proxy object has the same functions as the server. To access a certain API of the server, you only need to access the corresponding API in the proxy object. The proxy object sends the request to the server, and the server processes the received request and returns the processing result to the proxy object through the driver. Then, the proxy object forwards the processing result to the client. The server registers system abilities (SAs) with the system ability manager (SAMgr), which manages the SAs and provides APIs for clients. To communicate with a specific SA, the client must obtain the proxy of the SA from SAMgr. > **NOTE**
> The applications in the stage model cannot use IPC or RPC directly, and must use the following capabilities to implement related service scenarios:
>- [Background services](../application-models/background-services.md): use IPC to implement service invocation across processes.
>- [Multi-device collaboration](../application-models/hop-multi-device-collaboration.md): uses RPC to call remote interfaces and transfer data.
In the following sections, proxy represents the service requester, and stub represents the service provider.
![IPC&RPC communication mechanisms](figures/IPC_RPC_communication.PNG) ## Implementation Principles
IPC and RPC usually use the client-server model, where the client (service requester, that is, the process that requests a service) obtains the proxy of the server (service provider, that is, the process that provides the service) and uses the proxy to read and write data to implement data communication across processes. More specifically, the client constructs a proxy object of the server. The proxy object has the same functions as the server. To access a certain API of the server, you only need to access the corresponding API in the proxy object. The proxy object sends the request to the server, and the server processes the received request and returns the processing result to the proxy object through the driver. Then, the proxy object forwards the processing result to the client. The server registers system abilities (SAs) with the system ability manager (SAMgr), which manages the SAs and provides APIs for clients. To communicate with a specific SA, the client must obtain the proxy of the SA from SAMgr. In the following sections, proxy represents the service requester, and stub represents the service provider.
## Constraints ![IPC & RPC communication mechanisms] (figures/IPC_RPC_communication.PNG)
- During cross-process communication within a single device, the maximum amount of data to be transmitted is about 1 MB. If the amount of data to be transmitted exceeds this limit, use the [anonymous shared memory](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/apis/js-apis-rpc.md#ashmem8).
- Subscription to death notifications of anonymous stub objects (not registered with SAMgr) is prohibited in RPC.
- During cross-process communication across processes, a proxy object cannot be passed back to the device that hosts the stub object pointed by the proxy object. That is, the proxy object pointing to the stub object of the remote device cannot be passed across processes twice on the local device.
## **Recommendations**
First, compile an API class and define message codes in the API class for both communication parties to identify operations. Unimplemented APIs are allowed in the API class because it must be inherited by both communication parties and its inheritance classes cannot be abstract classes. When inheriting the API class, both communication parties must implement the unimplemented APIs, so as to make sure that the inheritance classes are not abstract classes.
Then, implement the API class specific to the stub, and override the **AsObject** and **OnRemoteRequest** APIs. In addition, compile the proxy to implement the APIs in the API class and override the **AsObject** API. You can also encapsulate an additional API for calling **SendRequest** to send data to the peer.
After the preceding operations are done, register a system ability (SA) with SAMgr. Note that the registration should be completed in the process that hosts the stub. Then, obtain the proxy from SAMgr as needed to implement cross-process communication with the stub.
Related steps are as follows:
- Implementing the API class: Inherit **IRemoteBroker**, define message codes, and declare APIs that are not implemented in the API class. ## Constraints
- Implementing the service provider (stub): Inherit **IRemoteStub** or **RemoteObject**, and override the **AsObject** and **OnRemoteRequest** APIs.
- Implementing the service requester (proxy): Inherit **IRemoteProxy** or **RemoteProxy**, override the **AsObject** API, and encapsulate the required API to call **SendRequest**.
- Registering the SA: Apply for a unique ID for the SA, and register the SA with SAMgr.
- Obtaining the SA: Obtain the proxy based on the SA ID and device ID, and use the proxy to communicate with the remote end.
- A maximum of 1 MB data can be transferred in cross-process communication on a single device. If the amount of data to be transmitted is larger than 1 MB, use [anonymous shared memory](../reference/apis/js-apis-rpc.md#ashmem8).
## Related Modules - Subscription to death notifications of anonymous stub objects (not registered with SAMgr) is prohibited in RPC.
[Distributed Ability Manager Service Framework](https://gitee.com/openharmony/ability_dmsfwk) - During cross-process communication across processes, a proxy object cannot be passed back to the device that hosts the stub object pointed by the proxy object. That is, the proxy object pointing to the stub object of the remote device cannot be passed across processes twice on the local device.
...@@ -7,7 +7,7 @@ IPC/RPC allows you to subscribe to the state changes of a remote stub object. Wh ...@@ -7,7 +7,7 @@ IPC/RPC allows you to subscribe to the state changes of a remote stub object. Wh
This subscription mechanism is applicable when the local proxy object needs to detect death of the process hosting the remote stub object or network detach of the device hosting the remote stub object. When the proxy detects death of the remote stub object, the proxy can clear local resources. Currently, IPC supports death notification for anonymous objects, but RPC does not. That is, you can only subscribe to death notifications of services that have been registered with SAMgr. This subscription mechanism is applicable when the local proxy object needs to detect death of the process hosting the remote stub object or network detach of the device hosting the remote stub object. When the proxy detects death of the remote stub object, the proxy can clear local resources. Currently, IPC supports death notification for anonymous objects, but RPC does not. That is, you can only subscribe to death notifications of services that have been registered with SAMgr.
## **Using Native APIs** ## **Development Using Native APIs**
| API| Return Value Type| Feature Description| | API| Return Value Type| Feature Description|
| -------- | -------- | -------- | | -------- | -------- | -------- |
...@@ -21,7 +21,6 @@ This subscription mechanism is applicable when the local proxy object needs to d ...@@ -21,7 +21,6 @@ This subscription mechanism is applicable when the local proxy object needs to d
#include "iremote_broker.h" #include "iremote_broker.h"
#include "iremote_stub.h" #include "iremote_stub.h"
// Define message codes. // Define message codes.
enum { enum {
TRANS_ID_PING_ABILITY = 5, TRANS_ID_PING_ABILITY = 5,
...@@ -61,9 +60,6 @@ int TestServiceProxy::TestPingAbility(const std::u16string &dummy){ ...@@ -61,9 +60,6 @@ int TestServiceProxy::TestPingAbility(const std::u16string &dummy){
} }
``` ```
```c++ ```c++
#include "iremote_object.h" #include "iremote_object.h"
...@@ -84,18 +80,54 @@ bool result = object->AddDeathRecipient(deathRecipient); // Add a recipient for ...@@ -84,18 +80,54 @@ bool result = object->AddDeathRecipient(deathRecipient); // Add a recipient for
result = object->RemoveDeathRecipient(deathRecipient); // Remove the recipient for death notifications. result = object->RemoveDeathRecipient(deathRecipient); // Remove the recipient for death notifications.
``` ```
## **Using JS APIs** ## **Development Using JS APIs**
| API | Return Value Type| Feature Description |
| ------------------------ | ---------- | ----------------------------------------------------------------- |
| registerDeathRecipient | void | Adds a recipient for death notifications of the remote object, including death notifications of the remote proxy.|
| unregisterDeathRecipient | void | Removes the recipient for death notifications of the remote object. |
| onRemoteDied | void | Called to perform subsequent operations when a death notification of the remote object is received. |
### Obtaining the Context
| API | Return Value Type| Feature Description | If you use the stage model, you need to obtain the context before connecting to an ability.
| -------------------- | ---------- | ------------------------------------------------------------ |
| addDeathRecippient | boolean | Adds a recipient for death notifications of the remote object, including death notifications of the remote proxy.| ```ts
| removeDeathRecipient | boolean | Removes the recipient for death notifications of the remote object. | import Ability from "@ohos.app.ability.UIAbility";
| onRemoteDied | void | Called to perform subsequent operations when a death notification of the remote object is received.|
export default class MainAbility extends Ability {
onCreate(want, launchParam) {
console.log("[Demo] MainAbility onCreate");
globalThis.context = this.context;
}
onDestroy() {
console.log("[Demo] MainAbility onDestroy");
}
onWindowStageCreate(windowStage) {
// Main window is created, set main page for this ability
console.log("[Demo] MainAbility onWindowStageCreate");
}
onWindowStageDestroy() {
// Main window is destroyed, release UI related resources
console.log("[Demo] MainAbility onWindowStageDestroy");
}
onForeground() {
// Ability has brought to foreground
console.log("[Demo] MainAbility onForeground");
}
onBackground() {
// Ability has back to background
console.log("[Demo] MainAbility onBackground");
}
}
```
### Sample Code ### Sample Code
```ts ```ts
import FA from "@ohos.ability.featureAbility"; // Import @ohos.ability.featureAbility only for the application developed based on the FA model.
// import FA from "@ohos.ability.featureAbility";
let proxy; let proxy;
let connect = { let connect = {
onConnect: function(elementName, remoteProxy) { onConnect: function(elementName, remoteProxy) {
...@@ -113,31 +145,35 @@ let want = { ...@@ -113,31 +145,35 @@ let want = {
"bundleName": "com.ohos.server", "bundleName": "com.ohos.server",
"abilityName": "com.ohos.server.EntryAbility", "abilityName": "com.ohos.server.EntryAbility",
}; };
FA.connectAbility(want, connect); // Use this method to connect to the ability in the FA model.
// FA.connectAbility(want, connect);
globalThis.context.connectServiceExtensionAbility(want, connect);
class MyDeathRecipient { class MyDeathRecipient {
onRemoteDied() { onRemoteDied() {
console.log("server died"); console.log("server died");
} }
} }
let deathRecipient = new MyDeathRecipient(); let deathRecipient = new MyDeathRecipient();
proxy.addDeathRecippient(deathRecipient, 0); proxy.registerDeathRecippient(deathRecipient, 0);
proxy.removeDeathRecipient(deathRecipient, 0); proxy.unregisterDeathRecipient(deathRecipient, 0);
``` ```
## Reverse Death Notification (Anonymous Stub) ## Reverse Death Notification (Anonymous Stub)
Forward dead notification is a mechanism that allows the proxy to detect death notifications of the stub. To achieve reverse dead notification, we can leverage the forward dead notification mechanism to allow the stub to detect death notifications of the proxy. Forward dead notification is a mechanism that allows the proxy to detect death notifications of the stub. To achieve reverse dead notification, we can leverage the forward dead notification mechanism to allow the stub to detect death notifications of the proxy. Suppose there are two processes, A (the process hosting the original stub) and B (the process hosting the original proxy). After obtaining the proxy object of process A, process B creates an anonymous stub object (that is, a stub object not registered with SAMgr), which can be called a callback stub. Then, process B calls **SendRequest** to send the callback stub to the original stub of process A. As a result, process A obtains the callback proxy of process B. When process B dies or the device hosting process B detaches from the network, the callback stub dies. The callback proxy detects the death of the callback stub and sends a death notification to the original stub. In this way, reverse death notification is implemented.
Note:
Suppose there are two processes, A (the process hosting the original stub) and B (the process hosting the original proxy). After obtaining the proxy object of process A, process B creates an anonymous stub object (that is, a stub object not registered with SAMgr), which can be called a callback stub. Then, process B calls **SendRequest** to send the callback stub to the original stub of process A. As a result, process A obtains the callback proxy of process B. When process B dies or the device hosting process B detaches from the network, the callback stub dies. The callback proxy detects the death of the callback stub and sends a death notification to the original stub. In this way, reverse death notification is implemented. > Reverse death notification can only be used for cross-process communication within a device.
> NOTE > When an anonymous stub object is not pointed by any proxy, the kernel automatically reclaims the object.
> - Reverse death notification can only be used for cross-process communication within a device.
> - When an anonymous stub object is not pointed by any proxy, the kernel automatically reclaims the object.
### Sample Code ### Sample Code
```c++ ```c++
// Proxy //Proxy
int TestAbilityProxy::TestAnonymousStub() int TestAbilityProxy::TestAnonymousStub()
{ {
MessageOption option; MessageOption option;
...@@ -149,7 +185,7 @@ int TestAbilityProxy::TestAnonymousStub() ...@@ -149,7 +185,7 @@ int TestAbilityProxy::TestAnonymousStub()
return result; return result;
} }
// Stub //Stub
int TestAbilityStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) int TestAbilityStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
{ {
......
...@@ -6,7 +6,7 @@ Applicable to: OpenHarmony 3.2 Beta (API version 9) ...@@ -6,7 +6,7 @@ Applicable to: OpenHarmony 3.2 Beta (API version 9)
**Solution** **Solution**
**extraData** indicates additional data in an HTTP request. It varies depending on the HTTP request method. **extraData** specifies additional data in an HTTP request. It varies depending on the HTTP request method.
- If the HTTP request uses a POST or PUT method, **extraData** serves as the content of the HTTP request. - If the HTTP request uses a POST or PUT method, **extraData** serves as the content of the HTTP request.
- If the HTTP request uses a GET, OPTIONS, DELETE, TRACE, or CONNECT method, **extraData** serves as a supplement to the HTTP request parameters and will be added to the URL when the request is sent. - If the HTTP request uses a GET, OPTIONS, DELETE, TRACE, or CONNECT method, **extraData** serves as a supplement to the HTTP request parameters and will be added to the URL when the request is sent.
......
...@@ -184,18 +184,18 @@ import featureAbility from '@ohos.ability.featureAbility' ...@@ -184,18 +184,18 @@ import featureAbility from '@ohos.ability.featureAbility'
let context = featureAbility.getContext(); let context = featureAbility.getContext();
context.getFilesDir().then((data) => { context.getFilesDir().then((data) => {
var path = data + "/serviceInfo.txt" var path = data + "/serviceInfo.txt";
console.info("output path: " + path) console.info("output path: " + path);
let fd = fs.openSync(path, 0o102, 0o666) let file = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
var serviceId = 10 var serviceId = 10;
var args = new Array("allInfo") var args = new Array("allInfo");
try { try {
hidebug.getServiceDump(serviceId, fd, args) hidebug.getServiceDump(serviceId, file.fd, args);
} catch (error) { } catch (error) {
console.info(error.code) console.info(error.code);
console.info(error.message) console.info(error.message);
} }
fs.closeSync(fd); fs.closeSync(file);
}) })
``` ```
......
...@@ -12,6 +12,8 @@ debug(message: string, ...arguments: any[]): void ...@@ -12,6 +12,8 @@ debug(message: string, ...arguments: any[]): void
Prints debugging information in formatted output mode. Prints debugging information in formatted output mode.
Since API version 9, this API is supported in ArkTS widgets.
**System capability**: SystemCapability.ArkUI.ArkUI.Full **System capability**: SystemCapability.ArkUI.ArkUI.Full
**Parameters** **Parameters**
...@@ -39,6 +41,8 @@ log(message: string, ...arguments: any[]): void ...@@ -39,6 +41,8 @@ log(message: string, ...arguments: any[]): void
Prints log information in formatted output mode. Prints log information in formatted output mode.
Since API version 9, this API is supported in ArkTS widgets.
**System capability**: SystemCapability.ArkUI.ArkUI.Full **System capability**: SystemCapability.ArkUI.ArkUI.Full
**Parameters** **Parameters**
...@@ -66,6 +70,8 @@ info(message: string, ...arguments: any[]): void ...@@ -66,6 +70,8 @@ info(message: string, ...arguments: any[]): void
Prints log information in formatted output mode. This API is the alias of **console.log ()**. Prints log information in formatted output mode. This API is the alias of **console.log ()**.
Since API version 9, this API is supported in ArkTS widgets.
**System capability**: SystemCapability.ArkUI.ArkUI.Full **System capability**: SystemCapability.ArkUI.ArkUI.Full
**Parameters** **Parameters**
...@@ -93,6 +99,8 @@ warn(message: string, ...arguments: any[]): void ...@@ -93,6 +99,8 @@ warn(message: string, ...arguments: any[]): void
Prints warning information in formatted output mode. Prints warning information in formatted output mode.
Since API version 9, this API is supported in ArkTS widgets.
**System capability**: SystemCapability.ArkUI.ArkUI.Full **System capability**: SystemCapability.ArkUI.ArkUI.Full
**Parameters** **Parameters**
...@@ -120,6 +128,8 @@ error(message: string, ...arguments: any[]): void ...@@ -120,6 +128,8 @@ error(message: string, ...arguments: any[]): void
Prints error information in formatted output mode. Prints error information in formatted output mode.
Since API version 9, this API is supported in ArkTS widgets.
**System capability**: SystemCapability.ArkUI.ArkUI.Full **System capability**: SystemCapability.ArkUI.ArkUI.Full
**Parameters** **Parameters**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册