Loading flags/carrier.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -30,3 +30,14 @@ flag { description: "Enable temporary failures in CarrierMessagingService" bug:"326610112" } # OWNER=melhuishj TARGET=25Q3 flag { name: "disable_carrier_network_change_on_carrier_app_lost" namespace: "telephony" description: "Set carrier network change status to false whenever the carrier app is lost" bug:"333571417" metadata { purpose: PURPOSE_BUGFIX } } src/java/com/android/internal/telephony/CarrierServiceBindHelper.java +29 −1 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.os.UserHandle; import android.service.carrier.CarrierService; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.TelephonyRegistryManager; import android.text.TextUtils; import android.util.LocalLog; import android.util.Log; Loading Loading @@ -335,7 +336,7 @@ public class CarrierServiceBindHelper { bindCount++; lastBindStartMillis = System.currentTimeMillis(); connection = new CarrierServiceConnection(); connection = new CarrierServiceConnection(getPhoneId()); String error; try { Loading Loading @@ -431,6 +432,11 @@ public class CarrierServiceBindHelper { private class CarrierServiceConnection implements ServiceConnection { private boolean connected; private final int mPhoneId; CarrierServiceConnection(int phoneId) { mPhoneId = phoneId; } @Override public void onServiceConnected(ComponentName name, IBinder service) { Loading @@ -438,16 +444,38 @@ public class CarrierServiceBindHelper { connected = true; } private void maybeDisableCarrierNetworkChangeNotification() { int subscriptionId = SubscriptionManager.getSubscriptionId(mPhoneId); // TODO(b/117525047): switch to phoneId-based solution when available in // TelephonyRegistryManager to address SIM remove/disable case. if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { logdWithLocalLog( "No valid subscription found when trying to disable carrierNetworkChange" + " for phoneId: " + mPhoneId); return; } TelephonyRegistryManager telephonyRegistryManager = mContext.getSystemService(TelephonyRegistryManager.class); telephonyRegistryManager.notifyCarrierNetworkChange(subscriptionId, false); } @Override public void onServiceDisconnected(ComponentName name) { logdWithLocalLog("Disconnected from carrier app: " + name.flattenToString()); connected = false; if (Flags.disableCarrierNetworkChangeOnCarrierAppLost()) { maybeDisableCarrierNetworkChangeNotification(); } } @Override public void onBindingDied(ComponentName name) { logdWithLocalLog("Binding from carrier app died: " + name.flattenToString()); connected = false; if (Flags.disableCarrierNetworkChangeOnCarrierAppLost()) { maybeDisableCarrierNetworkChangeNotification(); } } @Override Loading tests/telephonytests/src/com/android/internal/telephony/CarrierServiceBindHelperTest.java +137 −11 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.internal.telephony; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.any; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doReturn; Loading @@ -25,18 +26,30 @@ import static org.mockito.Mockito.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Bundle; import android.os.Message; import android.service.carrier.CarrierService; import android.service.carrier.ICarrierService; import android.telephony.TelephonyManager.CarrierPrivilegesCallback; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import androidx.test.filters.SmallTest; import com.android.internal.telephony.flags.Flags; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper Loading Loading @@ -101,6 +114,16 @@ public class CarrierServiceBindHelperTest extends TelephonyTest { new Integer(0))); } // Verify a CarrierPrivilegesCallback is registered and return the callback object. May return // null if no callback is captured. private CarrierPrivilegesCallback expectRegisterCarrierPrivilegesCallback(int phoneId) { ArgumentCaptor<CarrierPrivilegesCallback> callbackCaptor = ArgumentCaptor.forClass(CarrierPrivilegesCallback.class); verify(mTelephonyManager) .registerCarrierPrivilegesCallback(eq(phoneId), any(), callbackCaptor.capture()); return callbackCaptor.getAllValues().get(0); } @Test public void testCarrierPrivilegesCallbackRegistration() { // Device starts with DSDS mode Loading @@ -110,18 +133,11 @@ public class CarrierServiceBindHelperTest extends TelephonyTest { // Verify that CarrierPrivilegesCallbacks are registered on both phones. // Capture the callbacks for further verification ArgumentCaptor<CarrierPrivilegesCallback> phone0CallbackCaptor = ArgumentCaptor.forClass( CarrierPrivilegesCallback.class); verify(mTelephonyManager).registerCarrierPrivilegesCallback(eq(PHONE_ID_0), any(), phone0CallbackCaptor.capture()); CarrierPrivilegesCallback phone0Callback = phone0CallbackCaptor.getAllValues().get(0); CarrierPrivilegesCallback phone0Callback = expectRegisterCarrierPrivilegesCallback(PHONE_ID_0); assertNotNull(phone0Callback); ArgumentCaptor<CarrierPrivilegesCallback> phone1CallbackCaptor = ArgumentCaptor.forClass( CarrierPrivilegesCallback.class); verify(mTelephonyManager).registerCarrierPrivilegesCallback(eq(PHONE_ID_1), any(), phone1CallbackCaptor.capture()); CarrierPrivilegesCallback phone1Callback = phone1CallbackCaptor.getAllValues().get(0); CarrierPrivilegesCallback phone1Callback = expectRegisterCarrierPrivilegesCallback(PHONE_ID_1); assertNotNull(phone1Callback); // Switch back to single SIM. Loading @@ -133,5 +149,115 @@ public class CarrierServiceBindHelperTest extends TelephonyTest { verify(mTelephonyManager).unregisterCarrierPrivilegesCallback(eq(phone1Callback)); verify(mTelephonyManager, never()).unregisterCarrierPrivilegesCallback(eq(phone0Callback)); } @Test public void testCarrierAppConnectionLost_resetsCarrierNetworkChange() { if (!Flags.disableCarrierNetworkChangeOnCarrierAppLost()) { return; } // Static test data String carrierServicePackageName = "android.test.package.carrier"; ComponentName carrierServiceComponentName = new ComponentName("android.test.package", "carrier"); ArgumentCaptor<ServiceConnection> serviceConnectionCaptor = ArgumentCaptor.forClass(ServiceConnection.class); ResolveInfo resolveInfo = new ResolveInfo(); ServiceInfo serviceInfo = new ServiceInfo(); serviceInfo.packageName = carrierServicePackageName; serviceInfo.name = "carrier"; serviceInfo.metaData = new Bundle(); serviceInfo.metaData.putBoolean("android.service.carrier.LONG_LIVED_BINDING", true); resolveInfo.serviceInfo = serviceInfo; // Set up expectations for construction/initialization. doReturn(carrierServicePackageName) .when(mTelephonyManager) .getCarrierServicePackageNameForLogicalSlot(PHONE_ID_0); doReturn(1).when(mTelephonyManager).getActiveModemCount(); doReturn(resolveInfo) .when(mPackageManager) .resolveService(any(), eq(PackageManager.GET_META_DATA)); ICarrierService carrierServiceInterface = Mockito.mock(ICarrierService.class); mContextFixture.addService( CarrierService.CARRIER_SERVICE_INTERFACE, carrierServiceComponentName, carrierServicePackageName, carrierServiceInterface, serviceInfo); mCarrierServiceBindHelper = new CarrierServiceBindHelper(mContext); processAllMessages(); CarrierPrivilegesCallback phoneCallback = expectRegisterCarrierPrivilegesCallback(PHONE_ID_0); assertNotNull(phoneCallback); phoneCallback.onCarrierServiceChanged(null, 0); processAllMessages(); // Grab the ServiceConnection for CarrierService verify(mContext) .bindService(any(Intent.class), anyInt(), any(), serviceConnectionCaptor.capture()); ServiceConnection serviceConnection = serviceConnectionCaptor.getAllValues().get(0); assertNotNull(serviceConnection); // Test CarrierService disconnection serviceConnection.onServiceDisconnected(carrierServiceComponentName); verify(mTelephonyRegistryManager).notifyCarrierNetworkChange(PHONE_ID_0, false); } @Test public void testCarrierAppBindingLost_resetsCarrierNetworkChange() { if (!Flags.disableCarrierNetworkChangeOnCarrierAppLost()) { return; } // Static test data String carrierServicePackageName = "android.test.package.carrier"; ComponentName carrierServiceComponentName = new ComponentName("android.test.package", "carrier"); ArgumentCaptor<ServiceConnection> serviceConnectionCaptor = ArgumentCaptor.forClass(ServiceConnection.class); ResolveInfo resolveInfo = new ResolveInfo(); ServiceInfo serviceInfo = new ServiceInfo(); serviceInfo.packageName = carrierServicePackageName; serviceInfo.name = "carrier"; serviceInfo.metaData = new Bundle(); serviceInfo.metaData.putBoolean("android.service.carrier.LONG_LIVED_BINDING", true); resolveInfo.serviceInfo = serviceInfo; // Set up expectations for construction/initialization. doReturn(carrierServicePackageName) .when(mTelephonyManager) .getCarrierServicePackageNameForLogicalSlot(PHONE_ID_0); doReturn(1).when(mTelephonyManager).getActiveModemCount(); doReturn(resolveInfo) .when(mPackageManager) .resolveService(any(), eq(PackageManager.GET_META_DATA)); ICarrierService carrierServiceInterface = Mockito.mock(ICarrierService.class); mContextFixture.addService( CarrierService.CARRIER_SERVICE_INTERFACE, carrierServiceComponentName, carrierServicePackageName, carrierServiceInterface, serviceInfo); mCarrierServiceBindHelper = new CarrierServiceBindHelper(mContext); processAllMessages(); CarrierPrivilegesCallback phoneCallback = expectRegisterCarrierPrivilegesCallback(PHONE_ID_0); assertNotNull(phoneCallback); phoneCallback.onCarrierServiceChanged(null, 0); processAllMessages(); // Grab the ServiceConnection for CarrierService verify(mContext) .bindService(any(Intent.class), anyInt(), any(), serviceConnectionCaptor.capture()); ServiceConnection serviceConnection = serviceConnectionCaptor.getAllValues().get(0); assertNotNull(serviceConnection); // Test CarrierService disconnection serviceConnection.onBindingDied(carrierServiceComponentName); verify(mTelephonyRegistryManager).notifyCarrierNetworkChange(PHONE_ID_0, false); } // TODO (b/232461097): Add UT cases to cover more scenarios (user unlock, SIM state change...) } tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java +20 −3 Original line number Diff line number Diff line Loading @@ -105,6 +105,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.Executor; /** * Controls a test {@link Context} as would be provided by the Android framework to an Loading Loading @@ -226,20 +227,36 @@ public class ContextFixture implements TestFixture<Context> { if (mServiceByServiceConnection.containsKey(connection)) { throw new RuntimeException("ServiceConnection already bound: " + connection); } IInterface service = mServiceByComponentName.get(serviceIntent.getComponent()); IInterface service = null; if (serviceIntent.getComponent() != null) { service = mServiceByComponentName.get(serviceIntent.getComponent()); } if (service == null) { service = mServiceByPackageName.get(serviceIntent.getPackage()); } if (service == null) { throw new RuntimeException( String.format("ServiceConnection not found for component: %s, package: %s", String.format( "ServiceConnection not found for component: %s, package: %s", serviceIntent.getComponent(), serviceIntent.getPackage())); } mServiceByServiceConnection.put(connection, service); connection.onServiceConnected(serviceIntent.getComponent(), service.asBinder()); ComponentName componentName = null; if (mComponentNameByService.containsKey(service)) { componentName = mComponentNameByService.get(service); } else { componentName = serviceIntent.getComponent(); } connection.onServiceConnected(componentName, service.asBinder()); return true; } @Override public boolean bindService( Intent serviceIntent, int flags, Executor executor, ServiceConnection connection) { return bindService(serviceIntent, connection, flags); } @Override public boolean bindServiceAsUser( Intent serviceIntent, Loading Loading
flags/carrier.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -30,3 +30,14 @@ flag { description: "Enable temporary failures in CarrierMessagingService" bug:"326610112" } # OWNER=melhuishj TARGET=25Q3 flag { name: "disable_carrier_network_change_on_carrier_app_lost" namespace: "telephony" description: "Set carrier network change status to false whenever the carrier app is lost" bug:"333571417" metadata { purpose: PURPOSE_BUGFIX } }
src/java/com/android/internal/telephony/CarrierServiceBindHelper.java +29 −1 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.os.UserHandle; import android.service.carrier.CarrierService; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.TelephonyRegistryManager; import android.text.TextUtils; import android.util.LocalLog; import android.util.Log; Loading Loading @@ -335,7 +336,7 @@ public class CarrierServiceBindHelper { bindCount++; lastBindStartMillis = System.currentTimeMillis(); connection = new CarrierServiceConnection(); connection = new CarrierServiceConnection(getPhoneId()); String error; try { Loading Loading @@ -431,6 +432,11 @@ public class CarrierServiceBindHelper { private class CarrierServiceConnection implements ServiceConnection { private boolean connected; private final int mPhoneId; CarrierServiceConnection(int phoneId) { mPhoneId = phoneId; } @Override public void onServiceConnected(ComponentName name, IBinder service) { Loading @@ -438,16 +444,38 @@ public class CarrierServiceBindHelper { connected = true; } private void maybeDisableCarrierNetworkChangeNotification() { int subscriptionId = SubscriptionManager.getSubscriptionId(mPhoneId); // TODO(b/117525047): switch to phoneId-based solution when available in // TelephonyRegistryManager to address SIM remove/disable case. if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { logdWithLocalLog( "No valid subscription found when trying to disable carrierNetworkChange" + " for phoneId: " + mPhoneId); return; } TelephonyRegistryManager telephonyRegistryManager = mContext.getSystemService(TelephonyRegistryManager.class); telephonyRegistryManager.notifyCarrierNetworkChange(subscriptionId, false); } @Override public void onServiceDisconnected(ComponentName name) { logdWithLocalLog("Disconnected from carrier app: " + name.flattenToString()); connected = false; if (Flags.disableCarrierNetworkChangeOnCarrierAppLost()) { maybeDisableCarrierNetworkChangeNotification(); } } @Override public void onBindingDied(ComponentName name) { logdWithLocalLog("Binding from carrier app died: " + name.flattenToString()); connected = false; if (Flags.disableCarrierNetworkChangeOnCarrierAppLost()) { maybeDisableCarrierNetworkChangeNotification(); } } @Override Loading
tests/telephonytests/src/com/android/internal/telephony/CarrierServiceBindHelperTest.java +137 −11 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.internal.telephony; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.any; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doReturn; Loading @@ -25,18 +26,30 @@ import static org.mockito.Mockito.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Bundle; import android.os.Message; import android.service.carrier.CarrierService; import android.service.carrier.ICarrierService; import android.telephony.TelephonyManager.CarrierPrivilegesCallback; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import androidx.test.filters.SmallTest; import com.android.internal.telephony.flags.Flags; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper Loading Loading @@ -101,6 +114,16 @@ public class CarrierServiceBindHelperTest extends TelephonyTest { new Integer(0))); } // Verify a CarrierPrivilegesCallback is registered and return the callback object. May return // null if no callback is captured. private CarrierPrivilegesCallback expectRegisterCarrierPrivilegesCallback(int phoneId) { ArgumentCaptor<CarrierPrivilegesCallback> callbackCaptor = ArgumentCaptor.forClass(CarrierPrivilegesCallback.class); verify(mTelephonyManager) .registerCarrierPrivilegesCallback(eq(phoneId), any(), callbackCaptor.capture()); return callbackCaptor.getAllValues().get(0); } @Test public void testCarrierPrivilegesCallbackRegistration() { // Device starts with DSDS mode Loading @@ -110,18 +133,11 @@ public class CarrierServiceBindHelperTest extends TelephonyTest { // Verify that CarrierPrivilegesCallbacks are registered on both phones. // Capture the callbacks for further verification ArgumentCaptor<CarrierPrivilegesCallback> phone0CallbackCaptor = ArgumentCaptor.forClass( CarrierPrivilegesCallback.class); verify(mTelephonyManager).registerCarrierPrivilegesCallback(eq(PHONE_ID_0), any(), phone0CallbackCaptor.capture()); CarrierPrivilegesCallback phone0Callback = phone0CallbackCaptor.getAllValues().get(0); CarrierPrivilegesCallback phone0Callback = expectRegisterCarrierPrivilegesCallback(PHONE_ID_0); assertNotNull(phone0Callback); ArgumentCaptor<CarrierPrivilegesCallback> phone1CallbackCaptor = ArgumentCaptor.forClass( CarrierPrivilegesCallback.class); verify(mTelephonyManager).registerCarrierPrivilegesCallback(eq(PHONE_ID_1), any(), phone1CallbackCaptor.capture()); CarrierPrivilegesCallback phone1Callback = phone1CallbackCaptor.getAllValues().get(0); CarrierPrivilegesCallback phone1Callback = expectRegisterCarrierPrivilegesCallback(PHONE_ID_1); assertNotNull(phone1Callback); // Switch back to single SIM. Loading @@ -133,5 +149,115 @@ public class CarrierServiceBindHelperTest extends TelephonyTest { verify(mTelephonyManager).unregisterCarrierPrivilegesCallback(eq(phone1Callback)); verify(mTelephonyManager, never()).unregisterCarrierPrivilegesCallback(eq(phone0Callback)); } @Test public void testCarrierAppConnectionLost_resetsCarrierNetworkChange() { if (!Flags.disableCarrierNetworkChangeOnCarrierAppLost()) { return; } // Static test data String carrierServicePackageName = "android.test.package.carrier"; ComponentName carrierServiceComponentName = new ComponentName("android.test.package", "carrier"); ArgumentCaptor<ServiceConnection> serviceConnectionCaptor = ArgumentCaptor.forClass(ServiceConnection.class); ResolveInfo resolveInfo = new ResolveInfo(); ServiceInfo serviceInfo = new ServiceInfo(); serviceInfo.packageName = carrierServicePackageName; serviceInfo.name = "carrier"; serviceInfo.metaData = new Bundle(); serviceInfo.metaData.putBoolean("android.service.carrier.LONG_LIVED_BINDING", true); resolveInfo.serviceInfo = serviceInfo; // Set up expectations for construction/initialization. doReturn(carrierServicePackageName) .when(mTelephonyManager) .getCarrierServicePackageNameForLogicalSlot(PHONE_ID_0); doReturn(1).when(mTelephonyManager).getActiveModemCount(); doReturn(resolveInfo) .when(mPackageManager) .resolveService(any(), eq(PackageManager.GET_META_DATA)); ICarrierService carrierServiceInterface = Mockito.mock(ICarrierService.class); mContextFixture.addService( CarrierService.CARRIER_SERVICE_INTERFACE, carrierServiceComponentName, carrierServicePackageName, carrierServiceInterface, serviceInfo); mCarrierServiceBindHelper = new CarrierServiceBindHelper(mContext); processAllMessages(); CarrierPrivilegesCallback phoneCallback = expectRegisterCarrierPrivilegesCallback(PHONE_ID_0); assertNotNull(phoneCallback); phoneCallback.onCarrierServiceChanged(null, 0); processAllMessages(); // Grab the ServiceConnection for CarrierService verify(mContext) .bindService(any(Intent.class), anyInt(), any(), serviceConnectionCaptor.capture()); ServiceConnection serviceConnection = serviceConnectionCaptor.getAllValues().get(0); assertNotNull(serviceConnection); // Test CarrierService disconnection serviceConnection.onServiceDisconnected(carrierServiceComponentName); verify(mTelephonyRegistryManager).notifyCarrierNetworkChange(PHONE_ID_0, false); } @Test public void testCarrierAppBindingLost_resetsCarrierNetworkChange() { if (!Flags.disableCarrierNetworkChangeOnCarrierAppLost()) { return; } // Static test data String carrierServicePackageName = "android.test.package.carrier"; ComponentName carrierServiceComponentName = new ComponentName("android.test.package", "carrier"); ArgumentCaptor<ServiceConnection> serviceConnectionCaptor = ArgumentCaptor.forClass(ServiceConnection.class); ResolveInfo resolveInfo = new ResolveInfo(); ServiceInfo serviceInfo = new ServiceInfo(); serviceInfo.packageName = carrierServicePackageName; serviceInfo.name = "carrier"; serviceInfo.metaData = new Bundle(); serviceInfo.metaData.putBoolean("android.service.carrier.LONG_LIVED_BINDING", true); resolveInfo.serviceInfo = serviceInfo; // Set up expectations for construction/initialization. doReturn(carrierServicePackageName) .when(mTelephonyManager) .getCarrierServicePackageNameForLogicalSlot(PHONE_ID_0); doReturn(1).when(mTelephonyManager).getActiveModemCount(); doReturn(resolveInfo) .when(mPackageManager) .resolveService(any(), eq(PackageManager.GET_META_DATA)); ICarrierService carrierServiceInterface = Mockito.mock(ICarrierService.class); mContextFixture.addService( CarrierService.CARRIER_SERVICE_INTERFACE, carrierServiceComponentName, carrierServicePackageName, carrierServiceInterface, serviceInfo); mCarrierServiceBindHelper = new CarrierServiceBindHelper(mContext); processAllMessages(); CarrierPrivilegesCallback phoneCallback = expectRegisterCarrierPrivilegesCallback(PHONE_ID_0); assertNotNull(phoneCallback); phoneCallback.onCarrierServiceChanged(null, 0); processAllMessages(); // Grab the ServiceConnection for CarrierService verify(mContext) .bindService(any(Intent.class), anyInt(), any(), serviceConnectionCaptor.capture()); ServiceConnection serviceConnection = serviceConnectionCaptor.getAllValues().get(0); assertNotNull(serviceConnection); // Test CarrierService disconnection serviceConnection.onBindingDied(carrierServiceComponentName); verify(mTelephonyRegistryManager).notifyCarrierNetworkChange(PHONE_ID_0, false); } // TODO (b/232461097): Add UT cases to cover more scenarios (user unlock, SIM state change...) }
tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java +20 −3 Original line number Diff line number Diff line Loading @@ -105,6 +105,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.Executor; /** * Controls a test {@link Context} as would be provided by the Android framework to an Loading Loading @@ -226,20 +227,36 @@ public class ContextFixture implements TestFixture<Context> { if (mServiceByServiceConnection.containsKey(connection)) { throw new RuntimeException("ServiceConnection already bound: " + connection); } IInterface service = mServiceByComponentName.get(serviceIntent.getComponent()); IInterface service = null; if (serviceIntent.getComponent() != null) { service = mServiceByComponentName.get(serviceIntent.getComponent()); } if (service == null) { service = mServiceByPackageName.get(serviceIntent.getPackage()); } if (service == null) { throw new RuntimeException( String.format("ServiceConnection not found for component: %s, package: %s", String.format( "ServiceConnection not found for component: %s, package: %s", serviceIntent.getComponent(), serviceIntent.getPackage())); } mServiceByServiceConnection.put(connection, service); connection.onServiceConnected(serviceIntent.getComponent(), service.asBinder()); ComponentName componentName = null; if (mComponentNameByService.containsKey(service)) { componentName = mComponentNameByService.get(service); } else { componentName = serviceIntent.getComponent(); } connection.onServiceConnected(componentName, service.asBinder()); return true; } @Override public boolean bindService( Intent serviceIntent, int flags, Executor executor, ServiceConnection connection) { return bindService(serviceIntent, connection, flags); } @Override public boolean bindServiceAsUser( Intent serviceIntent, Loading