xref: /aosp_15_r20/frameworks/base/packages/SettingsLib/Ipc/README.md (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker# Service IPC library
2*d57664e9SAndroid Build Coastguard Worker
3*d57664e9SAndroid Build Coastguard WorkerThis library provides a kind of IPC (inter-process communication) framework
4*d57664e9SAndroid Build Coastguard Workerbased on Android
5*d57664e9SAndroid Build Coastguard Worker[bound service](https://developer.android.com/develop/background-work/services/bound-services)
6*d57664e9SAndroid Build Coastguard Workerwith [Messenger](https://developer.android.com/reference/android/os/Messenger).
7*d57664e9SAndroid Build Coastguard Worker
8*d57664e9SAndroid Build Coastguard WorkerFollowing benefits are offered by the library to improve and simplify IPC
9*d57664e9SAndroid Build Coastguard Workerdevelopment:
10*d57664e9SAndroid Build Coastguard Worker
11*d57664e9SAndroid Build Coastguard Worker-   Enforce permission check for every API implementation to avoid security
12*d57664e9SAndroid Build Coastguard Worker    vulnerability.
13*d57664e9SAndroid Build Coastguard Worker-   Allow modular API development for better code maintenance (no more huge
14*d57664e9SAndroid Build Coastguard Worker    Service class).
15*d57664e9SAndroid Build Coastguard Worker-   Prevent common mistakes, e.g. Service context leaking, ServiceConnection
16*d57664e9SAndroid Build Coastguard Worker    management.
17*d57664e9SAndroid Build Coastguard Worker
18*d57664e9SAndroid Build Coastguard Worker## Overview
19*d57664e9SAndroid Build Coastguard Worker
20*d57664e9SAndroid Build Coastguard WorkerIn this manner of IPC,
21*d57664e9SAndroid Build Coastguard Worker[Service](https://developer.android.com/reference/android/app/Service) works
22*d57664e9SAndroid Build Coastguard Workerwith [Handler](https://developer.android.com/reference/android/os/Handler) to
23*d57664e9SAndroid Build Coastguard Workerdeal with different types of
24*d57664e9SAndroid Build Coastguard Worker[Message](https://developer.android.com/reference/android/os/Message) objects.
25*d57664e9SAndroid Build Coastguard Worker
26*d57664e9SAndroid Build Coastguard WorkerUnder the hood, each API is represented as a `Message` object:
27*d57664e9SAndroid Build Coastguard Worker
28*d57664e9SAndroid Build Coastguard Worker-   [what](https://developer.android.com/reference/android/os/Message#what):
29*d57664e9SAndroid Build Coastguard Worker    used to identify API.
30*d57664e9SAndroid Build Coastguard Worker-   [data](https://developer.android.com/reference/android/os/Message#getData\(\)):
31*d57664e9SAndroid Build Coastguard Worker    payload of the API parameters and result.
32*d57664e9SAndroid Build Coastguard Worker
33*d57664e9SAndroid Build Coastguard WorkerThis could be mapped to the `ApiHandler` interface abstraction exactly.
34*d57664e9SAndroid Build Coastguard WorkerSpecifically, the API implementation needs to provide:
35*d57664e9SAndroid Build Coastguard Worker
36*d57664e9SAndroid Build Coastguard Worker-   An unique id for the API.
37*d57664e9SAndroid Build Coastguard Worker-   How to marshall/unmarshall the request and response.
38*d57664e9SAndroid Build Coastguard Worker-   Whether the given request is permitted.
39*d57664e9SAndroid Build Coastguard Worker
40*d57664e9SAndroid Build Coastguard Worker## Threading model
41*d57664e9SAndroid Build Coastguard Worker
42*d57664e9SAndroid Build Coastguard Worker`MessengerService` starts a dedicated
43*d57664e9SAndroid Build Coastguard Worker[HandlerThread](https://developer.android.com/reference/android/os/HandlerThread)
44*d57664e9SAndroid Build Coastguard Workerto handle requests. `ApiHandler` implementation uses Kotlin `suspend`, which
45*d57664e9SAndroid Build Coastguard Workerallows flexible threading model on top of the
46*d57664e9SAndroid Build Coastguard Worker[Kotlin coroutines](https://kotlinlang.org/docs/coroutines-overview.html).
47*d57664e9SAndroid Build Coastguard Worker
48*d57664e9SAndroid Build Coastguard Worker## Usage
49*d57664e9SAndroid Build Coastguard Worker
50*d57664e9SAndroid Build Coastguard WorkerThe service provider should extend `MessengerService` and provide API
51*d57664e9SAndroid Build Coastguard Workerimplementations. In `AndroidManifest.xml`, declare `<service>` with permission,
52*d57664e9SAndroid Build Coastguard Workerintent filter, etc. if needed.
53*d57664e9SAndroid Build Coastguard Worker
54*d57664e9SAndroid Build Coastguard WorkerMeanwhile, the service client implements `MessengerServiceClient` with API
55*d57664e9SAndroid Build Coastguard Workerdescriptors to make requests.
56*d57664e9SAndroid Build Coastguard Worker
57*d57664e9SAndroid Build Coastguard WorkerHere is an example:
58*d57664e9SAndroid Build Coastguard Worker
59*d57664e9SAndroid Build Coastguard Worker```kotlin
60*d57664e9SAndroid Build Coastguard Workerimport android.app.Application
61*d57664e9SAndroid Build Coastguard Workerimport android.content.Context
62*d57664e9SAndroid Build Coastguard Workerimport android.content.Intent
63*d57664e9SAndroid Build Coastguard Workerimport android.os.Bundle
64*d57664e9SAndroid Build Coastguard Workerimport kotlinx.coroutines.runBlocking
65*d57664e9SAndroid Build Coastguard Worker
66*d57664e9SAndroid Build Coastguard Workerclass EchoService :
67*d57664e9SAndroid Build Coastguard Worker  MessengerService(
68*d57664e9SAndroid Build Coastguard Worker    listOf(EchoApiImpl),
69*d57664e9SAndroid Build Coastguard Worker    PermissionChecker { _, _, _ -> true },
70*d57664e9SAndroid Build Coastguard Worker  )
71*d57664e9SAndroid Build Coastguard Worker
72*d57664e9SAndroid Build Coastguard Workerclass EchoServiceClient(context: Context) : MessengerServiceClient(context) {
73*d57664e9SAndroid Build Coastguard Worker  override val serviceIntentFactory: () -> Intent
74*d57664e9SAndroid Build Coastguard Worker    get() = { Intent("example.intent.action.ECHO") }
75*d57664e9SAndroid Build Coastguard Worker
76*d57664e9SAndroid Build Coastguard Worker  fun echo(data: String?): String? =
77*d57664e9SAndroid Build Coastguard Worker    runBlocking { invoke(context.packageName, EchoApi, data).await() }
78*d57664e9SAndroid Build Coastguard Worker}
79*d57664e9SAndroid Build Coastguard Worker
80*d57664e9SAndroid Build Coastguard Workerobject EchoApi : ApiDescriptor<String?, String?> {
81*d57664e9SAndroid Build Coastguard Worker  private val codec =
82*d57664e9SAndroid Build Coastguard Worker    object : MessageCodec<String?> {
83*d57664e9SAndroid Build Coastguard Worker      override fun encode(data: String?) =
84*d57664e9SAndroid Build Coastguard Worker        Bundle(1).apply { putString("data", data) }
85*d57664e9SAndroid Build Coastguard Worker
86*d57664e9SAndroid Build Coastguard Worker      override fun decode(data: Bundle): String? = data.getString("data", null)
87*d57664e9SAndroid Build Coastguard Worker    }
88*d57664e9SAndroid Build Coastguard Worker
89*d57664e9SAndroid Build Coastguard Worker  override val id: Int
90*d57664e9SAndroid Build Coastguard Worker    get() = 1
91*d57664e9SAndroid Build Coastguard Worker
92*d57664e9SAndroid Build Coastguard Worker  override val requestCodec: MessageCodec<String?>
93*d57664e9SAndroid Build Coastguard Worker    get() = codec
94*d57664e9SAndroid Build Coastguard Worker
95*d57664e9SAndroid Build Coastguard Worker  override val responseCodec: MessageCodec<String?>
96*d57664e9SAndroid Build Coastguard Worker    get() = codec
97*d57664e9SAndroid Build Coastguard Worker}
98*d57664e9SAndroid Build Coastguard Worker
99*d57664e9SAndroid Build Coastguard Worker// This is not needed by EchoServiceClient.
100*d57664e9SAndroid Build Coastguard Workerobject EchoApiImpl : ApiHandler<String?, String?>,
101*d57664e9SAndroid Build Coastguard Worker                     ApiDescriptor<String?, String?> by EchoApi {
102*d57664e9SAndroid Build Coastguard Worker  override suspend fun invoke(
103*d57664e9SAndroid Build Coastguard Worker    application: Application,
104*d57664e9SAndroid Build Coastguard Worker    myUid: Int,
105*d57664e9SAndroid Build Coastguard Worker    callingUid: Int,
106*d57664e9SAndroid Build Coastguard Worker    request: String?,
107*d57664e9SAndroid Build Coastguard Worker  ): String? = request
108*d57664e9SAndroid Build Coastguard Worker
109*d57664e9SAndroid Build Coastguard Worker  override fun hasPermission(
110*d57664e9SAndroid Build Coastguard Worker    application: Application,
111*d57664e9SAndroid Build Coastguard Worker    myUid: Int,
112*d57664e9SAndroid Build Coastguard Worker    callingUid: Int,
113*d57664e9SAndroid Build Coastguard Worker    request: String?,
114*d57664e9SAndroid Build Coastguard Worker  ): Boolean = (request?.length ?: 0) <= 5
115*d57664e9SAndroid Build Coastguard Worker}
116*d57664e9SAndroid Build Coastguard Worker```
117