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
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -28,7 +28,7 @@ import java.util.ArrayList;
|
||||
interface ActivityThreadInternal {
|
||||
ContextImpl getSystemContext();
|
||||
|
||||
ContextImpl getSystemUiContext();
|
||||
ContextImpl getSystemUiContextNoCreate();
|
||||
|
||||
boolean isInDensityCompatMode();
|
||||
|
||||
|
||||
@@ -154,9 +154,12 @@ class ConfigurationController {
|
||||
int configDiff;
|
||||
boolean equivalent;
|
||||
|
||||
// Get theme outside of synchronization to avoid nested lock.
|
||||
final Resources.Theme systemTheme = mActivityThread.getSystemContext().getTheme();
|
||||
final ContextImpl systemUiContext = mActivityThread.getSystemUiContextNoCreate();
|
||||
final Resources.Theme systemUiTheme =
|
||||
systemUiContext != null ? systemUiContext.getTheme() : null;
|
||||
synchronized (mResourcesManager) {
|
||||
final Resources.Theme systemTheme = mActivityThread.getSystemContext().getTheme();
|
||||
final Resources.Theme systemUiTheme = mActivityThread.getSystemUiContext().getTheme();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user