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

Commit 35c5e745 authored by Marco Loaiza's avatar Marco Loaiza
Browse files

Update deviceId on non-ui contexts on last started activity

Adds deviceId to LaunchActivityItem so deviceId is updated
in Application and Service contexts on activity start.
Also passes deviceId in ConfigurationChangeItem to capture
process-level device-id changes.

Test: atest DeviceAssociationTest
Bug: 253201821
Change-Id: Ieb65a6c0945d95cda1b8a1fcec0c3ce8341f36c3
parent 0fa4a143
Loading
Loading
Loading
Loading
+49 −2
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ import android.app.servertransaction.ResumeActivityItem;
import android.app.servertransaction.TransactionExecutor;
import android.app.servertransaction.TransactionExecutorHelper;
import android.bluetooth.BluetoothFrameworkInitializer;
import android.companion.virtual.VirtualDeviceManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.AttributionSource;
import android.content.AutofillOptions;
@@ -361,6 +362,8 @@ public final class ActivityThread extends ClientTransactionHandler
    private int mLastProcessState = PROCESS_STATE_UNKNOWN;
    ArrayList<WeakReference<AssistStructure>> mLastAssistStructures = new ArrayList<>();
    private int mLastSessionId;
    // Holds the value of the last reported device ID value from the server for the top activity.
    int mLastReportedDeviceId;
    final ArrayMap<IBinder, CreateServiceData> mServicesData = new ArrayMap<>();
    @UnsupportedAppUsage
    final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();
@@ -546,6 +549,9 @@ public final class ActivityThread extends ClientTransactionHandler
        boolean hideForNow;
        Configuration createdConfig;
        Configuration overrideConfig;
        // TODO(b/263402465): pass deviceId directly in LaunchActivityItem#execute
        // The deviceId assigned by the server when this activity was first started.
        int mDeviceId;
        // Used for consolidating configs before sending on to Activity.
        private Configuration tmpConfig = new Configuration();
        // Callback used for updating activity override config and camera compat control state.
