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