Log data to ApplicationLocalesChanged atom

Log the caller who changes the per-app locales

Bug: 272741428
Test: atest ApplicationLocalesChangedAtomTests
Change-Id: Ic96092330f51cb6e14c973d5c65a5274e206b795
This commit is contained in:
Josh Hou
2023-03-23 11:59:54 +00:00
parent 34ab67a0a0
commit 1f35a414e3
5 changed files with 87 additions and 33 deletions

View File

@@ -20,24 +20,32 @@ import static android.os.Process.INVALID_UID;
import com.android.internal.util.FrameworkStatsLog;
import java.util.Locale;
/**
* Holds data used to report the ApplicationLocalesChanged atom.
*/
public final class AppLocaleChangedAtomRecord {
private static final String DEFAULT_PREFIX = "default-";
final int mCallingUid;
int mTargetUid = INVALID_UID;
String mNewLocales = "";
String mPrevLocales = "";
String mNewLocales = DEFAULT_PREFIX;
String mPrevLocales = DEFAULT_PREFIX;
int mStatus = FrameworkStatsLog
.APPLICATION_LOCALES_CHANGED__STATUS__STATUS_UNSPECIFIED;
int mCaller = FrameworkStatsLog
.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_UNKNOWN;
AppLocaleChangedAtomRecord(int callingUid) {
this.mCallingUid = callingUid;
Locale defaultLocale = Locale.getDefault();
if (defaultLocale != null) {
this.mNewLocales = DEFAULT_PREFIX + defaultLocale.toLanguageTag();
this.mPrevLocales = DEFAULT_PREFIX + defaultLocale.toLanguageTag();
}
}
void setNewLocales(String newLocales) {
this.mNewLocales = newLocales;
this.mNewLocales = convertEmptyLocales(newLocales);
}
void setTargetUid(int targetUid) {
@@ -45,7 +53,7 @@ public final class AppLocaleChangedAtomRecord {
}
void setPrevLocales(String prevLocales) {
this.mPrevLocales = prevLocales;
this.mPrevLocales = convertEmptyLocales(prevLocales);
}
void setStatus(int status) {
@@ -55,4 +63,16 @@ public final class AppLocaleChangedAtomRecord {
void setCaller(int caller) {
this.mCaller = caller;
}
private String convertEmptyLocales(String locales) {
String target = locales;
if ("".equals(locales)) {
Locale defaultLocale = Locale.getDefault();
if (defaultLocale != null) {
target = DEFAULT_PREFIX + defaultLocale.toLanguageTag();
}
}
return target;
}
}

View File

@@ -44,6 +44,7 @@ import android.util.SparseArray;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
@@ -377,7 +378,8 @@ class LocaleManagerBackupHelper {
// Restore the locale immediately
try {
mLocaleManagerService.setApplicationLocales(pkgName, userId,
LocaleList.forLanguageTags(localesInfo.mLocales), localesInfo.mSetFromDelegate);
LocaleList.forLanguageTags(localesInfo.mLocales), localesInfo.mSetFromDelegate,
FrameworkStatsLog.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_BACKUP_RESTORE);
if (DEBUG) {
Slog.d(TAG, "Restored locales=" + localesInfo.mLocales + " fromDelegate="
+ localesInfo.mSetFromDelegate + " for package=" + pkgName);
@@ -662,7 +664,9 @@ class LocaleManagerBackupHelper {
try {
LocaleConfig localeConfig = new LocaleConfig(
mContext.createPackageContextAsUser(packageName, 0, UserHandle.of(userId)));
mLocaleManagerService.removeUnsupportedAppLocales(packageName, userId, localeConfig);
mLocaleManagerService.removeUnsupportedAppLocales(packageName, userId, localeConfig,
FrameworkStatsLog
.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_APP_UPDATE_LOCALES_CHANGE);
} catch (PackageManager.NameNotFoundException e) {
Slog.e(TAG, "Can not found the package name : " + packageName + " / " + e);
}

View File

@@ -182,8 +182,11 @@ public class LocaleManagerService extends SystemService {
@Override
public void setApplicationLocales(@NonNull String appPackageName, @UserIdInt int userId,
@NonNull LocaleList locales, boolean fromDelegate) throws RemoteException {
int caller = fromDelegate
? FrameworkStatsLog.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_DELEGATE
: FrameworkStatsLog.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_APPS;
LocaleManagerService.this.setApplicationLocales(appPackageName, userId, locales,
fromDelegate);
fromDelegate, caller);
}
@Override
@@ -226,13 +229,14 @@ public class LocaleManagerService extends SystemService {
* Sets the current UI locales for a specified app.
*/
public void setApplicationLocales(@NonNull String appPackageName, @UserIdInt int userId,
@NonNull LocaleList locales, boolean fromDelegate)
@NonNull LocaleList locales, boolean fromDelegate, int caller)
throws RemoteException, IllegalArgumentException {
AppLocaleChangedAtomRecord atomRecordForMetrics = new
AppLocaleChangedAtomRecord(Binder.getCallingUid());
try {
requireNonNull(appPackageName);
requireNonNull(locales);
atomRecordForMetrics.setCaller(caller);
atomRecordForMetrics.setNewLocales(locales.toLanguageTags());
//Allow apps with INTERACT_ACROSS_USERS permission to set locales for different user.
userId = mActivityManagerInternal.handleIncomingUser(
@@ -273,8 +277,8 @@ public class LocaleManagerService extends SystemService {
+ " and user " + userId);
}
atomRecordForMetrics.setPrevLocales(getApplicationLocalesUnchecked(appPackageName, userId)
.toLanguageTags());
atomRecordForMetrics.setPrevLocales(
getApplicationLocalesUnchecked(appPackageName, userId).toLanguageTags());
final ActivityTaskManagerInternal.PackageConfigurationUpdater updater =
mActivityTaskManagerInternal.createPackageConfigurationUpdater(appPackageName,
userId);
@@ -619,7 +623,10 @@ public class LocaleManagerService extends SystemService {
Slog.d(TAG, "remove the override LocaleConfig");
file.delete();
}
removeUnsupportedAppLocales(appPackageName, userId, resLocaleConfig);
removeUnsupportedAppLocales(appPackageName, userId, resLocaleConfig,
FrameworkStatsLog
.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_DYNAMIC_LOCALES_CHANGE
);
atomRecord.setOverrideRemoved(true);
atomRecord.setStatus(FrameworkStatsLog
.APP_SUPPORTED_LOCALES_CHANGED__STATUS__SUCCESS);
@@ -661,7 +668,10 @@ public class LocaleManagerService extends SystemService {
}
atomicFile.finishWrite(stream);
// Clear per-app locales if they are not in the override LocaleConfig.
removeUnsupportedAppLocales(appPackageName, userId, overrideLocaleConfig);
removeUnsupportedAppLocales(appPackageName, userId, overrideLocaleConfig,
FrameworkStatsLog
.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_DYNAMIC_LOCALES_CHANGE
);
if (overrideLocaleConfig.isSameLocaleConfig(resLocaleConfig)) {
Slog.d(TAG, "setOverrideLocaleConfig, same as the app's LocaleConfig");
atomRecord.setSameAsResConfig(true);
@@ -678,9 +688,12 @@ public class LocaleManagerService extends SystemService {
/**
* Checks if the per-app locales are in the LocaleConfig. Per-app locales missing from the
* LocaleConfig will be removed.
*
* <p><b>Note:</b> Check whether to remove the per-app locales when the app is upgraded or
* the LocaleConfig is overridden.
*/
void removeUnsupportedAppLocales(String appPackageName, int userId,
LocaleConfig localeConfig) {
LocaleConfig localeConfig, int caller) {
LocaleList appLocales = getApplicationLocalesUnchecked(appPackageName, userId);
// Remove the per-app locales from the locale list if they don't exist in the LocaleConfig.
boolean resetAppLocales = false;
@@ -707,7 +720,7 @@ public class LocaleManagerService extends SystemService {
try {
setApplicationLocales(appPackageName, userId,
new LocaleList(newAppLocales.toArray(locales)),
mBackupHelper.areLocalesSetFromDelegate(userId, appPackageName));
mBackupHelper.areLocalesSetFromDelegate(userId, appPackageName), caller);
} catch (RemoteException | IllegalArgumentException e) {
Slog.e(TAG, "Could not set locales for " + appPackageName, e);
}

View File

@@ -54,6 +54,7 @@ import android.util.Xml;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
@@ -264,7 +265,8 @@ public class LocaleManagerBackupRestoreTest {
// Locales were restored
verify(mMockLocaleManagerService, times(1)).setApplicationLocales(DEFAULT_PACKAGE_NAME,
DEFAULT_USER_ID, DEFAULT_LOCALES, false);
DEFAULT_USER_ID, DEFAULT_LOCALES, false, FrameworkStatsLog
.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_BACKUP_RESTORE);
checkStageDataDoesNotExist(DEFAULT_USER_ID);
}
@@ -280,7 +282,8 @@ public class LocaleManagerBackupRestoreTest {
// Locales were restored
verify(mMockLocaleManagerService, times(1)).setApplicationLocales(DEFAULT_PACKAGE_NAME,
DEFAULT_USER_ID, DEFAULT_LOCALES, false);
DEFAULT_USER_ID, DEFAULT_LOCALES, false, FrameworkStatsLog
.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_BACKUP_RESTORE);
checkStageDataDoesNotExist(DEFAULT_USER_ID);
mBackupHelper.persistLocalesModificationInfo(DEFAULT_USER_ID, DEFAULT_PACKAGE_NAME, false,
@@ -303,7 +306,8 @@ public class LocaleManagerBackupRestoreTest {
// Locales were restored
verify(mMockLocaleManagerService, times(1)).setApplicationLocales(DEFAULT_PACKAGE_NAME,
DEFAULT_USER_ID, DEFAULT_LOCALES, true);
DEFAULT_USER_ID, DEFAULT_LOCALES, true, FrameworkStatsLog
.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_BACKUP_RESTORE);
checkStageDataDoesNotExist(DEFAULT_USER_ID);
mBackupHelper.persistLocalesModificationInfo(DEFAULT_USER_ID, DEFAULT_PACKAGE_NAME, true,
@@ -327,7 +331,8 @@ public class LocaleManagerBackupRestoreTest {
// Locales were restored
verify(mMockLocaleManagerService, times(1)).setApplicationLocales(
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID, DEFAULT_LOCALES, true);
DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID, DEFAULT_LOCALES, true,
FrameworkStatsLog.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_BACKUP_RESTORE);
checkStageDataDoesNotExist(DEFAULT_USER_ID);
mBackupHelper.persistLocalesModificationInfo(DEFAULT_USER_ID, DEFAULT_PACKAGE_NAME, true,
@@ -369,7 +374,8 @@ public class LocaleManagerBackupRestoreTest {
mBackupHelper.stageAndApplyRestoredPayload(out.toByteArray(), DEFAULT_USER_ID);
verify(mMockLocaleManagerService, times(1)).setApplicationLocales(pkgNameA, DEFAULT_USER_ID,
LocaleList.forLanguageTags(langTagsA), true);
LocaleList.forLanguageTags(langTagsA), true, FrameworkStatsLog
.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_BACKUP_RESTORE);
pkgLocalesMap.remove(pkgNameA);
@@ -422,11 +428,12 @@ public class LocaleManagerBackupRestoreTest {
// Restore locales only for myAppB.
verify(mMockLocaleManagerService, times(0)).setApplicationLocales(eq(pkgNameA), anyInt(),
any(), anyBoolean());
any(), anyBoolean(), anyInt());
verify(mMockLocaleManagerService, times(1)).setApplicationLocales(pkgNameB, DEFAULT_USER_ID,
LocaleList.forLanguageTags(langTagsB), true);
LocaleList.forLanguageTags(langTagsB), true, FrameworkStatsLog
.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_BACKUP_RESTORE);
verify(mMockLocaleManagerService, times(0)).setApplicationLocales(eq(pkgNameC), anyInt(),
any(), anyBoolean());
any(), anyBoolean(), anyInt());
// App C is staged.
pkgLocalesMap.remove(pkgNameA);
@@ -484,7 +491,8 @@ public class LocaleManagerBackupRestoreTest {
mPackageMonitor.onPackageAdded(pkgNameA, DEFAULT_UID);
verify(mMockLocaleManagerService, times(1)).setApplicationLocales(pkgNameA, DEFAULT_USER_ID,
LocaleList.forLanguageTags(langTagsA), false);
LocaleList.forLanguageTags(langTagsA), false, FrameworkStatsLog
.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_BACKUP_RESTORE);
mBackupHelper.persistLocalesModificationInfo(DEFAULT_USER_ID, pkgNameA, false, false);
@@ -499,7 +507,8 @@ public class LocaleManagerBackupRestoreTest {
mPackageMonitor.onPackageAdded(pkgNameB, DEFAULT_UID);
verify(mMockLocaleManagerService, times(1)).setApplicationLocales(pkgNameB, DEFAULT_USER_ID,
LocaleList.forLanguageTags(langTagsB), true);
LocaleList.forLanguageTags(langTagsB), true, FrameworkStatsLog
.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_BACKUP_RESTORE);
mBackupHelper.persistLocalesModificationInfo(DEFAULT_USER_ID, pkgNameB, true, false);
@@ -606,7 +615,8 @@ public class LocaleManagerBackupRestoreTest {
mPackageMonitor.onPackageAdded(pkgNameA, DEFAULT_UID);
verify(mMockLocaleManagerService, times(1)).setApplicationLocales(
pkgNameA, DEFAULT_USER_ID, LocaleList.forLanguageTags(langTagsA), false);
pkgNameA, DEFAULT_USER_ID, LocaleList.forLanguageTags(langTagsA), false,
FrameworkStatsLog.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_BACKUP_RESTORE);
pkgLocalesMap.remove(pkgNameA);
@@ -620,7 +630,7 @@ public class LocaleManagerBackupRestoreTest {
mPackageMonitor.onPackageAdded(pkgNameB, DEFAULT_UID);
verify(mMockLocaleManagerService, times(0)).setApplicationLocales(eq(pkgNameB), anyInt(),
any(), anyBoolean());
any(), anyBoolean(), anyInt());
checkStageDataDoesNotExist(DEFAULT_USER_ID);
}
@@ -734,7 +744,7 @@ public class LocaleManagerBackupRestoreTest {
*/
private void verifyNothingRestored() throws Exception {
verify(mMockLocaleManagerService, times(0)).setApplicationLocales(anyString(), anyInt(),
any(), anyBoolean());
any(), anyBoolean(), anyInt());
}
private static void verifyPayloadForAppLocales(Map<String, LocalesInfo> expectedPkgLocalesMap,

View File

@@ -52,6 +52,7 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal.PackageConfig;
@@ -136,7 +137,8 @@ public class LocaleManagerServiceTest {
try {
mLocaleManagerService.setApplicationLocales(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID,
LocaleList.getEmptyLocaleList(), false);
LocaleList.getEmptyLocaleList(), false, FrameworkStatsLog
.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_APPS);
fail("Expected SecurityException");
} finally {
verify(mMockContext).enforceCallingOrSelfPermission(
@@ -151,7 +153,8 @@ public class LocaleManagerServiceTest {
public void testSetApplicationLocales_nullPackageName_fails() throws Exception {
try {
mLocaleManagerService.setApplicationLocales(/* appPackageName = */ null,
DEFAULT_USER_ID, LocaleList.getEmptyLocaleList(), false);
DEFAULT_USER_ID, LocaleList.getEmptyLocaleList(), false,
FrameworkStatsLog.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_APPS);
fail("Expected NullPointerException");
} finally {
verify(mMockBackupHelper, times(0)).notifyBackupManager();
@@ -165,7 +168,8 @@ public class LocaleManagerServiceTest {
try {
mLocaleManagerService.setApplicationLocales(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID,
/* locales = */ null, false);
/* locales = */ null, false, FrameworkStatsLog
.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_APPS);
fail("Expected NullPointerException");
} finally {
verify(mMockBackupHelper, times(0)).notifyBackupManager();
@@ -183,7 +187,8 @@ public class LocaleManagerServiceTest {
setUpPassingPermissionCheckFor(Manifest.permission.CHANGE_CONFIGURATION);
mLocaleManagerService.setApplicationLocales(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID,
DEFAULT_LOCALES, true);
DEFAULT_LOCALES, true, FrameworkStatsLog
.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_DELEGATE);
assertEquals(DEFAULT_LOCALES, mFakePackageConfigurationUpdater.getStoredLocales());
verify(mMockBackupHelper, times(1)).notifyBackupManager();
@@ -196,7 +201,8 @@ public class LocaleManagerServiceTest {
.when(mMockPackageManager).getPackageUidAsUser(anyString(), any(), anyInt());
mLocaleManagerService.setApplicationLocales(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID,
DEFAULT_LOCALES, false);
DEFAULT_LOCALES, false, FrameworkStatsLog
.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_APPS);
assertEquals(DEFAULT_LOCALES, mFakePackageConfigurationUpdater.getStoredLocales());
verify(mMockBackupHelper, times(1)).notifyBackupManager();
@@ -208,7 +214,8 @@ public class LocaleManagerServiceTest {
.when(mMockPackageManager).getPackageUidAsUser(anyString(), any(), anyInt());
try {
mLocaleManagerService.setApplicationLocales(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID,
LocaleList.getEmptyLocaleList(), false);
LocaleList.getEmptyLocaleList(), false, FrameworkStatsLog
.APPLICATION_LOCALES_CHANGED__CALLER__CALLER_APPS);
fail("Expected IllegalArgumentException");
} finally {
assertNoLocalesStored(mFakePackageConfigurationUpdater.getStoredLocales());