1# samgr_lite
2
3## Introduction
4
5Due to limited platform resources, a unified system ability framework is provided to harmonize differences of hardware architectures (for example, RISC-V, Cortex-M, and Cortex-A), platform resources, and running modes. Two types of hardware platforms (M- and A-core) are defined.
6
7-   M-core: hardware platforms with Cortex-M or equivalent processing capabilities. The system memory is generally less than 512 KB. There is only a lightweight file system that can be used in limited scenarios, or no file system at all. M-core platforms comply with the Cortex Microcontroller Software Interface Standard (CMSIS).
8-   A-core: hardware platforms with Cortex-A or equivalent processing capabilities. The system memory is greater than 512 KB. There is a comprehensive file system for storing a large amount of data. A-core platforms comply with the Portable Operating System Interface (POSIX) specifications.
9
10This service-oriented system ability framework enables you to develop services, features, and external APIs, and implement multi-service process sharing and service invoking for inter-process communication (IPC). Where:
11
12-   M core provides services, features, external APIs, and multi-service process sharing development.
13-   In addition to the capabilities provided by M-core, A-core provides capabilities such as IPC service invoking, permission control for IPC service invoking, and IPC service API development.
14
15## System Architecture
16
17Figure 1 Service-oriented architecture
18
19
20![](figures/en-us_image_0000001128146921.png)
21
22-   Provider: a service provider that provides capabilities (external APIs) for the system.
23-   Consumer: a service consumer that invokes the features (external APIs) provided by the service.
24-   Samgr: an agency that manages capabilities provided by providers and helps consumers discover providers' capabilities.
25
26**Figure 2** Main objects of the system ability framework
27
28![](figures/en-us_image_0000001081285004.png)
29
30-   SamgrLite: provides service registration and discovery.
31-   Service: implements lifecycle APIs of the service during service development.
32-   Feature: implements lifecycle APIs of the feature during feature development.
33-   IUnknown: implements external APIs for services or features based on **IUnknown**.
34-   IClientProxy: implements the consumer's proxy to send messages during IPC invoking.
35-   IServerProxy: implements the provider's proxy during IPC invoking, which needs to be implemented by developers.
36
37## Directory Structure
38
39**Figure 1** Structure of the source code directory of the system ability framework
40
41| Name                                              | Description                                        |
42| -------------------------------------------------- | -------------------------------------------- |
43| interfaces/kits/samgr_lite/samgr                   | External APIs of the M- and A-core system ability frameworks.          |
44| interfaces/kits/samgr_lite/registry                | External APIs for service invocation between A-core processes.           |
45| interfaces/kits/samgr_lite/communication/broadcast | External APIs of the event broadcast service within M- and A-core processes.  |
46| services/samgr_lite/samgr/adapter                  | POSIX and CMSIS interface adaptation layer, which is used to harmonize the differences between the APIs of M- and A-core.|
47| services/samgr_lite/samgr/registry                 | Stub functions for M-core service registration and discovery.                   |
48| services/samgr_lite/samgr/source                   | Basic code for the M- and A-core system ability frameworks.          |
49| services/samgr_lite/samgr_client                   | Registration and discovery for service invocation between A-core processes.             |
50| services/samgr_lite/samgr_server                   | IPC address management and access control for service invocation between A-core processes.  |
51| services/samgr_lite/samgr_endpoint                 | Packet Rx/Tx management for A-core IPC.                  |
52| services/samgr_lite/communication/broadcast        | Event broadcast service for M- and A-core processes.                |
53
54## Constraints
55
56-   The system ability framework is developed using the C programming language.
57-   Services in the same process use **IUnknown** for invoking. Messages are passed to the service through **IUnknown**.
58-   The service name and feature name must be constant strings and the length must be less than 16 bytes.
59-   More-core depends on the Bootstrap service and calls the **OHOS_SystemInit()** function in the system startup function.
60-   A-core depends on the Samgr library and calls the **SAMGR_Bootstrap()** function in the **main** function.
61
62## Developing a Service
63
64-   Inherit and redefine a service.
65
66    ```
67    typedef struct ExampleService {
68        INHERIT_SERVICE;
69        INHERIT_IUNKNOWNENTRY(DefaultFeatureApi);
70        Identity identity;
71    } ExampleService;
72    ```
73
74-   Implement the lifecycle function of the service.
75
76    ```
77    static const char *GetName(Service *service)
78    {
79        return EXAMPLE_SERVICE;
80    }
81
82    static BOOL Initialize(Service *service, Identity identity)
83    {
84        ExampleService *example = (ExampleService *)service;
85        // Save the unique ID of the service, which is used when IUnknown is used to send messages to the service.
86        example->identity = identity;
87        return TRUE;
88    }
89    static BOOL MessageHandle(Service *service, Request *msg)
90    {
91        ExampleService *example = (ExampleService *)service;
92        switch (msg->msgId) {
93            case MSG_SYNC:
94                // Process the service.
95                break;
96            default:break;
97        }
98        return FALSE;
99    }
100    static TaskConfig GetTaskConfig(Service *service)
101    {
102        TaskConfig config = {LEVEL_HIGH, PRI_BELOW_NORMAL,
103                             0x800, 20, SHARED_TASK};
104        return config;
105    }
106    ```
107
108-   Create a service object.
109
110    ```
111    static ExampleService g_example = {
112        .GetName = GetName,
113        .Initialize = Initialize,
114        .MessageHandle = MessageHandle,
115        .GetTaskConfig = GetTaskConfig,
116        SERVER_IPROXY_IMPL_BEGIN,
117            .Invoke = NULL,
118            .SyncCall = SyncCall,
119        IPROXY_END,
120    };
121    ```
122
123-   Register the service and API with Samgr.
124
125    ```
126    static void Init(void)
127    {
128        SAMGR_GetInstance()->RegisterService((Service *)&g_example);
129        SAMGR_GetInstance()->RegisterDefaultFeatureApi(EXAMPLE_SERVICE, GET_IUNKNOWN(g_example));
130    }
131    ```
132
133-   Define the initializer of the service.
134
135    ```
136    SYSEX_SERVICE_INIT(Init);
137
138    ```
139
140
141## Developing a Feature of a Service
142
143-   Inherit and redefine a feature.
144
145    ```
146    typedef struct DemoFeature {
147        INHERIT_FEATURE;
148        INHERIT_IUNKNOWNENTRY(DemoApi);
149        Identity identity;
150        Service *parent;
151    } DemoFeature;
152    ```
153
154-   Implement the lifecycle function of the feature.
155
156    ```
157    static const char *FEATURE_GetName(Feature *feature)
158    {
159        return EXAMPLE_FEATURE;
160    }
161
162    static void FEATURE_OnInitialize(Feature *feature, Service *parent, Identity identity)
163    {
164        DemoFeature *demoFeature = (DemoFeature *)feature;
165        demoFeature->identity = identity;
166        demoFeature->parent = parent;
167    }
168
169    static void FEATURE_OnStop(Feature *feature, Identity identity)
170    {
171        g_example.identity.queueId = NULL;
172        g_example.identity.featureId = -1;
173        g_example.identity.serviceId = -1;
174    }
175
176    static BOOL FEATURE_OnMessage(Feature *feature, Request *request)
177    {
178        if (request->msgId == MSG_PROC) {
179            Response response = {.data = "Yes, you did!", .len = 0};
180            SAMGR_SendResponse(request, &response);
181            return TRUE;
182        } else {
183            if (request->msgId == MSG_TIME_PROC) {
184                LOS_Msleep(WAIT_FEATURE_PROC * 10);
185                if (request->msgValue) {
186                    SAMGR_PrintServices();
187                } else {
188                    SAMGR_PrintOperations();
189                }
190                AsyncTimeCall(GET_IUNKNOWN(g_example));
191                return FALSE;
192            }
193        }
194        return FALSE;
195    }
196    ```
197
198-   Create a feature object.
199
200    ```
201    static DemoFeature g_example = {
202        .GetName = FEATURE_GetName,
203        .OnInitialize = FEATURE_OnInitialize,
204        .OnStop = FEATURE_OnStop,
205        .OnMessage = FEATURE_OnMessage,
206        DEFAULT_IUNKNOWN_ENTRY_BEGIN,
207            .AsyncCall = AsyncCall,
208            .AsyncTimeCall = AsyncTimeCall,
209            .SyncCall = SyncCall,
210            .AsyncCallBack = AsyncCallBack,
211        DEFAULT_IUNKNOWN_ENTRY_END,
212        .identity = {-1, -1, NULL},
213    };
214    ```
215
216-   Register the feature and API with Samgr.
217
218    ```
219    static void Init(void){
220        SAMGR_GetInstance()->RegisterFeature(EXAMPLE_SERVICE, (Feature *)&g_example);
221        SAMGR_GetInstance()->RegisterFeatureApi(EXAMPLE_SERVICE, EXAMPLE_FEATURE, GET_IUNKNOWN(g_example));
222    }
223    ```
224
225-   Define the initializer of the feature.
226
227    ```
228    SYSEX_FEATURE_INIT(Init);
229
230    ```
231
232
233## Developing an External API for Intra-Process Communication
234
235-   Define the **IUnknown** API.
236
237    ```
238    typedef struct DemoApi {
239        INHERIT_IUNKNOWN;
240        BOOL (*AsyncCall)(IUnknown *iUnknown, const char *buff);
241        BOOL (*AsyncTimeCall)(IUnknown *iUnknown);
242        BOOL (*SyncCall)(IUnknown *iUnknown, struct Payload *payload);
243        BOOL (*AsyncCallBack)(IUnknown *iUnknown, const char *buff, Handler handler);
244    } DemoApi;
245    ```
246
247-   Define the reference object of **IUnknown**.
248
249    ```
250    typedef struct DemoRefApi {
251        INHERIT_IUNKNOWNENTRY(DemoApi);
252    } DemoRefApi;
253    ```
254
255-   Initialize the object of **IUnknown**.
256
257    ```
258    static DemoRefApi api = {
259        DEFAULT_IUNKNOWN_ENTRY_BEGIN,
260            .AsyncCall = AsyncCall,
261            .AsyncTimeCall = AsyncTimeCall,
262            .SyncCall = SyncCall,
263            .AsyncCallBack = AsyncCallBack,
264        DEFAULT_IUNKNOWN_ENTRY_END,
265    };
266    ```
267
268-   Register the feature API.
269
270    ```
271    SAMGR_GetInstance()->RegisterFeatureApi(EXAMPLE_SERVICE, EXAMPLE_FEATURE, GET_IUNKNOWN(api));
272
273    ```
274
275
276## Invoking a Service in the Same Process
277
278-   Obtain the external API of the service.
279
280    ```
281    DemoApi *demoApi = NULL;
282    IUnknown *iUnknown = SAMGR_GetInstance()->GetFeatureApi(EXAMPLE_SERVICE, EXAMPLE_FEATURE);
283    if (iUnknown == NULL) {
284        return NULL;
285    }
286    int result = iUnknown->QueryInterface(iUnknown, DEFAULT_VERSION, (void **)&demoApi);
287    if (result != 0 || demoApi == NULL) {
288        return NULL;
289    }
290    ```
291
292-   Call the API.
293
294    ```
295    if (demoApi->AsyncCallBack == NULL) {
296        return NULL;
297    }
298    demoApi->AsyncCallBack((IUnknown *)demoApi, "I wanna async call callback good result!", AsyncHandler);
299    ```
300
301-   Release the API.
302
303    ```
304    int32 ref = demoApi->Release((IUnknown *)demoApi);
305
306    ```
307
308
309## Developing an External API for IPC
310
311-   Inherit **IServerProxy** to replace **IUnknown**: INHERIT\_SERVER\_IPROXY
312
313    ```
314    typedef struct DemoFeatureApi {
315        INHERIT_SERVER_IPROXY;
316        BOOL (*AsyncCall)(IUnknown *iUnknown, const char *buff);
317        BOOL (*AsyncTimeCall)(IUnknown *iUnknown);
318        BOOL (*SyncCall)(IUnknown *iUnknown, struct Payload *payload);
319        BOOL (*AsyncCallBack)(IUnknown *iUnknown, const char *buff, IOwner notify, INotifyFunc handler);
320    } DemoFeatureApi;
321    ```
322
323-   Initialize the **IServerProxy** object.
324
325    ```
326    static DemoFeature g_example = {
327        SERVER_IPROXY_IMPL_BEGIN,
328        .Invoke = Invoke,
329        .AsyncCall = AsyncCall,
330        .AsyncTimeCall = AsyncTimeCall,
331        .SyncCall = SyncCall,
332        .AsyncCallBack = AsyncCallBack,
333        IPROXY_END,
334    };
335    ```
336
337-   Implement the **Invoke** function to process IPC messages.
338
339    ```
340    static int32 Invoke(IServerProxy *iProxy, int funcId, void *origin, IpcIo *req, IpcIo *reply)
341    {
342        DemoFeatureApi *api = (DemoFeatureApi *)iProxy;
343        BOOL ret;
344        size_t len = 0;
345        switch (funcId) {
346            case ID_ASYNCALL:
347                ret = api->AsyncCall((IUnknown *)iProxy, (char *)IpcIoPopString(req, &len));
348                IpcIoPushBool(reply, ret);
349                break;
350            case ID_ASYNTIMECALL:
351                ret = api->AsyncTimeCall((IUnknown *)iProxy);
352                IpcIoPushBool(reply, ret);
353                break;
354            case ID_SYNCCALL: {
355                struct Payload payload;
356                payload.id = IpcIoPopInt32(req);
357                payload.value = IpcIoPopInt32(req);
358                payload.name = (char *)IpcIoPopString(req, &len);
359                ret = api->SyncCall((IUnknown *)iProxy, &payload);
360                IpcIoPushString(reply, ret ? "TRUE" : "FALSE");
361            }
362                break;
363            case ID_ASYNCCALLBACK: { // convert to sync proxy
364                IpcIoPushString(reply, "Yes, you did!");
365                IpcIoPushBool(reply, TRUE);
366            }
367                break;
368            default:
369                IpcIoPushBool(reply, FALSE);
370                break;
371        }
372        return EC_SUCCESS;
373    }
374    ```
375
376-   Register the API. This step is same as the API registration for intra-process communication.
377
378    ```
379    SAMGR_GetInstance()->RegisterFeatureApi(EXAMPLE_SERVICE, EXAMPLE_FEATURE, GET_IUNKNOWN(g_example));
380
381    ```
382
383
384## Invoking a Service in Another Process
385
386-   Obtain the external API of the service in another process.
387
388    ```
389    IClientProxy *demoApi = NULL;
390    IUnknown *iUnknown = SAMGR_GetInstance()->GetFeatureApi(EXAMPLE_SERVICE, EXAMPLE_FEATURE);
391    if (iUnknown == NULL) {
392        return NULL;
393    }
394    int result = iUnknown->QueryInterface(iUnknown, CLIENT_PROXY_VER, (void **)&demoApi);
395    if (result != 0 || demoApi == NULL) {
396        return NULL;
397    }
398    ```
399
400-   Invoke the API for sending IPC messages.
401
402    ```
403    IpcIo request;char data[250];
404    IpcIoInit(&request, data, sizeof(data), 0);
405    demoApi->Invoke(demoApi, 0, &request, NULL, NULL);
406    ```
407
408-   Release the API.
409
410    ```
411    int32 ref = demoApi->Release((IUnknown *)demoApi);
412
413    ```
414
415
416## Developing a Client Proxy for Inter-Process Service Invocation
417
418-   Define a client proxy for the IPC API.
419
420    ```
421    typedef struct DemoClientProxy {
422        INHERIT_CLIENT_IPROXY;
423        BOOL (*AsyncCall)(IUnknown *iUnknown, const char *buff);
424        BOOL (*AsyncTimeCall)(IUnknown *iUnknown);
425        BOOL (*SyncCall)(IUnknown *iUnknown, struct Payload *payload);
426        BOOL (*AsyncCallBack)(IUnknown *iUnknown, const char *buff, IOwner notify, INotifyFunc handler);
427    } DemoClientProxy;
428    typedef struct DemoClientEntry {
429        INHERIT_IUNKNOWNENTRY(DemoClientProxy);
430    } DemoClientEntry;
431    ```
432
433-   Enable the client proxy to encapsulate the IPC message API.
434
435    ```
436    static BOOL AsyncCall(IUnknown *iUnknown, const char *buff)
437    {
438        DemoClientProxy *proxy = (DemoClientProxy *)iUnknown;
439        IpcIo request;
440        char data[MAX_DATA_LEN];
441        IpcIoInit(&request, data, MAX_DATA_LEN, 0);
442        IpcIoPushString(&request, buff);
443        int ret = proxy->Invoke((IClientProxy *)proxy, ID_ASYNCALL, &request, NULL, NULL);
444        return ret == EC_SUCCESS;
445    }
446
447    static BOOL AsyncTimeCall(IUnknown *iUnknown)
448    {
449        DemoClientProxy *proxy = (DemoClientProxy *)iUnknown;
450        IpcIo request;
451        char data[MAX_DATA_LEN];
452        IpcIoInit(&request, data, MAX_DATA_LEN, 0);
453        int ret = proxy->Invoke((IClientProxy *)proxy, ID_ASYNTIMECALL, &request, NULL, NULL);
454        return ret == EC_SUCCESS;
455    }
456
457    static int Callback(IOwner owner, int code, IpcIo *reply)
458    {
459        size_t len = 0;
460        return strcpy_s(owner, MAX_DATA_LEN, (char *)IpcIoPopString(reply, &len));
461    }
462
463    static BOOL SyncCall(IUnknown *iUnknown, struct Payload *payload)
464    {
465        DemoClientProxy *proxy = (DemoClientProxy *)iUnknown;
466        IpcIo request;
467        char data[MAX_DATA_LEN];
468        IpcIoInit(&request, data, MAX_DATA_LEN, 0);
469        IpcIoPushInt32(&request, payload->id);
470        IpcIoPushInt32(&request, payload->value);
471        IpcIoPushString(&request, payload->name);
472        int ret = proxy->Invoke((IClientProxy *)proxy, ID_SYNCCALL, &request, data, Callback);
473        data[MAX_DATA_LEN - 1] = 0;
474        HILOG_INFO(HILOG_MODULE_APP, "[TID:0x%lx]Remote response is %s!", pthread_self(), data);
475        return ret == EC_SUCCESS;
476    }
477
478    struct CurrentNotify {
479        IOwner notify;
480        INotifyFunc handler;
481    };
482
483    static int CurrentCallback(IOwner owner, int code, IpcIo *reply)
484    {
485        struct CurrentNotify *notify = (struct CurrentNotify *)owner;
486        size_t len = 0;
487        char *response = (char *)IpcIoPopString(reply, &len);
488        HILOG_INFO(HILOG_MODULE_APP, "[TID:0x%lx]Notify Remote response is %s!", pthread_self(), response);
489        notify->handler(notify->notify, response);
490        return EC_SUCCESS;
491    }
492
493    static BOOL AsyncCallBack(IUnknown *iUnknown, const char *buff, IOwner notify, INotifyFunc handler)
494    {
495        struct CurrentNotify owner = {notify, handler};
496        DemoClientProxy *proxy = (DemoClientProxy *)iUnknown;
497        IpcIo request;
498        char data[MAX_DATA_LEN];
499        IpcIoInit(&request, data, MAX_DATA_LEN, 0);
500        IpcIoPushString(&request, buff);
501        int ret = proxy->Invoke((IClientProxy *)proxy, ID_ASYNCCALLBACK, &request, &owner, CurrentCallback);
502        return ret == EC_SUCCESS;
503    }
504    ```
505
506-   Implement the factory method for creating the client proxy.
507
508    ```
509    void *DEMO_CreatClient(const char *service, const char *feature, uint32 size)
510    {
511        (void)service;
512        (void)feature;
513        uint32 len = size + sizeof(DemoClientEntry);
514        uint8 *client = malloc(len);
515        (void)memset_s(client, len, 0, len);
516        DemoClientEntry *entry = (DemoClientEntry *)&client[size];
517        entry->ver = ((uint16)CLIENT_PROXY_VER | (uint16)DEFAULT_VERSION);
518        entry->ref = 1;
519        entry->iUnknown.QueryInterface = IUNKNOWN_QueryInterface;
520        entry->iUnknown.AddRef = IUNKNOWN_AddRef;
521        entry->iUnknown.Release = IUNKNOWN_Release;
522        entry->iUnknown.Invoke = NULL;
523        entry->iUnknown.AsyncCall = AsyncCall;
524        entry->iUnknown.AsyncTimeCall = AsyncTimeCall;
525        entry->iUnknown.SyncCall = SyncCall;
526        entry->iUnknown.AsyncCallBack = AsyncCallBack;
527        return client;
528    }
529    void DEMO_DestroyClient(const char *service, const char *feature, void *iproxy)
530    {
531        free(iproxy);
532    }
533    ```
534
535-   Register the factory method of the client proxy with Samgr.
536
537    ```
538    SAMGR_RegisterFactory(EXAMPLE_SERVICE, EXAMPLE_FEATURE, DEMO_CreatClient, DEMO_DestroyClient);
539    ```
540
541-   Obtain the external API of the service in another process.
542
543    ```
544    DemoClientProxy *demoApi = NULL;
545    IUnknown *iUnknown = SAMGR_GetInstance()->GetFeatureApi(EXAMPLE_SERVICE, EXAMPLE_FEATURE);
546    if (iUnknown == NULL) {
547        return NULL;
548    }
549    int result = iUnknown->QueryInterface(iUnknown, DEFAULT_VERSION, (void **)&demoApi);
550    if (result != 0 || demoApi == NULL) {
551        return NULL;
552    }
553    ```
554
555-   Invoke the client proxy API of the service in another process.
556
557    ```
558    if (demoApi->AsyncCallBack == NULL) {
559        return NULL;
560    }
561    demoApi->AsyncCallBack((IUnknown *)demoApi,
562                           "I wanna async call callback good result!", NULL, AsyncHandler);
563    ```
564
565-   Release the API.
566
567    ```
568    int32 ref = demoApi->Release((IUnknown *)demoApi);
569    ```
570
571
572## Repositories Involved
573
574Samgr
575
576[**systemabilitymgr\_samgr\_lite**](https://gitee.com/openharmony/systemabilitymgr_samgr_lite)
577
578[systemabilitymgr\_samgr](https://gitee.com/openharmony/systemabilitymgr_samgr)
579
580[systemabilitymgr\_safwk](https://gitee.com/openharmony/systemabilitymgr_safwk)
581
582[systemabilitymgr\_safwk\_lite](https://gitee.com/openharmony/systemabilitymgr_safwk_lite)
583