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

Commit 45e4bcf9 authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Reduce unnecessary overhead of SystemUiContext

- Do not report change when initializing DisplayContent
  (DisplayContent#isReady() is false).
  This reduces boot time by dozen of milliseconds
  (RootWindowContainer#setWindowManager).
- Only create SystemUiContext if needed. Most of processes don't
  use it. This reduces many registrations (e.g. according to the
  number of processes, it maybe from ~60 to ~10), which involve
  binder/listener creation/invocation, especially the extra cost
  of dispatching configuration to the context which no one uses.
- Store token as IWindowToken to avoid object creation every time
  by asInterface.

Bug: 207620458
Test: atest InputMethodMenuControllerTest WindowContextControllerTest
Change-Id: I867e9f81116796c42048195406d74feccf4772d3
parent d43efc90
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -321,7 +321,8 @@ public final class ActivityThread extends ClientTransactionHandler

    @UnsupportedAppUsage
    private ContextImpl mSystemContext;
    private final SparseArray<ContextImpl> mDisplaySystemUiContexts = new SparseArray<>();
    @GuardedBy("this")
    private SparseArray<ContextImpl> mDisplaySystemUiContexts;

    @UnsupportedAppUsage
    static volatile IPackageManager sPackageManager;
@@ -2650,7 +2651,6 @@ public final class ActivityThread extends ClientTransactionHandler
        }
    }

    @Override
    @NonNull
    public ContextImpl getSystemUiContext() {
        return getSystemUiContext(DEFAULT_DISPLAY);
@@ -2664,6 +2664,9 @@ public final class ActivityThread extends ClientTransactionHandler
    @NonNull
    public ContextImpl getSystemUiContext(int displayId) {
        synchronized (this) {
            if (mDisplaySystemUiContexts == null) {
                mDisplaySystemUiContexts = new SparseArray<>();
            }
            ContextImpl systemUiContext = mDisplaySystemUiContexts.get(displayId);
            if (systemUiContext == null) {
                systemUiContext = ContextImpl.createSystemUiContext(getSystemContext(), displayId);
@@ -2673,6 +2676,15 @@ public final class ActivityThread extends ClientTransactionHandler
        }
    }

    @Nullable
    @Override
    public ContextImpl getSystemUiContextNoCreate() {
        synchronized (this) {
            if (mDisplaySystemUiContexts == null) return null;
            return mDisplaySystemUiContexts.get(DEFAULT_DISPLAY);
        }
    }

    public void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
        synchronized (this) {
            getSystemContext().installSystemApplicationInfo(info, classLoader);
+1 −1
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ import java.util.ArrayList;
interface ActivityThreadInternal {
    ContextImpl getSystemContext();

    ContextImpl getSystemUiContext();
    ContextImpl getSystemUiContextNoCreate();

    boolean isInDensityCompatMode();

+7 −3
Original line number Diff line number Diff line
@@ -154,9 +154,12 @@ class ConfigurationController {
        int configDiff;
        boolean equivalent;

        synchronized (mResourcesManager) {
        // Get theme outside of synchronization to avoid nested lock.
        final Resources.Theme systemTheme = mActivityThread.getSystemContext().getTheme();
            final Resources.Theme systemUiTheme = mActivityThread.getSystemUiContext().getTheme();
        final ContextImpl systemUiContext = mActivityThread.getSystemUiContextNoCreate();
        final Resources.Theme systemUiTheme =
                systemUiContext != null ? systemUiContext.getTheme() : null;
        synchronized (mResourcesManager) {
            if (mPendingConfiguration != null) {
                if (!mPendingConfiguration.isOtherSeqNewer(config)) {
                    config = mPendingConfiguration;
@@ -207,7 +210,8 @@ class ConfigurationController {
                systemTheme.rebase();
            }

            if ((systemUiTheme.getChangingConfigurations() & configDiff) != 0) {
            if (systemUiTheme != null
                    && (systemUiTheme.getChangingConfigurations() & configDiff) != 0) {
                systemUiTheme.rebase();
            }
        }
+22 −19
Original line number Diff line number Diff line
@@ -173,7 +173,7 @@ class WindowContextListenerController {

    @VisibleForTesting
    class WindowContextListenerImpl implements WindowContainerListener {
        @NonNull private final IBinder mClientToken;
        @NonNull private final IWindowToken mClientToken;
        private final int mOwnerUid;
        @NonNull private WindowContainer<?> mContainer;
        /**
@@ -193,7 +193,7 @@ class WindowContextListenerController {

        private WindowContextListenerImpl(IBinder clientToken, WindowContainer<?> container,
                int ownerUid, @WindowType int type, @Nullable Bundle options) {
            mClientToken = clientToken;
            mClientToken = IWindowToken.Stub.asInterface(clientToken);
            mContainer = Objects.requireNonNull(container);
            mOwnerUid = ownerUid;
            mType = type;
@@ -205,7 +205,7 @@ class WindowContextListenerController {
                mDeathRecipient = deathRecipient;
            } catch (RemoteException e) {
                ProtoLog.e(WM_ERROR, "Could not register window container listener token=%s, "
                        + "container=%s", mClientToken, mContainer);
                        + "container=%s", clientToken, mContainer);
            }
        }

@@ -228,17 +228,17 @@ class WindowContextListenerController {
        }

        private void register() {
            final IBinder token = mClientToken.asBinder();
            if (mDeathRecipient == null) {
                throw new IllegalStateException("Invalid client token: " + mClientToken);
                throw new IllegalStateException("Invalid client token: " + token);
            }
            mListeners.putIfAbsent(mClientToken, this);
            mListeners.putIfAbsent(token, this);
            mContainer.registerWindowContainerListener(this);
            reportConfigToWindowTokenClient();
        }

        private void unregister() {
            mContainer.unregisterWindowContainerListener(this);
            mListeners.remove(mClientToken);
            mListeners.remove(mClientToken.asBinder());
        }

        private void clear() {
@@ -258,19 +258,24 @@ class WindowContextListenerController {

        private void reportConfigToWindowTokenClient() {
            if (mDeathRecipient == null) {
                throw new IllegalStateException("Invalid client token: " + mClientToken);
                throw new IllegalStateException("Invalid client token: " + mClientToken.asBinder());
            }
            final DisplayContent dc = mContainer.getDisplayContent();
            if (!dc.isReady()) {
                // Do not report configuration when booting. The latest configuration will be sent
                // when WindowManagerService#displayReady().
                return;
            }
            // If the display of window context associated window container is suspended, don't
            // report the configuration update. Note that we still dispatch the configuration update
            // to WindowProviderService to make it compatible with Service#onConfigurationChanged.
            // Service always receives #onConfigurationChanged callback regardless of display state.
            if (!isWindowProviderService(mOptions)
                    && isSuspendedState(mContainer.getDisplayContent().getDisplayInfo().state)) {
            if (!isWindowProviderService(mOptions) && isSuspendedState(dc.getDisplayInfo().state)) {
                mHasPendingConfiguration = true;
                return;
            }
            final Configuration config = mContainer.getConfiguration();
            final int displayId = mContainer.getDisplayContent().getDisplayId();
            final int displayId = dc.getDisplayId();
            if (mLastReportedConfig == null) {
                mLastReportedConfig = new Configuration();
            }
@@ -282,9 +287,8 @@ class WindowContextListenerController {
            mLastReportedConfig.setTo(config);
            mLastReportedDisplay = displayId;

            IWindowToken windowTokenClient = IWindowToken.Stub.asInterface(mClientToken);
            try {
                windowTokenClient.onConfigurationChanged(config, displayId);
                mClientToken.onConfigurationChanged(config, displayId);
            } catch (RemoteException e) {
                ProtoLog.w(WM_ERROR, "Could not report config changes to the window token client.");
            }
@@ -294,7 +298,7 @@ class WindowContextListenerController {
        @Override
        public void onRemoved() {
            if (mDeathRecipient == null) {
                throw new IllegalStateException("Invalid client token: " + mClientToken);
                throw new IllegalStateException("Invalid client token: " + mClientToken.asBinder());
            }
            final WindowToken windowToken = mContainer.asWindowToken();
            if (windowToken != null && windowToken.isFromClient()) {
@@ -312,9 +316,8 @@ class WindowContextListenerController {
                }
            }
            mDeathRecipient.unlinkToDeath();
            IWindowToken windowTokenClient = IWindowToken.Stub.asInterface(mClientToken);
            try {
                windowTokenClient.onWindowTokenRemoved();
                mClientToken.onWindowTokenRemoved();
            } catch (RemoteException e) {
                ProtoLog.w(WM_ERROR, "Could not report token removal to the window token client.");
            }
@@ -323,7 +326,7 @@ class WindowContextListenerController {

        @Override
        public String toString() {
            return "WindowContextListenerImpl{clientToken=" + mClientToken + ", "
            return "WindowContextListenerImpl{clientToken=" + mClientToken.asBinder() + ", "
                    + "container=" + mContainer + "}";
        }

@@ -337,11 +340,11 @@ class WindowContextListenerController {
            }

            void linkToDeath() throws RemoteException {
                mClientToken.linkToDeath(this, 0);
                mClientToken.asBinder().linkToDeath(this, 0);
            }

            void unlinkToDeath() {
                mClientToken.unlinkToDeath(this, 0);
                mClientToken.asBinder().unlinkToDeath(this, 0);
            }
        }
    }