@@ -608,7 +614,7 @@ public final class ActivityThread extends ClientTransactionHandler
        }

        public ActivityClientRecord(IBinder token, Intent intent, int ident,
                ActivityInfo info, Configuration overrideConfig,
                ActivityInfo info, Configuration overrideConfig, int deviceId,
                String referrer, IVoiceInteractor voiceInteractor, Bundle state,
                PersistableBundle persistentState, List<ResultInfo> pendingResults,
                List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
@@ -630,6 +636,7 @@ public final class ActivityThread extends ClientTransactionHandler
            this.isForward = isForward;
            this.profilerInfo = profilerInfo;
            this.overrideConfig = overrideConfig;
            this.mDeviceId = deviceId;
            this.packageInfo = client.getPackageInfoNoCheck(activityInfo.applicationInfo);
            mActivityOptions = activityOptions;
            mLaunchedFromBubble = launchedFromBubble;
@@ -3816,6 +3823,7 @@ public final class ActivityThread extends ClientTransactionHandler

        // Make sure we are running with the most recent config.
        mConfigurationController.handleConfigurationChanged(null, null);
        updateDeviceIdForNonUIContexts(r.mDeviceId);

        if (localLOGV) Slog.v(
            TAG, "Handling launch of " + r);
@@ -6061,9 +6069,48 @@ public final class ActivityThread extends ClientTransactionHandler
        }
    }

    private void updateDeviceIdForNonUIContexts(int deviceId) {
        // Invalid device id is treated as a no-op.
        if (deviceId == VirtualDeviceManager.DEVICE_ID_INVALID) {
            return;
        }
        if (deviceId == mLastReportedDeviceId) {
            return;
        }
        mLastReportedDeviceId = deviceId;
        ArrayList<Context> nonUIContexts = new ArrayList<>();
        // Update Application and Service contexts with implicit device association.
        // UI Contexts are able to derived their device Id association from the display.
        synchronized (mResourcesManager) {
            final int numApps = mAllApplications.size();
            for (int i = 0; i < numApps; i++) {
                nonUIContexts.add(mAllApplications.get(i));
            }
            final int numServices = mServices.size();
            for (int i = 0; i < numServices; i++) {
                final Service service = mServices.valueAt(i);
                // WindowProviderService is a UI Context.
                if (!service.isUiContext()) {
                    nonUIContexts.add(service);
                }
            }
        }
        for (Context context : nonUIContexts) {
            try {
                context.updateDeviceId(deviceId);
            } catch (IllegalArgumentException e) {
                // It can happen that the system already closed/removed a virtual device
                // and the passed deviceId is no longer valid.
                // TODO(b/263355088): check for validity of deviceId before updating
                // instead of catching this exception once VDM add an API to validate ids.
            }
        }
    }

    @Override
    public void handleConfigurationChanged(Configuration config) {
    public void handleConfigurationChanged(Configuration config, int deviceId) {
        mConfigurationController.handleConfigurationChanged(config);
        updateDeviceIdForNonUIContexts(deviceId);

        // These are only done to maintain @UnsupportedAppUsage and should be removed someday.
        mCurDefaultDisplayDpi = mConfigurationController.getCurDefaultDisplayDpi();
+2 −2
Original line number Diff line number Diff line
@@ -181,8 +181,8 @@ public abstract class ClientTransactionHandler {
    /** Get package info. */
    public abstract LoadedApk getPackageInfoNoCheck(ApplicationInfo ai);

    /** Deliver app configuration change notification. */
    public abstract void handleConfigurationChanged(Configuration config);
    /** Deliver app configuration change notification and device association. */
    public abstract void handleConfigurationChanged(Configuration config, int deviceId);

    /**
     * Get {@link android.app.ActivityThread.ActivityClientRecord} instance that corresponds to the
+14 −5
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import java.util.Objects;
public class ConfigurationChangeItem extends ClientTransactionItem {

    private Configuration mConfiguration;
    private int mDeviceId;

    @Override
    public void preExecute(android.app.ClientTransactionHandler client, IBinder token) {
@@ -42,7 +43,7 @@ public class ConfigurationChangeItem extends ClientTransactionItem {
    @Override
    public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        client.handleConfigurationChanged(mConfiguration);
        client.handleConfigurationChanged(mConfiguration, mDeviceId);
    }


@@ -51,12 +52,13 @@ public class ConfigurationChangeItem extends ClientTransactionItem {
    private ConfigurationChangeItem() {}

    /** Obtain an instance initialized with provided params. */
    public static ConfigurationChangeItem obtain(Configuration config) {
    public static ConfigurationChangeItem obtain(Configuration config, int deviceId) {
        ConfigurationChangeItem instance = ObjectPool.obtain(ConfigurationChangeItem.class);
        if (instance == null) {
            instance = new ConfigurationChangeItem();
        }
        instance.mConfiguration = config;
        instance.mDeviceId = deviceId;

        return instance;
    }
@@ -64,6 +66,7 @@ public class ConfigurationChangeItem extends ClientTransactionItem {
    @Override
    public void recycle() {
        mConfiguration = null;
        mDeviceId = 0;
        ObjectPool.recycle(this);
    }

@@ -74,11 +77,13 @@ public class ConfigurationChangeItem extends ClientTransactionItem {
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeTypedObject(mConfiguration, flags);
        dest.writeInt(mDeviceId);
    }

    /** Read from Parcel. */
    private ConfigurationChangeItem(Parcel in) {
        mConfiguration = in.readTypedObject(Configuration.CREATOR);
        mDeviceId = in.readInt();
    }

    public static final @android.annotation.NonNull Creator<ConfigurationChangeItem> CREATOR =
@@ -101,16 +106,20 @@ public class ConfigurationChangeItem extends ClientTransactionItem {
            return false;
        }
        final ConfigurationChangeItem other = (ConfigurationChangeItem) o;
        return Objects.equals(mConfiguration, other.mConfiguration);
        return Objects.equals(mConfiguration, other.mConfiguration)
                && mDeviceId == other.mDeviceId;
    }

    @Override
    public int hashCode() {
        return mConfiguration.hashCode();
        int result = 17;
        result = 31 * result + mDeviceId;
        result = 31 * result + mConfiguration.hashCode();
        return result;
    }

    @Override
    public String toString() {
        return "ConfigurationChangeItem{config=" + mConfiguration + "}";
        return "ConfigurationChangeItem{deviceId=" + mDeviceId + ", config" + mConfiguration + "}";
    }
}
+17 −11
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
    private ActivityInfo mInfo;
    private Configuration mCurConfig;
    private Configuration mOverrideConfig;
    private int mDeviceId;
    private String mReferrer;
    private IVoiceInteractor mVoiceInteractor;
    private int mProcState;
@@ -95,7 +96,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
        ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                mOverrideConfig, mReferrer, mVoiceInteractor, mState, mPersistentState,
                mOverrideConfig, mDeviceId, mReferrer, mVoiceInteractor, mState, mPersistentState,
                mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
                client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble,
                mTaskFragmentToken);
@@ -116,7 +117,7 @@ public class LaunchActivityItem extends ClientTransactionItem {

    /** Obtain an instance initialized with provided params. */
    public static LaunchActivityItem obtain(Intent intent, int ident, ActivityInfo info,
            Configuration curConfig, Configuration overrideConfig,
            Configuration curConfig, Configuration overrideConfig, int deviceId,
            String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
            PersistableBundle persistentState, List<ResultInfo> pendingResults,
            List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
@@ -127,7 +128,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
        if (instance == null) {
            instance = new LaunchActivityItem();
        }
        setValues(instance, intent, ident, info, curConfig, overrideConfig, referrer,
        setValues(instance, intent, ident, info, curConfig, overrideConfig, deviceId, referrer,
                voiceInteractor, procState, state, persistentState, pendingResults,
                pendingNewIntents, activityOptions, isForward, profilerInfo, assistToken,
                activityClientController, shareableActivityToken,
@@ -138,7 +139,7 @@ public class LaunchActivityItem extends ClientTransactionItem {

    @Override
    public void recycle() {
        setValues(this, null, 0, null, null, null, null, null, 0, null, null, null, null,
        setValues(this, null, 0, null, null, null, 0, null, null, 0, null, null, null, null,
                null, false, null, null, null, null, false, null);
        ObjectPool.recycle(this);
    }
@@ -154,6 +155,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
        dest.writeTypedObject(mInfo, flags);
        dest.writeTypedObject(mCurConfig, flags);
        dest.writeTypedObject(mOverrideConfig, flags);
        dest.writeInt(mDeviceId);
        dest.writeString(mReferrer);
        dest.writeStrongInterface(mVoiceInteractor);
        dest.writeInt(mProcState);
@@ -175,7 +177,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
    private LaunchActivityItem(Parcel in) {
        setValues(this, in.readTypedObject(Intent.CREATOR), in.readInt(),
                in.readTypedObject(ActivityInfo.CREATOR), in.readTypedObject(Configuration.CREATOR),
                in.readTypedObject(Configuration.CREATOR), in.readString(),
                in.readTypedObject(Configuration.CREATOR), in.readInt(), in.readString(),
                IVoiceInteractor.Stub.asInterface(in.readStrongBinder()), in.readInt(),
                in.readBundle(getClass().getClassLoader()),
                in.readPersistableBundle(getClass().getClassLoader()),
@@ -215,6 +217,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
        return intentsEqual && mIdent == other.mIdent
                && activityInfoEqual(other.mInfo) && Objects.equals(mCurConfig, other.mCurConfig)
                && Objects.equals(mOverrideConfig, other.mOverrideConfig)
                && mDeviceId == other.mDeviceId
                && Objects.equals(mReferrer, other.mReferrer)
                && mProcState == other.mProcState && areBundlesEqualRoughly(mState, other.mState)
                && areBundlesEqualRoughly(mPersistentState, other.mPersistentState)
@@ -235,6 +238,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
        result = 31 * result + mIdent;
        result = 31 * result + Objects.hashCode(mCurConfig);
        result = 31 * result + Objects.hashCode(mOverrideConfig);
        result = 31 * result + mDeviceId;
        result = 31 * result + Objects.hashCode(mReferrer);
        result = 31 * result + Objects.hashCode(mProcState);
        result = 31 * result + getRoughBundleHashCode(mState);
@@ -279,16 +283,17 @@ public class LaunchActivityItem extends ClientTransactionItem {
    public String toString() {
        return "LaunchActivityItem{intent=" + mIntent + ",ident=" + mIdent + ",info=" + mInfo
                + ",curConfig=" + mCurConfig + ",overrideConfig=" + mOverrideConfig
                + ",referrer=" + mReferrer + ",procState=" + mProcState + ",state=" + mState
                + ",persistentState=" + mPersistentState + ",pendingResults=" + mPendingResults
                + ",pendingNewIntents=" + mPendingNewIntents + ",options=" + mActivityOptions
                + ",profilerInfo=" + mProfilerInfo + ",assistToken=" + mAssistToken
                + ",shareableActivityToken=" + mShareableActivityToken + "}";
                + ",deviceId=" + mDeviceId + ",referrer=" + mReferrer + ",procState=" + mProcState
                + ",state=" + mState + ",persistentState=" + mPersistentState
                + ",pendingResults=" + mPendingResults + ",pendingNewIntents=" + mPendingNewIntents
                + ",options=" + mActivityOptions + ",profilerInfo=" + mProfilerInfo
                + ",assistToken=" + mAssistToken + ",shareableActivityToken="
                + mShareableActivityToken + "}";
    }

    // Using the same method to set and clear values to make sure we don't forget anything
    private static void setValues(LaunchActivityItem instance, Intent intent, int ident,
            ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
            ActivityInfo info, Configuration curConfig, Configuration overrideConfig, int deviceId,
            String referrer, IVoiceInteractor voiceInteractor,
            int procState, Bundle state, PersistableBundle persistentState,
            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
@@ -300,6 +305,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
        instance.mInfo = info;
        instance.mCurConfig = curConfig;
        instance.mOverrideConfig = overrideConfig;
        instance.mDeviceId = deviceId;
        instance.mReferrer = referrer;
        instance.mVoiceInteractor = voiceInteractor;
        instance.mProcState = procState;
+10 −6
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.app.activity;

import static android.companion.virtual.VirtualDeviceManager.DEVICE_ID_INVALID;
import static android.content.Intent.ACTION_EDIT;
import static android.content.Intent.ACTION_VIEW;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
@@ -204,7 +205,8 @@ public class ActivityThreadTest {
        try {
            // Send process level config change.
            ClientTransaction transaction = newTransaction(activityThread, null);
            transaction.addCallback(ConfigurationChangeItem.obtain(new Configuration(newConfig)));
            transaction.addCallback(ConfigurationChangeItem.obtain(
                    new Configuration(newConfig), DEVICE_ID_INVALID));
            appThread.scheduleTransaction(transaction);
            InstrumentationRegistry.getInstrumentation().waitForIdleSync();

@@ -413,12 +415,14 @@ public class ActivityThreadTest {
        activity.mTestLatch = new CountDownLatch(1);

        ClientTransaction transaction = newTransaction(activityThread, null);
        transaction.addCallback(ConfigurationChangeItem.obtain(processConfigLandscape));
        transaction.addCallback(ConfigurationChangeItem.obtain(
                processConfigLandscape, DEVICE_ID_INVALID));
        appThread.scheduleTransaction(transaction);

        transaction = newTransaction(activityThread, activity.getActivityToken());
        transaction.addCallback(ActivityConfigurationChangeItem.obtain(activityConfigLandscape));
        transaction.addCallback(ConfigurationChangeItem.obtain(processConfigPortrait));
        transaction.addCallback(ConfigurationChangeItem.obtain(
                processConfigPortrait, DEVICE_ID_INVALID));
        transaction.addCallback(ActivityConfigurationChangeItem.obtain(activityConfigPortrait));
        appThread.scheduleTransaction(transaction);

@@ -530,7 +534,7 @@ public class ActivityThreadTest {
                    ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;

            activityThread.updatePendingConfiguration(newAppConfig);
            activityThread.handleConfigurationChanged(newAppConfig);
            activityThread.handleConfigurationChanged(newAppConfig, DEVICE_ID_INVALID);

            try {
                assertEquals("Virtual display orientation must not change when process"
@@ -548,7 +552,7 @@ public class ActivityThreadTest {
    private static void restoreConfig(ActivityThread thread, Configuration originalConfig) {
        thread.getConfiguration().seq = originalConfig.seq - 1;
        ResourcesManager.getInstance().getConfiguration().seq = originalConfig.seq - 1;
        thread.handleConfigurationChanged(originalConfig);
        thread.handleConfigurationChanged(originalConfig, DEVICE_ID_INVALID);
    }

    @Test
@@ -626,7 +630,7 @@ public class ActivityThreadTest {
            newAppConfig.seq++;

            final ActivityThread activityThread = activity.getActivityThread();
            activityThread.handleConfigurationChanged(newAppConfig);
            activityThread.handleConfigurationChanged(newAppConfig, DEVICE_ID_INVALID);

            // Verify that application config update was applied, but didn't change activity config.
            assertEquals("Activity config must not change if the process config changes",
Loading