Loading src/java/com/android/internal/telephony/ims/ImsResolver.java +9 −2 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.content.pm.ServiceInfo; import android.os.AsyncResult; import android.os.Handler; import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; Loading Loading @@ -130,6 +131,7 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal // Delay between dynamic ImsService queries. private static final int DELAY_DYNAMIC_QUERY_MS = 5000; private static final HandlerThread sHandlerThread = new HandlerThread(TAG); private static ImsResolver sInstance; Loading @@ -139,9 +141,9 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal public static void make(Context context, String defaultMmTelPackageName, String defaultRcsPackageName, int numSlots, ImsFeatureBinderRepository repo) { if (sInstance == null) { Looper looper = Looper.getMainLooper(); sHandlerThread.start(); sInstance = new ImsResolver(context, defaultMmTelPackageName, defaultRcsPackageName, numSlots, repo, looper); numSlots, repo, sHandlerThread.getLooper()); } } Loading Loading @@ -630,8 +632,13 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal /** * Needs to be called after the constructor to kick off the process of binding to ImsServices. * Should be run on the handler thread of ImsResolver */ public void initialize() { mHandler.post(()-> initializeInternal()); } private void initializeInternal() { mEventLog.log("Initializing"); Log.i(TAG, "Initializing cache."); PhoneConfigurationManager.registerForMultiSimConfigChange(mHandler, Loading tests/telephonytests/src/com/android/internal/telephony/ims/ImsResolverTest.java +12 −1 Original line number Diff line number Diff line Loading @@ -956,7 +956,7 @@ public class ImsResolverTest extends ImsTestBase { carrierFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, ImsFeature.FEATURE_RCS)); // Assume that there is a CarrierConfig change that kicks off query to carrier service. sendCarrierConfigChanged(1, 1); setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, carrierFeatures, 2); setupDynamicQueryFeaturesMultiSim(TEST_CARRIER_DEFAULT_NAME, carrierFeatures, 2); verify(carrierController).changeImsServiceFeatures(eq(carrierFeatures), any(SparseIntArray.class)); deviceFeatureSet = convertToHashSet(deviceFeatures, 0); Loading Loading @@ -2021,6 +2021,7 @@ public class ImsResolverTest extends ImsTestBase { */ private void startBindCarrierConfigAlreadySet() { mTestImsResolver.initialize(); processAllMessages(); ArgumentCaptor<BroadcastReceiver> receiversCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class); verify(mMockContext, times(3)).registerReceiver(receiversCaptor.capture(), any()); Loading @@ -2042,6 +2043,7 @@ public class ImsResolverTest extends ImsTestBase { */ private void startBindNoCarrierConfig(int numSlots) { mTestImsResolver.initialize(); processAllMessages(); ArgumentCaptor<BroadcastReceiver> receiversCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class); verify(mMockContext, times(3)).registerReceiver(receiversCaptor.capture(), any()); Loading @@ -2068,6 +2070,15 @@ public class ImsResolverTest extends ImsTestBase { processAllMessages(); } private void setupDynamicQueryFeaturesMultiSim(ComponentName name, HashSet<ImsFeatureConfiguration.FeatureSlotPair> features, int times) { processAllFutureMessages(); // ensure that startQuery was called verify(mMockQueryManager, times(times)).startQuery(eq(name), any(String.class)); mDynamicQueryListener.onComplete(name, features); processAllMessages(); } private void setupDynamicQueryFeaturesFailure(ComponentName name, int times) { processAllMessages(); // ensure that startQuery was called Loading tests/telephonytests/src/com/android/internal/telephony/ims/ImsTestBase.java +89 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ import static org.junit.Assert.fail; import android.content.Context; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.MessageQueue; import android.testing.TestableLooper; import androidx.test.InstrumentationRegistry; Loading @@ -29,6 +31,7 @@ import com.android.internal.telephony.TelephonyTest; import org.mockito.MockitoAnnotations; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; Loading @@ -38,6 +41,22 @@ import java.util.concurrent.TimeUnit; * Helper class to load Mockito Resources into a test. */ public class ImsTestBase { private static final Field MESSAGE_QUEUE_FIELD; private static final Field MESSAGE_WHEN_FIELD; private static final Field MESSAGE_NEXT_FIELD; static { try { MESSAGE_QUEUE_FIELD = MessageQueue.class.getDeclaredField("mMessages"); MESSAGE_QUEUE_FIELD.setAccessible(true); MESSAGE_WHEN_FIELD = Message.class.getDeclaredField("when"); MESSAGE_WHEN_FIELD.setAccessible(true); MESSAGE_NEXT_FIELD = Message.class.getDeclaredField("next"); MESSAGE_NEXT_FIELD.setAccessible(true); } catch (NoSuchFieldException e) { throw new RuntimeException("Failed to initialize TelephonyTest", e); } } protected Context mContext; protected List<TestableLooper> mTestableLoopers = new ArrayList<>(); Loading Loading @@ -111,6 +130,52 @@ public class ImsTestBase { } } /** * @return The longest delay from all the message queues. */ private long getLongestDelay() { long delay = 0; for (TestableLooper looper : mTestableLoopers) { MessageQueue queue = looper.getLooper().getQueue(); try { Message msg = (Message) MESSAGE_QUEUE_FIELD.get(queue); while (msg != null) { delay = Math.max(msg.getWhen(), delay); msg = (Message) MESSAGE_NEXT_FIELD.get(msg); } } catch (IllegalAccessException e) { throw new RuntimeException("Access failed in TelephonyTest", e); } } return delay; } /** * @return {@code true} if there are any messages in the queue. */ private boolean messagesExist() { for (TestableLooper looper : mTestableLoopers) { MessageQueue queue = looper.getLooper().getQueue(); try { Message msg = (Message) MESSAGE_QUEUE_FIELD.get(queue); if (msg != null) return true; } catch (IllegalAccessException e) { throw new RuntimeException("Access failed in TelephonyTest", e); } } return false; } /** * Handle all messages including the delayed messages. */ public void processAllFutureMessages() { while (messagesExist()) { moveTimeForward(getLongestDelay()); processAllMessages(); } } /** * Check if there are any messages to be processed in any monitored TestableLooper * Delayed messages to be handled at a later time will be ignored Loading @@ -123,4 +188,28 @@ public class ImsTestBase { } return true; } /** * Effectively moves time forward by reducing the time of all messages * for all monitored TestableLoopers * @param milliSeconds number of milliseconds to move time forward by */ public void moveTimeForward(long milliSeconds) { for (TestableLooper looper : mTestableLoopers) { MessageQueue queue = looper.getLooper().getQueue(); try { Message msg = (Message) MESSAGE_QUEUE_FIELD.get(queue); while (msg != null) { long updatedWhen = msg.getWhen() - milliSeconds; if (updatedWhen < 0) { updatedWhen = 0; } MESSAGE_WHEN_FIELD.set(msg, updatedWhen); msg = (Message) MESSAGE_NEXT_FIELD.get(msg); } } catch (IllegalAccessException e) { throw new RuntimeException("Access failed in TelephonyTest", e); } } } } Loading
src/java/com/android/internal/telephony/ims/ImsResolver.java +9 −2 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.content.pm.ServiceInfo; import android.os.AsyncResult; import android.os.Handler; import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; Loading Loading @@ -130,6 +131,7 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal // Delay between dynamic ImsService queries. private static final int DELAY_DYNAMIC_QUERY_MS = 5000; private static final HandlerThread sHandlerThread = new HandlerThread(TAG); private static ImsResolver sInstance; Loading @@ -139,9 +141,9 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal public static void make(Context context, String defaultMmTelPackageName, String defaultRcsPackageName, int numSlots, ImsFeatureBinderRepository repo) { if (sInstance == null) { Looper looper = Looper.getMainLooper(); sHandlerThread.start(); sInstance = new ImsResolver(context, defaultMmTelPackageName, defaultRcsPackageName, numSlots, repo, looper); numSlots, repo, sHandlerThread.getLooper()); } } Loading Loading @@ -630,8 +632,13 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal /** * Needs to be called after the constructor to kick off the process of binding to ImsServices. * Should be run on the handler thread of ImsResolver */ public void initialize() { mHandler.post(()-> initializeInternal()); } private void initializeInternal() { mEventLog.log("Initializing"); Log.i(TAG, "Initializing cache."); PhoneConfigurationManager.registerForMultiSimConfigChange(mHandler, Loading
tests/telephonytests/src/com/android/internal/telephony/ims/ImsResolverTest.java +12 −1 Original line number Diff line number Diff line Loading @@ -956,7 +956,7 @@ public class ImsResolverTest extends ImsTestBase { carrierFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, ImsFeature.FEATURE_RCS)); // Assume that there is a CarrierConfig change that kicks off query to carrier service. sendCarrierConfigChanged(1, 1); setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, carrierFeatures, 2); setupDynamicQueryFeaturesMultiSim(TEST_CARRIER_DEFAULT_NAME, carrierFeatures, 2); verify(carrierController).changeImsServiceFeatures(eq(carrierFeatures), any(SparseIntArray.class)); deviceFeatureSet = convertToHashSet(deviceFeatures, 0); Loading Loading @@ -2021,6 +2021,7 @@ public class ImsResolverTest extends ImsTestBase { */ private void startBindCarrierConfigAlreadySet() { mTestImsResolver.initialize(); processAllMessages(); ArgumentCaptor<BroadcastReceiver> receiversCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class); verify(mMockContext, times(3)).registerReceiver(receiversCaptor.capture(), any()); Loading @@ -2042,6 +2043,7 @@ public class ImsResolverTest extends ImsTestBase { */ private void startBindNoCarrierConfig(int numSlots) { mTestImsResolver.initialize(); processAllMessages(); ArgumentCaptor<BroadcastReceiver> receiversCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class); verify(mMockContext, times(3)).registerReceiver(receiversCaptor.capture(), any()); Loading @@ -2068,6 +2070,15 @@ public class ImsResolverTest extends ImsTestBase { processAllMessages(); } private void setupDynamicQueryFeaturesMultiSim(ComponentName name, HashSet<ImsFeatureConfiguration.FeatureSlotPair> features, int times) { processAllFutureMessages(); // ensure that startQuery was called verify(mMockQueryManager, times(times)).startQuery(eq(name), any(String.class)); mDynamicQueryListener.onComplete(name, features); processAllMessages(); } private void setupDynamicQueryFeaturesFailure(ComponentName name, int times) { processAllMessages(); // ensure that startQuery was called Loading
tests/telephonytests/src/com/android/internal/telephony/ims/ImsTestBase.java +89 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ import static org.junit.Assert.fail; import android.content.Context; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.MessageQueue; import android.testing.TestableLooper; import androidx.test.InstrumentationRegistry; Loading @@ -29,6 +31,7 @@ import com.android.internal.telephony.TelephonyTest; import org.mockito.MockitoAnnotations; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; Loading @@ -38,6 +41,22 @@ import java.util.concurrent.TimeUnit; * Helper class to load Mockito Resources into a test. */ public class ImsTestBase { private static final Field MESSAGE_QUEUE_FIELD; private static final Field MESSAGE_WHEN_FIELD; private static final Field MESSAGE_NEXT_FIELD; static { try { MESSAGE_QUEUE_FIELD = MessageQueue.class.getDeclaredField("mMessages"); MESSAGE_QUEUE_FIELD.setAccessible(true); MESSAGE_WHEN_FIELD = Message.class.getDeclaredField("when"); MESSAGE_WHEN_FIELD.setAccessible(true); MESSAGE_NEXT_FIELD = Message.class.getDeclaredField("next"); MESSAGE_NEXT_FIELD.setAccessible(true); } catch (NoSuchFieldException e) { throw new RuntimeException("Failed to initialize TelephonyTest", e); } } protected Context mContext; protected List<TestableLooper> mTestableLoopers = new ArrayList<>(); Loading Loading @@ -111,6 +130,52 @@ public class ImsTestBase { } } /** * @return The longest delay from all the message queues. */ private long getLongestDelay() { long delay = 0; for (TestableLooper looper : mTestableLoopers) { MessageQueue queue = looper.getLooper().getQueue(); try { Message msg = (Message) MESSAGE_QUEUE_FIELD.get(queue); while (msg != null) { delay = Math.max(msg.getWhen(), delay); msg = (Message) MESSAGE_NEXT_FIELD.get(msg); } } catch (IllegalAccessException e) { throw new RuntimeException("Access failed in TelephonyTest", e); } } return delay; } /** * @return {@code true} if there are any messages in the queue. */ private boolean messagesExist() { for (TestableLooper looper : mTestableLoopers) { MessageQueue queue = looper.getLooper().getQueue(); try { Message msg = (Message) MESSAGE_QUEUE_FIELD.get(queue); if (msg != null) return true; } catch (IllegalAccessException e) { throw new RuntimeException("Access failed in TelephonyTest", e); } } return false; } /** * Handle all messages including the delayed messages. */ public void processAllFutureMessages() { while (messagesExist()) { moveTimeForward(getLongestDelay()); processAllMessages(); } } /** * Check if there are any messages to be processed in any monitored TestableLooper * Delayed messages to be handled at a later time will be ignored Loading @@ -123,4 +188,28 @@ public class ImsTestBase { } return true; } /** * Effectively moves time forward by reducing the time of all messages * for all monitored TestableLoopers * @param milliSeconds number of milliseconds to move time forward by */ public void moveTimeForward(long milliSeconds) { for (TestableLooper looper : mTestableLoopers) { MessageQueue queue = looper.getLooper().getQueue(); try { Message msg = (Message) MESSAGE_QUEUE_FIELD.get(queue); while (msg != null) { long updatedWhen = msg.getWhen() - milliSeconds; if (updatedWhen < 0) { updatedWhen = 0; } MESSAGE_WHEN_FIELD.set(msg, updatedWhen); msg = (Message) MESSAGE_NEXT_FIELD.get(msg); } } catch (IllegalAccessException e) { throw new RuntimeException("Access failed in TelephonyTest", e); } } } }