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 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 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