Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5662eb44 authored by Hakjun Choi's avatar Hakjun Choi Committed by Automerger Merge Worker
Browse files

Merge "Separate running thread of ImsResolver's handler to prevent ANR" into udc-dev am: 4557a0bf

parents 4071f0b5 4557a0bf
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -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;
@@ -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;

@@ -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());
        }
    }

@@ -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,
+12 −1
Original line number Diff line number Diff line
@@ -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);
@@ -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());
@@ -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());
@@ -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
+89 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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<>();
@@ -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
@@ -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);
            }
        }
    }
}