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