1 /* <lambda>null2 * Copyright 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.datastore.testapp.twoWayIpc 18 19 import android.content.Intent 20 import android.os.Handler 21 import android.os.IBinder 22 import android.os.Looper 23 import android.os.Message 24 import android.os.Messenger 25 import androidx.lifecycle.LifecycleService 26 import androidx.lifecycle.lifecycleScope 27 import kotlinx.coroutines.CoroutineScope 28 import kotlinx.coroutines.Dispatchers 29 import kotlinx.coroutines.Job 30 import kotlinx.coroutines.cancelAndJoin 31 import kotlinx.coroutines.launch 32 33 /** 34 * Another service of the same type, that runs in another separate process. 35 * 36 * @see TwoWayIpcService 37 */ 38 class TwoWayIpcService2 : TwoWayIpcService() 39 40 /** 41 * An Android [android.app.Service] implementation that can create and maintain multiple 42 * [TwoWayIpcSubject] instances. 43 * 44 * It properly scopes those subjects and destroys their scopes when the Service is destroyed, 45 * allowing tests to properly maintain resources. 46 * 47 * @see androidx.datastore.testapp.multiprocess.MultiProcessTestRule 48 */ 49 open class TwoWayIpcService : LifecycleService() { 50 private val subjects = mutableListOf<TwoWayIpcSubject>() 51 private val jobForSubjects = Job() 52 private val scopeForSubjects = CoroutineScope(jobForSubjects + Dispatchers.IO) 53 private val messenger: Messenger = 54 Messenger( 55 Handler(Looper.getMainLooper()) { incoming -> 56 // make a copy to prevent recycling 57 when (incoming.what) { 58 MSG_CREATE_SUBJECT -> { 59 val subject = TwoWayIpcSubject(scopeForSubjects).also { subjects.add(it) } 60 61 @Suppress("DEPRECATION") 62 val messenger = incoming.data.getParcelable<Messenger>("messenger") 63 checkNotNull(messenger) { "missing messenger" } 64 subject.bus.setOutgoingMessenger(messenger) 65 val response = 66 Message.obtain().also { 67 it.data.putParcelable("messenger", subject.bus.incomingMessenger) 68 } 69 incoming.replyTo.send(response) 70 } 71 MSG_DESTROY_SUBJECTS -> { 72 val incomingCopy = Message.obtain().also { it.copyFrom(incoming) } 73 lifecycleScope.launch { 74 IpcLogger.log("destroying subjects") 75 try { 76 jobForSubjects.cancelAndJoin() 77 IpcLogger.log("destroyed subjects") 78 } finally { 79 incomingCopy.replyTo.send( 80 Message.obtain().also { it.data.putBoolean("closed", true) } 81 ) 82 } 83 } 84 } 85 else -> error("unknown message type ${incoming.what}") 86 } 87 true 88 } 89 ) 90 91 override fun onBind(intent: Intent): IBinder? { 92 super.onBind(intent) 93 return messenger.binder 94 } 95 96 companion object { 97 const val MSG_CREATE_SUBJECT = 500 98 const val MSG_DESTROY_SUBJECTS = 501 99 } 100 } 101