From c923c2286e24df8bc4d5fec9f28d6ed6043a072c Mon Sep 17 00:00:00 2001 From: Jing Ji Date: Fri, 22 Jan 2021 18:15:37 -0800 Subject: [PATCH] Cache the owner name string in UserManagerService It's read frequently but it won't be changed until a configuration change. So cache the string. Bug: 178235824 Bug: 162450085 Test: Manual - switch languages and check 'dumpsys user |grep Owner' Test: atest UserManagerServiceUserInfoTest Test: atest UserManagerServiceUserTypeTest Test: atest UserManagerTest Change-Id: I337f403e38e9d54f545e773309d8bd1651cbcdf0 --- .../android/server/pm/UserManagerService.java | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 314510b89cb91..f43240bd810a9 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -47,6 +47,7 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.ShortcutServiceInternal; import android.content.pm.UserInfo; import android.content.pm.UserInfo.UserInfoFlag; +import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; import android.os.Binder; @@ -92,6 +93,7 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.TimeUtils; +import android.util.TypedValue; import android.util.TypedXmlPullParser; import android.util.TypedXmlSerializer; import android.util.Xml; @@ -139,6 +141,7 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; /** * Service for {@link UserManager}. @@ -461,6 +464,26 @@ public class UserManagerService extends IUserManager.Stub { } }; + /** + * Cache the owner name string, since it could be read repeatedly on a critical code path + * but hit by slow IO. This could be eliminated once we have the cached UserInfo in place. + */ + private final AtomicReference mOwnerName = new AtomicReference<>(); + + private final TypedValue mOwnerNameTypedValue = new TypedValue(); + + private final Configuration mLastConfiguration = new Configuration(); + + private final BroadcastReceiver mConfigurationChangeReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (!Intent.ACTION_CONFIGURATION_CHANGED.equals(intent.getAction())) { + return; + } + invalidateOwnerNameIfNecessary(context.getResources(), false /* forceUpdate */); + } + }; + // TODO(b/161915546): remove once userWithName() is fixed / removed // Use to debug / dump when user 0 is allocated at userWithName() public static final boolean DBG_ALLOCATION = false; // DO NOT SUBMIT WITH TRUE @@ -636,6 +659,7 @@ public class UserManagerService extends IUserManager.Stub { mHandler = new MainHandler(); mUserDataPreparer = userDataPreparer; mUserTypes = UserTypeFactory.getUserTypes(); + invalidateOwnerNameIfNecessary(context.getResources(), true /* forceUpdate */); synchronized (mPackagesLock) { mUsersDir = new File(dataDir, USER_INFO_DIR); mUsersDir.mkdirs(); @@ -669,6 +693,10 @@ public class UserManagerService extends IUserManager.Stub { mContext.registerReceiver(mDisableQuietModeCallback, new IntentFilter(ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK), null, mHandler); + + mContext.registerReceiver(mConfigurationChangeReceiver, + new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED), + null, mHandler); } /** @@ -2851,7 +2879,16 @@ public class UserManagerService extends IUserManager.Stub { } private String getOwnerName() { - return mContext.getResources().getString(com.android.internal.R.string.owner_name); + return mOwnerName.get(); + } + + private void invalidateOwnerNameIfNecessary(@NonNull Resources res, boolean forceUpdate) { + final int configChanges = mLastConfiguration.updateFrom(res.getConfiguration()); + if (forceUpdate || (configChanges & mOwnerNameTypedValue.changingConfigurations) != 0) { + res.getValue(com.android.internal.R.string.owner_name, mOwnerNameTypedValue, true); + final CharSequence ownerName = mOwnerNameTypedValue.coerceToString(); + mOwnerName.set(ownerName != null ? ownerName.toString() : null); + } } private void scheduleWriteUser(UserData userData) {