Merge changes from topic "revert-15058002-SNQUARIDWJ" into sc-dev
* changes: Revert^2 "Deprecate Context#createApplicationContext" Revert "Version LoadedApk cache using base code path" Revert "Apply overlay changes with config change"
This commit is contained in:
@@ -36,6 +36,7 @@ import static com.android.internal.annotations.VisibleForTesting.Visibility.PACK
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.assist.AssistContent;
|
||||
import android.app.assist.AssistStructure;
|
||||
import android.app.backup.BackupAgent;
|
||||
@@ -61,6 +62,7 @@ import android.content.ContentCaptureOptions;
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Context.CreatePackageOptions;
|
||||
import android.content.IContentProvider;
|
||||
import android.content.IIntentReceiver;
|
||||
import android.content.Intent;
|
||||
@@ -71,6 +73,7 @@ import android.content.pm.IPackageManager;
|
||||
import android.content.pm.InstrumentationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.ApplicationInfoFlags;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.content.pm.PermissionInfo;
|
||||
@@ -218,8 +221,6 @@ import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.InetAddress;
|
||||
@@ -230,7 +231,6 @@ import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -419,16 +419,6 @@ public final class ActivityThread extends ClientTransactionHandler
|
||||
@GuardedBy("mResourcesManager")
|
||||
@UnsupportedAppUsage
|
||||
final ArrayMap<String, WeakReference<LoadedApk>> mResourcePackages = new ArrayMap<>();
|
||||
|
||||
@GuardedBy("mResourcesManager")
|
||||
private final ArrayMap<List<String>, WeakReference<LoadedApk>> mPackageNonAMS =
|
||||
new ArrayMap<>();
|
||||
@GuardedBy("mResourcesManager")
|
||||
private final ArrayMap<List<String>, WeakReference<LoadedApk>> mResourcePackagesNonAMS =
|
||||
new ArrayMap<>();
|
||||
@GuardedBy("mResourcesManager")
|
||||
private final ReferenceQueue<LoadedApk> mPackageRefQueue = new ReferenceQueue<>();
|
||||
|
||||
@GuardedBy("mResourcesManager")
|
||||
final ArrayList<ActivityClientRecord> mRelaunchingActivities = new ArrayList<>();
|
||||
@GuardedBy("mResourcesManager")
|
||||
@@ -1182,7 +1172,6 @@ public final class ActivityThread extends ClientTransactionHandler
|
||||
}
|
||||
|
||||
public void scheduleApplicationInfoChanged(ApplicationInfo ai) {
|
||||
mResourcesManager.updatePendingAppInfoUpdates(ai);
|
||||
mH.removeMessages(H.APPLICATION_INFO_CHANGED, ai);
|
||||
sendMessage(H.APPLICATION_INFO_CHANGED, ai);
|
||||
}
|
||||
@@ -2385,281 +2374,72 @@ public final class ActivityThread extends ClientTransactionHandler
|
||||
return mH;
|
||||
}
|
||||
|
||||
/**
|
||||
* If {@code retainReferences} is false, prunes all {@link LoadedApk} representing any of the
|
||||
* specified packages from the package caches.
|
||||
*
|
||||
* @return whether the cache contains a loaded apk representing any of the specified packages
|
||||
*/
|
||||
private boolean clearCachedApks() {
|
||||
synchronized (mResourcesManager) {
|
||||
Reference<? extends LoadedApk> enqueuedRef = mPackageRefQueue.poll();
|
||||
if (enqueuedRef == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final HashSet<Reference<? extends LoadedApk>> deadReferences = new HashSet<>();
|
||||
for (; enqueuedRef != null; enqueuedRef = mPackageRefQueue.poll()) {
|
||||
deadReferences.add(enqueuedRef);
|
||||
}
|
||||
|
||||
return cleanWeakMapValues(mPackages, deadReferences)
|
||||
|| cleanWeakMapValues(mResourcePackages, deadReferences)
|
||||
|| cleanWeakMapValues(mPackageNonAMS, deadReferences)
|
||||
|| cleanWeakMapValues(mResourcePackages, deadReferences);
|
||||
}
|
||||
}
|
||||
|
||||
private static <K> boolean cleanWeakMapValues(ArrayMap<K, WeakReference<LoadedApk>> map,
|
||||
HashSet<Reference<? extends LoadedApk>> deadReferences) {
|
||||
boolean hasPkgInfo = false;
|
||||
for (int i = map.size() - 1; i >= 0; i--) {
|
||||
if (deadReferences.contains(map.valueAt(i))) {
|
||||
map.removeAt(i);
|
||||
hasPkgInfo = true;
|
||||
}
|
||||
}
|
||||
return hasPkgInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the previously cached {@link LoadedApk} that was created/updated with the most
|
||||
* recent {@link ApplicationInfo} sent from the activity manager service.
|
||||
*/
|
||||
@Nullable
|
||||
private LoadedApk peekLatestCachedApkFromAMS(@NonNull String packageName, boolean includeCode) {
|
||||
synchronized (mResourcesManager) {
|
||||
WeakReference<LoadedApk> ref;
|
||||
if (includeCode) {
|
||||
return ((ref = mPackages.get(packageName)) != null) ? ref.get() : null;
|
||||
} else {
|
||||
return ((ref = mResourcePackages.get(packageName)) != null) ? ref.get() : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the previously cached {@link LoadedApk} that was created/updated using an
|
||||
* {@link ApplicationInfo} sent from activity manager service.
|
||||
*
|
||||
* If {@code appInfo} is null, the most up-to-date {@link ApplicationInfo} will be fetched and
|
||||
* used to update the cached package; otherwise, the specified app info will be used.
|
||||
*/
|
||||
private boolean updateLatestCachedApkFromAMS(@NonNull String packageName,
|
||||
@Nullable ApplicationInfo appInfo, boolean updateActivityRecords) {
|
||||
final LoadedApk[] loadedPackages = new LoadedApk[]{
|
||||
peekLatestCachedApkFromAMS(packageName, true),
|
||||
peekLatestCachedApkFromAMS(packageName, false)
|
||||
};
|
||||
|
||||
try {
|
||||
if (appInfo == null) {
|
||||
appInfo = sPackageManager.getApplicationInfo(
|
||||
packageName, PackageManager.GET_SHARED_LIBRARY_FILES,
|
||||
UserHandle.myUserId());
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.v(TAG, "Failed to get most recent app info for '" + packageName + "'", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean hasPackage = false;
|
||||
final String[] oldResDirs = new String[loadedPackages.length];
|
||||
for (int i = loadedPackages.length - 1; i >= 0; i--) {
|
||||
final LoadedApk loadedPackage = loadedPackages[i];
|
||||
if (loadedPackage == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the package is being updated, yet it still has a valid LoadedApk object, the
|
||||
// package was updated with PACKAGE_REMOVED_DONT_KILL. Adjust it's internal references
|
||||
// to the application info and resources.
|
||||
hasPackage = true;
|
||||
if (updateActivityRecords && mActivities.size() > 0) {
|
||||
for (ActivityClientRecord ar : mActivities.values()) {
|
||||
if (ar.activityInfo.applicationInfo.packageName.equals(packageName)) {
|
||||
ar.activityInfo.applicationInfo = appInfo;
|
||||
ar.packageInfo = loadedPackage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateLoadedApk(loadedPackage, appInfo);
|
||||
oldResDirs[i] = loadedPackage.getResDir();
|
||||
}
|
||||
if (hasPackage) {
|
||||
synchronized (mResourcesManager) {
|
||||
mResourcesManager.applyNewResourceDirs(appInfo, oldResDirs);
|
||||
}
|
||||
}
|
||||
return hasPackage;
|
||||
}
|
||||
|
||||
private static List<String> makeNonAMSKey(@NonNull ApplicationInfo appInfo) {
|
||||
final List<String> paths = new ArrayList<>();
|
||||
paths.add(appInfo.sourceDir);
|
||||
if (appInfo.resourceDirs != null) {
|
||||
for (String path : appInfo.resourceDirs) {
|
||||
paths.add(path);
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the previously cached {@link LoadedApk}.
|
||||
*
|
||||
* If {@code isAppInfoFromAMS} is true, then {@code appInfo} will be used to update the paths
|
||||
* of the previously cached {@link LoadedApk} that was created/updated using an
|
||||
* {@link ApplicationInfo} sent from activity manager service.
|
||||
*/
|
||||
@Nullable
|
||||
private LoadedApk retrieveCachedApk(@NonNull ApplicationInfo appInfo, boolean includeCode,
|
||||
boolean isAppInfoFromAMS) {
|
||||
if (UserHandle.myUserId() != UserHandle.getUserId(appInfo.uid)) {
|
||||
// Caching not supported across users.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isAppInfoFromAMS) {
|
||||
LoadedApk loadedPackage = peekLatestCachedApkFromAMS(appInfo.packageName, includeCode);
|
||||
if (loadedPackage != null) {
|
||||
updateLoadedApk(loadedPackage, appInfo);
|
||||
}
|
||||
return loadedPackage;
|
||||
}
|
||||
|
||||
synchronized (mResourcesManager) {
|
||||
WeakReference<LoadedApk> ref;
|
||||
if (includeCode) {
|
||||
return ((ref = mPackageNonAMS.get(makeNonAMSKey(appInfo))) != null)
|
||||
? ref.get() : null;
|
||||
} else {
|
||||
return ((ref = mResourcePackagesNonAMS.get(makeNonAMSKey(appInfo))) != null)
|
||||
? ref.get() : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isLoadedApkResourceDirsUpToDate(LoadedApk loadedApk,
|
||||
ApplicationInfo appInfo) {
|
||||
boolean baseDirsUpToDate = loadedApk.getResDir().equals(appInfo.sourceDir);
|
||||
boolean resourceDirsUpToDate = Arrays.equals(
|
||||
ArrayUtils.defeatNullable(appInfo.resourceDirs),
|
||||
ArrayUtils.defeatNullable(loadedApk.getOverlayDirs()));
|
||||
boolean overlayPathsUpToDate = Arrays.equals(
|
||||
ArrayUtils.defeatNullable(appInfo.overlayPaths),
|
||||
ArrayUtils.defeatNullable(loadedApk.getOverlayPaths()));
|
||||
|
||||
return (loadedApk.mResources == null || loadedApk.mResources.getAssets().isUpToDate())
|
||||
&& baseDirsUpToDate && resourceDirsUpToDate && overlayPathsUpToDate;
|
||||
}
|
||||
|
||||
private void updateLoadedApk(@NonNull LoadedApk loadedPackage,
|
||||
@NonNull ApplicationInfo appInfo) {
|
||||
if (isLoadedApkResourceDirsUpToDate(loadedPackage, appInfo)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<String> oldPaths = new ArrayList<>();
|
||||
LoadedApk.makePaths(this, appInfo, oldPaths);
|
||||
loadedPackage.updateApplicationInfo(appInfo, oldPaths);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private LoadedApk createLoadedPackage(@NonNull ApplicationInfo appInfo,
|
||||
@Nullable CompatibilityInfo compatInfo, @Nullable ClassLoader baseLoader,
|
||||
boolean securityViolation, boolean includeCode, boolean registerPackage,
|
||||
boolean isAppInfoFromAMS) {
|
||||
final LoadedApk packageInfo =
|
||||
new LoadedApk(this, appInfo, compatInfo, baseLoader,
|
||||
securityViolation, includeCode
|
||||
&& (appInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage);
|
||||
|
||||
if (mSystemThread && "android".equals(appInfo.packageName)) {
|
||||
packageInfo.installSystemApplicationInfo(appInfo,
|
||||
getSystemContext().mPackageInfo.getClassLoader());
|
||||
}
|
||||
|
||||
if (UserHandle.myUserId() != UserHandle.getUserId(appInfo.uid)) {
|
||||
// Caching not supported across users
|
||||
return packageInfo;
|
||||
}
|
||||
|
||||
synchronized (mResourcesManager) {
|
||||
if (includeCode) {
|
||||
if (isAppInfoFromAMS) {
|
||||
mPackages.put(appInfo.packageName,
|
||||
new WeakReference<>(packageInfo, mPackageRefQueue));
|
||||
} else {
|
||||
mPackageNonAMS.put(makeNonAMSKey(appInfo),
|
||||
new WeakReference<>(packageInfo, mPackageRefQueue));
|
||||
}
|
||||
} else {
|
||||
if (isAppInfoFromAMS) {
|
||||
mResourcePackages.put(appInfo.packageName,
|
||||
new WeakReference<>(packageInfo, mPackageRefQueue));
|
||||
} else {
|
||||
mResourcePackagesNonAMS.put(makeNonAMSKey(appInfo),
|
||||
new WeakReference<>(packageInfo, mPackageRefQueue));
|
||||
}
|
||||
}
|
||||
return packageInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
|
||||
public final LoadedApk getPackageInfo(String packageName, CompatibilityInfo compatInfo,
|
||||
int flags) {
|
||||
@CreatePackageOptions int flags) {
|
||||
return getPackageInfo(packageName, compatInfo, flags, UserHandle.myUserId());
|
||||
}
|
||||
|
||||
public final LoadedApk getPackageInfo(String packageName, CompatibilityInfo compatInfo,
|
||||
int flags, int userId) {
|
||||
final ApplicationInfo ai = PackageManager.getApplicationInfoAsUserCached(
|
||||
@CreatePackageOptions int flags, @UserIdInt int userId) {
|
||||
return getPackageInfo(packageName, compatInfo, flags, userId, 0 /* packageFlags */);
|
||||
}
|
||||
|
||||
public final LoadedApk getPackageInfo(String packageName, CompatibilityInfo compatInfo,
|
||||
@CreatePackageOptions int flags, @UserIdInt int userId,
|
||||
@ApplicationInfoFlags int packageFlags) {
|
||||
final boolean differentUser = (UserHandle.myUserId() != userId);
|
||||
ApplicationInfo ai = PackageManager.getApplicationInfoAsUserCached(
|
||||
packageName,
|
||||
PackageManager.GET_SHARED_LIBRARY_FILES
|
||||
packageFlags | PackageManager.GET_SHARED_LIBRARY_FILES
|
||||
| PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
|
||||
(userId < 0) ? UserHandle.myUserId() : userId);
|
||||
LoadedApk packageInfo = null;
|
||||
if (ai != null) {
|
||||
packageInfo = retrieveCachedApk(ai,
|
||||
(flags & Context.CONTEXT_INCLUDE_CODE) != 0,
|
||||
false);
|
||||
}
|
||||
|
||||
if (packageInfo != null) {
|
||||
if (packageInfo.isSecurityViolation()
|
||||
&& (flags & Context.CONTEXT_IGNORE_SECURITY) == 0) {
|
||||
throw new SecurityException(
|
||||
"Requesting code from " + packageName
|
||||
+ " to be run in process "
|
||||
+ mBoundApplication.processName
|
||||
+ "/" + mBoundApplication.appInfo.uid);
|
||||
synchronized (mResourcesManager) {
|
||||
WeakReference<LoadedApk> ref;
|
||||
if (differentUser) {
|
||||
// Caching not supported across users
|
||||
ref = null;
|
||||
} else if ((flags & Context.CONTEXT_INCLUDE_CODE) != 0) {
|
||||
ref = mPackages.get(packageName);
|
||||
} else {
|
||||
ref = mResourcePackages.get(packageName);
|
||||
}
|
||||
|
||||
LoadedApk packageInfo = ref != null ? ref.get() : null;
|
||||
if (ai != null && packageInfo != null) {
|
||||
if (!isLoadedApkResourceDirsUpToDate(packageInfo, ai)) {
|
||||
List<String> oldPaths = new ArrayList<>();
|
||||
LoadedApk.makePaths(this, ai, oldPaths);
|
||||
packageInfo.updateApplicationInfo(ai, oldPaths);
|
||||
}
|
||||
|
||||
if (packageInfo.isSecurityViolation()
|
||||
&& (flags&Context.CONTEXT_IGNORE_SECURITY) == 0) {
|
||||
throw new SecurityException(
|
||||
"Requesting code from " + packageName
|
||||
+ " to be run in process "
|
||||
+ mBoundApplication.processName
|
||||
+ "/" + mBoundApplication.appInfo.uid);
|
||||
}
|
||||
return packageInfo;
|
||||
}
|
||||
return packageInfo;
|
||||
}
|
||||
|
||||
return ai == null ? null : getPackageInfo(ai, compatInfo, flags, false);
|
||||
if (ai != null) {
|
||||
return getPackageInfo(ai, compatInfo, flags);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getPackageInfo(ApplicationInfo, CompatibilityInfo, int, boolean)}
|
||||
* instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@UnsupportedAppUsage(trackingBug = 171933273)
|
||||
public final LoadedApk getPackageInfo(ApplicationInfo ai, CompatibilityInfo compatInfo,
|
||||
int flags) {
|
||||
return getPackageInfo(ai, compatInfo, flags, true);
|
||||
}
|
||||
|
||||
public final LoadedApk getPackageInfo(ApplicationInfo ai, CompatibilityInfo compatInfo,
|
||||
@Context.CreatePackageOptions int flags, boolean isAppInfoFromAMS) {
|
||||
@CreatePackageOptions int flags) {
|
||||
boolean includeCode = (flags&Context.CONTEXT_INCLUDE_CODE) != 0;
|
||||
boolean securityViolation = includeCode && ai.uid != 0
|
||||
&& ai.uid != Process.SYSTEM_UID && (mBoundApplication == null
|
||||
|| !UserHandle.isSameApp(ai.uid, mBoundApplication.appInfo.uid));
|
||||
&& ai.uid != Process.SYSTEM_UID && (mBoundApplication != null
|
||||
? !UserHandle.isSameApp(ai.uid, mBoundApplication.appInfo.uid)
|
||||
: true);
|
||||
boolean registerPackage = includeCode && (flags&Context.CONTEXT_REGISTER_PACKAGE) != 0;
|
||||
if ((flags&(Context.CONTEXT_INCLUDE_CODE
|
||||
|Context.CONTEXT_IGNORE_SECURITY))
|
||||
@@ -2669,47 +2449,107 @@ public final class ActivityThread extends ClientTransactionHandler
|
||||
+ " (with uid " + ai.uid + ")";
|
||||
if (mBoundApplication != null) {
|
||||
msg = msg + " to be run in process "
|
||||
+ mBoundApplication.processName + " (with uid "
|
||||
+ mBoundApplication.appInfo.uid + ")";
|
||||
+ mBoundApplication.processName + " (with uid "
|
||||
+ mBoundApplication.appInfo.uid + ")";
|
||||
}
|
||||
throw new SecurityException(msg);
|
||||
}
|
||||
}
|
||||
return getPackageInfo(ai, compatInfo, null, securityViolation, includeCode,
|
||||
registerPackage, isAppInfoFromAMS);
|
||||
registerPackage);
|
||||
}
|
||||
|
||||
@Override
|
||||
@UnsupportedAppUsage
|
||||
public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
|
||||
CompatibilityInfo compatInfo) {
|
||||
return getPackageInfo(ai, compatInfo, null, false, true, false, true);
|
||||
return getPackageInfo(ai, compatInfo, null, false, true, false);
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
|
||||
public final LoadedApk peekPackageInfo(String packageName, boolean includeCode) {
|
||||
synchronized (mResourcesManager) {
|
||||
return peekLatestCachedApkFromAMS(packageName, includeCode);
|
||||
WeakReference<LoadedApk> ref;
|
||||
if (includeCode) {
|
||||
ref = mPackages.get(packageName);
|
||||
} else {
|
||||
ref = mResourcePackages.get(packageName);
|
||||
}
|
||||
return ref != null ? ref.get() : null;
|
||||
}
|
||||
}
|
||||
|
||||
private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
|
||||
ClassLoader baseLoader, boolean securityViolation, boolean includeCode,
|
||||
boolean registerPackage, boolean isAppInfoFromAMS) {
|
||||
LoadedApk packageInfo = retrieveCachedApk(aInfo, includeCode,
|
||||
isAppInfoFromAMS);
|
||||
if (packageInfo != null) {
|
||||
boolean registerPackage) {
|
||||
final boolean differentUser = (UserHandle.myUserId() != UserHandle.getUserId(aInfo.uid));
|
||||
synchronized (mResourcesManager) {
|
||||
WeakReference<LoadedApk> ref;
|
||||
if (differentUser) {
|
||||
// Caching not supported across users
|
||||
ref = null;
|
||||
} else if (includeCode) {
|
||||
ref = mPackages.get(aInfo.packageName);
|
||||
} else {
|
||||
ref = mResourcePackages.get(aInfo.packageName);
|
||||
}
|
||||
|
||||
LoadedApk packageInfo = ref != null ? ref.get() : null;
|
||||
|
||||
if (packageInfo != null) {
|
||||
if (!isLoadedApkResourceDirsUpToDate(packageInfo, aInfo)) {
|
||||
List<String> oldPaths = new ArrayList<>();
|
||||
LoadedApk.makePaths(this, aInfo, oldPaths);
|
||||
packageInfo.updateApplicationInfo(aInfo, oldPaths);
|
||||
}
|
||||
|
||||
return packageInfo;
|
||||
}
|
||||
|
||||
if (localLOGV) {
|
||||
Slog.v(TAG, (includeCode ? "Loading code package "
|
||||
: "Loading resource-only package ") + aInfo.packageName
|
||||
+ " (in " + (mBoundApplication != null
|
||||
? mBoundApplication.processName : null)
|
||||
+ ")");
|
||||
}
|
||||
|
||||
packageInfo =
|
||||
new LoadedApk(this, aInfo, compatInfo, baseLoader,
|
||||
securityViolation, includeCode
|
||||
&& (aInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage);
|
||||
|
||||
if (mSystemThread && "android".equals(aInfo.packageName)) {
|
||||
packageInfo.installSystemApplicationInfo(aInfo,
|
||||
getSystemContext().mPackageInfo.getClassLoader());
|
||||
}
|
||||
|
||||
if (differentUser) {
|
||||
// Caching not supported across users
|
||||
} else if (includeCode) {
|
||||
mPackages.put(aInfo.packageName,
|
||||
new WeakReference<LoadedApk>(packageInfo));
|
||||
} else {
|
||||
mResourcePackages.put(aInfo.packageName,
|
||||
new WeakReference<LoadedApk>(packageInfo));
|
||||
}
|
||||
|
||||
return packageInfo;
|
||||
}
|
||||
if (localLOGV) {
|
||||
Slog.v(TAG, (includeCode ? "Loading code package "
|
||||
: "Loading resource-only package ") + aInfo.packageName
|
||||
+ " (in " + (mBoundApplication != null
|
||||
? mBoundApplication.processName : null)
|
||||
+ ")");
|
||||
}
|
||||
return createLoadedPackage(aInfo, compatInfo, baseLoader,
|
||||
securityViolation, includeCode, registerPackage, isAppInfoFromAMS);
|
||||
}
|
||||
|
||||
private static boolean isLoadedApkResourceDirsUpToDate(LoadedApk loadedApk,
|
||||
ApplicationInfo appInfo) {
|
||||
Resources packageResources = loadedApk.mResources;
|
||||
boolean resourceDirsUpToDate = Arrays.equals(
|
||||
ArrayUtils.defeatNullable(appInfo.resourceDirs),
|
||||
ArrayUtils.defeatNullable(loadedApk.getOverlayDirs()));
|
||||
boolean overlayPathsUpToDate = Arrays.equals(
|
||||
ArrayUtils.defeatNullable(appInfo.overlayPaths),
|
||||
ArrayUtils.defeatNullable(loadedApk.getOverlayPaths()));
|
||||
|
||||
return (packageResources == null || packageResources.getAssets().isUpToDate())
|
||||
&& resourceDirsUpToDate && overlayPathsUpToDate;
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage
|
||||
@@ -3671,7 +3511,7 @@ public final class ActivityThread extends ClientTransactionHandler
|
||||
ActivityInfo aInfo = r.activityInfo;
|
||||
if (r.packageInfo == null) {
|
||||
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
|
||||
Context.CONTEXT_INCLUDE_CODE, true);
|
||||
Context.CONTEXT_INCLUDE_CODE);
|
||||
}
|
||||
|
||||
ComponentName component = r.intent.getComponent();
|
||||
@@ -6154,10 +5994,40 @@ public final class ActivityThread extends ClientTransactionHandler
|
||||
|
||||
@VisibleForTesting(visibility = PACKAGE)
|
||||
public void handleApplicationInfoChanged(@NonNull final ApplicationInfo ai) {
|
||||
// Updates triggered by package installation go through a package update receiver. Here we
|
||||
// try to capture ApplicationInfo changes that are caused by other sources, such as
|
||||
// overlays. That means we want to be as conservative about code changes as possible.
|
||||
updateLatestCachedApkFromAMS(ai.packageName, ai, false);
|
||||
// Updates triggered by package installation go through a package update
|
||||
// receiver. Here we try to capture ApplicationInfo changes that are
|
||||
// caused by other sources, such as overlays. That means we want to be as conservative
|
||||
// about code changes as possible. Take the diff of the old ApplicationInfo and the new
|
||||
// to see if anything needs to change.
|
||||
LoadedApk apk;
|
||||
LoadedApk resApk;
|
||||
// Update all affected loaded packages with new package information
|
||||
synchronized (mResourcesManager) {
|
||||
WeakReference<LoadedApk> ref = mPackages.get(ai.packageName);
|
||||
apk = ref != null ? ref.get() : null;
|
||||
ref = mResourcePackages.get(ai.packageName);
|
||||
resApk = ref != null ? ref.get() : null;
|
||||
}
|
||||
|
||||
final String[] oldResDirs = new String[2];
|
||||
|
||||
if (apk != null) {
|
||||
oldResDirs[0] = apk.getResDir();
|
||||
final ArrayList<String> oldPaths = new ArrayList<>();
|
||||
LoadedApk.makePaths(this, apk.getApplicationInfo(), oldPaths);
|
||||
apk.updateApplicationInfo(ai, oldPaths);
|
||||
}
|
||||
if (resApk != null) {
|
||||
oldResDirs[1] = resApk.getResDir();
|
||||
final ArrayList<String> oldPaths = new ArrayList<>();
|
||||
LoadedApk.makePaths(this, resApk.getApplicationInfo(), oldPaths);
|
||||
resApk.updateApplicationInfo(ai, oldPaths);
|
||||
}
|
||||
|
||||
synchronized (mResourcesManager) {
|
||||
// Update all affected Resources objects to use new ResourcesImpl
|
||||
mResourcesManager.applyNewResourceDirs(ai, oldResDirs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6334,7 +6204,29 @@ public final class ActivityThread extends ClientTransactionHandler
|
||||
case ApplicationThreadConstants.PACKAGE_REMOVED:
|
||||
case ApplicationThreadConstants.PACKAGE_REMOVED_DONT_KILL:
|
||||
{
|
||||
hasPkgInfo = clearCachedApks();
|
||||
final boolean killApp = cmd == ApplicationThreadConstants.PACKAGE_REMOVED;
|
||||
if (packages == null) {
|
||||
break;
|
||||
}
|
||||
synchronized (mResourcesManager) {
|
||||
for (int i = packages.length - 1; i >= 0; i--) {
|
||||
if (!hasPkgInfo) {
|
||||
WeakReference<LoadedApk> ref = mPackages.get(packages[i]);
|
||||
if (ref != null && ref.get() != null) {
|
||||
hasPkgInfo = true;
|
||||
} else {
|
||||
ref = mResourcePackages.get(packages[i]);
|
||||
if (ref != null && ref.get() != null) {
|
||||
hasPkgInfo = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (killApp) {
|
||||
mPackages.remove(packages[i]);
|
||||
mResourcePackages.remove(packages[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ApplicationThreadConstants.PACKAGE_REPLACED:
|
||||
@@ -6342,19 +6234,68 @@ public final class ActivityThread extends ClientTransactionHandler
|
||||
if (packages == null) {
|
||||
break;
|
||||
}
|
||||
final List<String> packagesHandled = new ArrayList<>();
|
||||
for (int i = packages.length - 1; i >= 0; i--) {
|
||||
final String packageName = packages[i];
|
||||
if (updateLatestCachedApkFromAMS(packageName, null, true)) {
|
||||
hasPkgInfo = true;
|
||||
packagesHandled.add(packageName);
|
||||
|
||||
List<String> packagesHandled = new ArrayList<>();
|
||||
|
||||
synchronized (mResourcesManager) {
|
||||
for (int i = packages.length - 1; i >= 0; i--) {
|
||||
String packageName = packages[i];
|
||||
WeakReference<LoadedApk> ref = mPackages.get(packageName);
|
||||
LoadedApk pkgInfo = ref != null ? ref.get() : null;
|
||||
if (pkgInfo != null) {
|
||||
hasPkgInfo = true;
|
||||
} else {
|
||||
ref = mResourcePackages.get(packageName);
|
||||
pkgInfo = ref != null ? ref.get() : null;
|
||||
if (pkgInfo != null) {
|
||||
hasPkgInfo = true;
|
||||
}
|
||||
}
|
||||
// If the package is being replaced, yet it still has a valid
|
||||
// LoadedApk object, the package was updated with _DONT_KILL.
|
||||
// Adjust it's internal references to the application info and
|
||||
// resources.
|
||||
if (pkgInfo != null) {
|
||||
packagesHandled.add(packageName);
|
||||
try {
|
||||
final ApplicationInfo aInfo =
|
||||
sPackageManager.getApplicationInfo(
|
||||
packageName,
|
||||
PackageManager.GET_SHARED_LIBRARY_FILES,
|
||||
UserHandle.myUserId());
|
||||
|
||||
if (mActivities.size() > 0) {
|
||||
for (ActivityClientRecord ar : mActivities.values()) {
|
||||
if (ar.activityInfo.applicationInfo.packageName
|
||||
.equals(packageName)) {
|
||||
ar.activityInfo.applicationInfo = aInfo;
|
||||
ar.packageInfo = pkgInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final String[] oldResDirs = { pkgInfo.getResDir() };
|
||||
|
||||
final ArrayList<String> oldPaths = new ArrayList<>();
|
||||
LoadedApk.makePaths(this, pkgInfo.getApplicationInfo(), oldPaths);
|
||||
pkgInfo.updateApplicationInfo(aInfo, oldPaths);
|
||||
|
||||
synchronized (mResourcesManager) {
|
||||
// Update affected Resources objects to use new ResourcesImpl
|
||||
mResourcesManager.applyNewResourceDirs(aInfo, oldResDirs);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
getPackageManager().notifyPackagesReplacedReceived(
|
||||
packagesHandled.toArray(new String[0]));
|
||||
} catch (RemoteException ignored) {
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -6913,7 +6854,7 @@ public final class ActivityThread extends ClientTransactionHandler
|
||||
ii.copyTo(instrApp);
|
||||
instrApp.initForUser(UserHandle.myUserId());
|
||||
final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
|
||||
appContext.getClassLoader(), false, true, false, true);
|
||||
appContext.getClassLoader(), false, true, false);
|
||||
|
||||
// The test context's op package name == the target app's op package name, because
|
||||
// the app ops manager checks the op package name against the real calling UID,
|
||||
|
||||
@@ -48,6 +48,7 @@ import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.ApplicationInfoFlags;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.res.CompatResources;
|
||||
@@ -2461,7 +2462,7 @@ class ContextImpl extends Context {
|
||||
public Context createApplicationContext(ApplicationInfo application, int flags)
|
||||
throws NameNotFoundException {
|
||||
LoadedApk pi = mMainThread.getPackageInfo(application, mResources.getCompatibilityInfo(),
|
||||
flags | CONTEXT_REGISTER_PACKAGE, false);
|
||||
flags | CONTEXT_REGISTER_PACKAGE);
|
||||
if (pi != null) {
|
||||
ContextImpl c = new ContextImpl(this, mMainThread, pi, ContextParams.EMPTY,
|
||||
mAttributionSource.getAttributionTag(),
|
||||
@@ -2493,6 +2494,13 @@ class ContextImpl extends Context {
|
||||
@Override
|
||||
public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)
|
||||
throws NameNotFoundException {
|
||||
return createPackageContextAsUser(packageName, flags, user, 0 /* packageFlags */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context createPackageContextAsUser(
|
||||
@NonNull String packageName, @CreatePackageOptions int flags, @NonNull UserHandle user,
|
||||
@ApplicationInfoFlags int packageFlags) throws PackageManager.NameNotFoundException {
|
||||
if (packageName.equals("system") || packageName.equals("android")) {
|
||||
// The system resources are loaded in every application, so we can safely copy
|
||||
// the context without reloading Resources.
|
||||
@@ -2503,7 +2511,7 @@ class ContextImpl extends Context {
|
||||
}
|
||||
|
||||
LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
|
||||
flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier());
|
||||
flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier(), packageFlags);
|
||||
if (pi != null) {
|
||||
ContextImpl c = new ContextImpl(this, mMainThread, pi, mParams,
|
||||
mAttributionSource.getAttributionTag(),
|
||||
|
||||
@@ -6344,10 +6344,11 @@ public class Notification implements Parcelable
|
||||
ApplicationInfo applicationInfo = n.extras.getParcelable(
|
||||
EXTRA_BUILDER_APPLICATION_INFO);
|
||||
Context builderContext;
|
||||
if (applicationInfo != null) {
|
||||
if (applicationInfo != null && applicationInfo.packageName != null) {
|
||||
try {
|
||||
builderContext = context.createApplicationContext(applicationInfo,
|
||||
Context.CONTEXT_RESTRICTED);
|
||||
builderContext = context.createPackageContextAsUser(applicationInfo.packageName,
|
||||
Context.CONTEXT_RESTRICTED,
|
||||
UserHandle.getUserHandleForUid(applicationInfo.uid));
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.e(TAG, "ApplicationInfo " + applicationInfo + " not found");
|
||||
builderContext = context; // try with our context
|
||||
|
||||
@@ -97,12 +97,6 @@ public class ResourcesManager {
|
||||
*/
|
||||
private int mResDisplayId = DEFAULT_DISPLAY;
|
||||
|
||||
/**
|
||||
* ApplicationInfo changes that need to be applied to Resources when the next configuration
|
||||
* change occurs.
|
||||
*/
|
||||
private ArrayList<ApplicationInfo> mPendingAppInfoUpdates;
|
||||
|
||||
/**
|
||||
* A mapping of ResourceImpls and their configurations. These are heavy weight objects
|
||||
* which should be reused as much as possible.
|
||||
@@ -994,7 +988,7 @@ public class ResourcesManager {
|
||||
* @param classLoader The classloader to use for the Resources object.
|
||||
* If null, {@link ClassLoader#getSystemClassLoader()} is used.
|
||||
* @return A Resources object that gets updated when
|
||||
* {@link #applyConfigurationToResources(Configuration, CompatibilityInfo)}
|
||||
* {@link #applyConfigurationToResourcesLocked(Configuration, CompatibilityInfo)}
|
||||
* is called.
|
||||
*/
|
||||
@Nullable
|
||||
@@ -1121,8 +1115,8 @@ public class ResourcesManager {
|
||||
/**
|
||||
* Updates an Activity's Resources object with overrideConfig. The Resources object
|
||||
* that was previously returned by {@link #getResources(IBinder, String, String[], String[],
|
||||
* String[], String[], Integer, Configuration, CompatibilityInfo, ClassLoader, List)} is still
|
||||
* valid and will have the updated configuration.
|
||||
* String[], Integer, Configuration, CompatibilityInfo, ClassLoader, List)} is still valid and
|
||||
* will have the updated configuration.
|
||||
*
|
||||
* @param activityToken The Activity token.
|
||||
* @param overrideConfig The configuration override to update.
|
||||
@@ -1273,22 +1267,6 @@ public class ResourcesManager {
|
||||
return newKey;
|
||||
}
|
||||
|
||||
public void updatePendingAppInfoUpdates(@NonNull ApplicationInfo appInfo) {
|
||||
synchronized (mLock) {
|
||||
if (mPendingAppInfoUpdates == null) {
|
||||
mPendingAppInfoUpdates = new ArrayList<>();
|
||||
}
|
||||
// Clear previous app info changes for the package to prevent multiple ResourcesImpl
|
||||
// recreations when only the last recreation will be used.
|
||||
for (int i = mPendingAppInfoUpdates.size() - 1; i >= 0; i--) {
|
||||
if (appInfo.sourceDir.equals(mPendingAppInfoUpdates.get(i).sourceDir)) {
|
||||
mPendingAppInfoUpdates.remove(i);
|
||||
}
|
||||
}
|
||||
mPendingAppInfoUpdates.add(appInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public final boolean applyConfigurationToResources(@NonNull Configuration config,
|
||||
@Nullable CompatibilityInfo compat) {
|
||||
return applyConfigurationToResources(config, compat, null /* adjustments */);
|
||||
@@ -1302,18 +1280,7 @@ public class ResourcesManager {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
|
||||
"ResourcesManager#applyConfigurationToResources");
|
||||
|
||||
final boolean assetsUpdated = mPendingAppInfoUpdates != null
|
||||
&& config.assetsSeq > mResConfiguration.assetsSeq;
|
||||
if (assetsUpdated) {
|
||||
for (int i = 0, n = mPendingAppInfoUpdates.size(); i < n; i++) {
|
||||
final ApplicationInfo appInfo = mPendingAppInfoUpdates.get(i);
|
||||
applyNewResourceDirs(appInfo, new String[]{appInfo.sourceDir});
|
||||
}
|
||||
mPendingAppInfoUpdates = null;
|
||||
}
|
||||
|
||||
if (!assetsUpdated && !mResConfiguration.isOtherSeqNewer(config)
|
||||
&& compat == null) {
|
||||
if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) {
|
||||
if (DEBUG || DEBUG_CONFIGURATION) {
|
||||
Slog.v(TAG, "Skipping new config: curSeq="
|
||||
+ mResConfiguration.seq + ", newSeq=" + config.seq);
|
||||
@@ -1353,7 +1320,7 @@ public class ResourcesManager {
|
||||
}
|
||||
}
|
||||
|
||||
return assetsUpdated || changes != 0;
|
||||
return changes != 0;
|
||||
} finally {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.Parcelable;
|
||||
import android.os.UserHandle;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
@@ -718,9 +719,10 @@ public class AppWidgetHostView extends FrameLayout {
|
||||
protected Context getRemoteContext() {
|
||||
try {
|
||||
// Return if cloned successfully, otherwise default
|
||||
Context newContext = mContext.createApplicationContext(
|
||||
mInfo.providerInfo.applicationInfo,
|
||||
Context.CONTEXT_RESTRICTED);
|
||||
final ApplicationInfo info = mInfo.providerInfo.applicationInfo;
|
||||
Context newContext = mContext.createPackageContextAsUser(info.packageName,
|
||||
Context.CONTEXT_RESTRICTED,
|
||||
UserHandle.getUserHandleForUid(info.uid));
|
||||
if (mColorResources != null) {
|
||||
mColorResources.apply(newContext);
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ import android.app.time.TimeManager;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.ApplicationInfoFlags;
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Configuration;
|
||||
@@ -6267,6 +6268,23 @@ public abstract class Context {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link #createPackageContextAsUser(String, int, UserHandle)}, but also allows
|
||||
* specifying the flags used to retrieve the {@link ApplicationInfo} of the package.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
public Context createPackageContextAsUser(
|
||||
@NonNull String packageName, @CreatePackageOptions int flags, @NonNull UserHandle user,
|
||||
@ApplicationInfoFlags int packageFlags)
|
||||
throws PackageManager.NameNotFoundException {
|
||||
if (Build.IS_ENG) {
|
||||
throw new IllegalStateException("createPackageContextAsUser not overridden!");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link #createPackageContext(String, int)}, but for the own package with a
|
||||
* different {@link UserHandle}. For example, {@link #getContentResolver()}
|
||||
@@ -6286,10 +6304,18 @@ public abstract class Context {
|
||||
/**
|
||||
* Creates a context given an {@link android.content.pm.ApplicationInfo}.
|
||||
*
|
||||
* @deprecated use {@link #createPackageContextAsUser(String, int, UserHandle, int)}
|
||||
* If an application caches an ApplicationInfo and uses it to call this method,
|
||||
* the app will not get the most recent version of Runtime Resource Overlays for
|
||||
* that application. To make things worse, the LoadedApk stored in
|
||||
* {@code ActivityThread#mResourcePackages} is updated using the old ApplicationInfo
|
||||
* causing further uses of the cached LoadedApk to return outdated information.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SuppressWarnings("HiddenAbstractMethod")
|
||||
@UnsupportedAppUsage
|
||||
@Deprecated
|
||||
public abstract Context createApplicationContext(ApplicationInfo application,
|
||||
@CreatePackageOptions int flags) throws PackageManager.NameNotFoundException;
|
||||
|
||||
|
||||
@@ -1007,6 +1007,14 @@ public class ContextWrapper extends Context {
|
||||
return mBase.createPackageContextAsUser(packageName, flags, user);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public Context createPackageContextAsUser(String packageName, int flags, UserHandle user,
|
||||
int packageFlags)
|
||||
throws PackageManager.NameNotFoundException {
|
||||
return mBase.createPackageContextAsUser(packageName, flags, user, packageFlags);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public Context createContextAsUser(UserHandle user, @CreatePackageOptions int flags) {
|
||||
|
||||
@@ -434,11 +434,8 @@ public class StatusBarNotification implements Parcelable {
|
||||
public Context getPackageContext(Context context) {
|
||||
if (mContext == null) {
|
||||
try {
|
||||
ApplicationInfo ai = context.getPackageManager()
|
||||
.getApplicationInfoAsUser(pkg, PackageManager.MATCH_UNINSTALLED_PACKAGES,
|
||||
getUserId());
|
||||
mContext = context.createApplicationContext(ai,
|
||||
Context.CONTEXT_RESTRICTED);
|
||||
mContext = context.createPackageContextAsUser(pkg, Context.CONTEXT_RESTRICTED, user,
|
||||
PackageManager.MATCH_UNINSTALLED_PACKAGES);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
mContext = null;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemClock;
|
||||
import android.os.Trace;
|
||||
import android.os.UserHandle;
|
||||
import android.util.AndroidRuntimeException;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
@@ -467,9 +468,12 @@ public final class WebViewFactory {
|
||||
sTimestamps.mCreateContextStart = SystemClock.uptimeMillis();
|
||||
try {
|
||||
// Construct an app context to load the Java code into the current app.
|
||||
Context webViewContext = initialApplication.createApplicationContext(
|
||||
ai,
|
||||
Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
|
||||
Context webViewContext = initialApplication.createPackageContextAsUser(
|
||||
ai.packageName,
|
||||
Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY,
|
||||
UserHandle.getUserHandleForUid(ai.uid),
|
||||
PackageManager.MATCH_UNINSTALLED_PACKAGES
|
||||
| PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
|
||||
sPackageInfo = newPackageInfo;
|
||||
return webViewContext;
|
||||
} finally {
|
||||
|
||||
@@ -5831,8 +5831,9 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
return context;
|
||||
}
|
||||
try {
|
||||
return context.createApplicationContext(mApplication,
|
||||
Context.CONTEXT_RESTRICTED);
|
||||
return context.createPackageContextAsUser(mApplication.packageName,
|
||||
Context.CONTEXT_RESTRICTED,
|
||||
UserHandle.getUserHandleForUid(mApplication.uid));
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.e(LOG_TAG, "Package name " + mApplication.packageName + " not found");
|
||||
}
|
||||
|
||||
@@ -121,8 +121,6 @@ java_genrule {
|
||||
":FrameworksCoreTests_keyset_splat_api",
|
||||
":FrameworksCoreTests_locales",
|
||||
":FrameworksCoreTests_overlay_config",
|
||||
":FrameworksCoreTests_res_version_after",
|
||||
":FrameworksCoreTests_res_version_before",
|
||||
":FrameworksCoreTests_version_1",
|
||||
":FrameworksCoreTests_version_1_diff",
|
||||
":FrameworksCoreTests_version_1_nosys",
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
package {
|
||||
// See: http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// all of the 'license_kinds' from "frameworks_base_license"
|
||||
// to get the below license kinds:
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["frameworks_base_license"],
|
||||
}
|
||||
|
||||
android_test_helper_app {
|
||||
name: "FrameworksCoreTests_res_version_before",
|
||||
defaults: ["FrameworksCoreTests_apks_defaults"],
|
||||
resource_dirs: ["res_before"],
|
||||
certificate: ":FrameworksCoreTests_unit_test_cert",
|
||||
}
|
||||
|
||||
android_test_helper_app {
|
||||
name: "FrameworksCoreTests_res_version_after",
|
||||
defaults: ["FrameworksCoreTests_apks_defaults"],
|
||||
resource_dirs: ["res_after"],
|
||||
certificate: ":FrameworksCoreTests_unit_test_cert",
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2021 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.frameworks.coretests.res_version">
|
||||
<application android:hasCode="false"/>
|
||||
</manifest>
|
||||
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
~ Copyright (C) 2021 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="version">after</string>
|
||||
<public type="string" name="version" id="0x7f010000"/>
|
||||
</resources>
|
||||
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
~ Copyright (C) 2021 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="version">before</string>
|
||||
<public type="string" name="version" id="0x7f010000"/>
|
||||
</resources>
|
||||
@@ -25,23 +25,15 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.app.ActivityThread;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInstaller;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.VirtualDisplay;
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
import android.media.ImageReader;
|
||||
import android.os.FileUtils;
|
||||
import android.os.UserHandle;
|
||||
import android.view.Display;
|
||||
|
||||
@@ -50,20 +42,12 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.compatibility.common.util.ShellIdentityUtils;
|
||||
import com.android.frameworks.coretests.R;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Build/Install/Run:
|
||||
* atest FrameworksCoreTests:ContextTest
|
||||
* Build/Install/Run:
|
||||
* atest FrameworksCoreTests:ContextTest
|
||||
*/
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@@ -232,132 +216,6 @@ public class ContextTest {
|
||||
assertFalse(context.isUiContext());
|
||||
}
|
||||
|
||||
private static class TestReceiver extends BroadcastReceiver implements AutoCloseable {
|
||||
private static final String INTENT_ACTION = "com.android.server.pm.test.test_app.action";
|
||||
private final ArrayBlockingQueue<Intent> mResults = new ArrayBlockingQueue<>(1);
|
||||
|
||||
public IntentSender makeIntentSender() {
|
||||
return PendingIntent.getBroadcast(getContext(), 0, new Intent(INTENT_ACTION),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED)
|
||||
.getIntentSender();
|
||||
}
|
||||
|
||||
public void waitForIntent() throws InterruptedException {
|
||||
assertNotNull(mResults.poll(30, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
mResults.add(intent);
|
||||
}
|
||||
|
||||
public void register() {
|
||||
getContext().registerReceiver(this, new IntentFilter(INTENT_ACTION));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
getContext().unregisterReceiver(this);
|
||||
}
|
||||
|
||||
private Context getContext() {
|
||||
return InstrumentationRegistry.getInstrumentation().getContext();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void applicationContextBeforeAndAfterUpgrade() throws Exception {
|
||||
final Context context = InstrumentationRegistry.getInstrumentation().getContext();
|
||||
final String testPackageName = "com.android.frameworks.coretests.res_version";
|
||||
try {
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
final int versionRes = 0x7f010000;
|
||||
|
||||
final Context appContext = ApplicationProvider.getApplicationContext();
|
||||
installApk(appContext, R.raw.res_version_before);
|
||||
|
||||
ApplicationInfo info = pm.getApplicationInfo(testPackageName, 0);
|
||||
final Context beforeContext = appContext.createApplicationContext(info, 0);
|
||||
assertEquals("before", beforeContext.getResources().getString(versionRes));
|
||||
|
||||
installApk(appContext, R.raw.res_version_after);
|
||||
|
||||
info = pm.getApplicationInfo(testPackageName, 0);
|
||||
final Context afterContext = appContext.createApplicationContext(info, 0);
|
||||
assertEquals("before", beforeContext.createConfigurationContext(Configuration.EMPTY)
|
||||
.getResources().getString(versionRes));
|
||||
assertEquals("after", afterContext.createConfigurationContext(Configuration.EMPTY)
|
||||
.getResources().getString(versionRes));
|
||||
assertNotEquals(beforeContext.getPackageResourcePath(),
|
||||
afterContext.getPackageResourcePath());
|
||||
} finally {
|
||||
uninstallPackage(context, testPackageName);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void packageContextBeforeAndAfterUpgrade() throws Exception {
|
||||
final Context context = InstrumentationRegistry.getInstrumentation().getContext();
|
||||
final String testPackageName = "com.android.frameworks.coretests.res_version";
|
||||
try {
|
||||
final int versionRes = 0x7f010000;
|
||||
final Context appContext = ApplicationProvider.getApplicationContext();
|
||||
installApk(appContext, R.raw.res_version_before);
|
||||
|
||||
final Context beforeContext = appContext.createPackageContext(testPackageName, 0);
|
||||
assertEquals("before", beforeContext.getResources().getString(versionRes));
|
||||
|
||||
installApk(appContext, R.raw.res_version_after);
|
||||
|
||||
final Context afterContext = appContext.createPackageContext(testPackageName, 0);
|
||||
assertEquals("before", beforeContext.createConfigurationContext(Configuration.EMPTY)
|
||||
.getResources().getString(versionRes));
|
||||
assertEquals("after", afterContext.createConfigurationContext(Configuration.EMPTY)
|
||||
.getResources().getString(versionRes));
|
||||
assertNotEquals(beforeContext.getPackageResourcePath(),
|
||||
afterContext.getPackageResourcePath());
|
||||
} finally {
|
||||
uninstallPackage(context, testPackageName);
|
||||
}
|
||||
}
|
||||
|
||||
private void installApk(Context context, int rawApkResId) throws Exception {
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
final PackageInstaller pi = pm.getPackageInstaller();
|
||||
final PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
|
||||
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
|
||||
final int sessionId = pi.createSession(params);
|
||||
|
||||
try (PackageInstaller.Session session = pi.openSession(sessionId)) {
|
||||
// Copy the apk to the install session.
|
||||
final Resources resources = context.getResources();
|
||||
try (InputStream is = resources.openRawResource(rawApkResId);
|
||||
OutputStream sessionOs = session.openWrite("base", 0, -1)) {
|
||||
FileUtils.copy(is, sessionOs);
|
||||
}
|
||||
|
||||
// Wait for the installation to finish
|
||||
try (TestReceiver receiver = new TestReceiver()) {
|
||||
receiver.register();
|
||||
ShellIdentityUtils.invokeMethodWithShellPermissions(session,
|
||||
(s) -> {
|
||||
s.commit(receiver.makeIntentSender());
|
||||
return true;
|
||||
});
|
||||
receiver.waitForIntent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void uninstallPackage(Context context, String packageName) throws Exception {
|
||||
try (TestReceiver receiver = new TestReceiver()) {
|
||||
receiver.register();
|
||||
final PackageInstaller pi = context.getPackageManager().getPackageInstaller();
|
||||
pi.uninstall(packageName, receiver.makeIntentSender());
|
||||
receiver.waitForIntent();
|
||||
}
|
||||
}
|
||||
|
||||
private Context createUiContext() {
|
||||
final Context appContext = ApplicationProvider.getApplicationContext();
|
||||
final DisplayManager displayManager = appContext.getSystemService(DisplayManager.class);
|
||||
|
||||
@@ -345,7 +345,7 @@ public class PluginInstanceManager<T extends Plugin> {
|
||||
// Create our own ClassLoader so we can use our own code as the parent.
|
||||
ClassLoader classLoader = mManager.getClassLoader(info);
|
||||
Context pluginContext = new PluginContextWrapper(
|
||||
mContext.createApplicationContext(info, 0), classLoader);
|
||||
mContext.createPackageContext(pkg, 0), classLoader);
|
||||
Class<?> pluginClass = Class.forName(cls, true, classLoader);
|
||||
// TODO: Only create the plugin before version check if we need it for
|
||||
// legacy version check.
|
||||
|
||||
@@ -4691,10 +4691,10 @@ public final class ProcessList {
|
||||
final ApplicationInfo ai = AppGlobals.getPackageManager()
|
||||
.getApplicationInfo(packageName, STOCK_PM_FLAGS, app.userId);
|
||||
if (ai != null) {
|
||||
app.getThread().scheduleApplicationInfoChanged(ai);
|
||||
if (ai.packageName.equals(app.info.packageName)) {
|
||||
app.info = ai;
|
||||
}
|
||||
app.getThread().scheduleApplicationInfoChanged(ai);
|
||||
targetProcesses.add(app.getWindowProcessController());
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
@@ -4705,7 +4705,8 @@ public final class ProcessList {
|
||||
});
|
||||
}
|
||||
|
||||
mService.mActivityTaskManager.updateAssetConfiguration(targetProcesses, updateFrameworkRes);
|
||||
mService.mActivityTaskManager.updateAssetConfiguration(
|
||||
updateFrameworkRes ? null : targetProcesses);
|
||||
}
|
||||
|
||||
@GuardedBy("mService")
|
||||
|
||||
@@ -4158,21 +4158,21 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
|
||||
/**
|
||||
* Update the asset configuration and increase the assets sequence number.
|
||||
* @param processes the processes that needs to update the asset configuration
|
||||
* @param processes the processes that needs to update the asset configuration, if none
|
||||
* updates the global configuration for all processes.
|
||||
*/
|
||||
public void updateAssetConfiguration(List<WindowProcessController> processes,
|
||||
boolean updateFrameworkRes) {
|
||||
public void updateAssetConfiguration(List<WindowProcessController> processes) {
|
||||
synchronized (mGlobalLock) {
|
||||
final int assetSeq = increaseAssetConfigurationSeq();
|
||||
|
||||
if (updateFrameworkRes) {
|
||||
// Update the global configuration if the no target processes
|
||||
if (processes == null) {
|
||||
Configuration newConfig = new Configuration();
|
||||
newConfig.assetsSeq = assetSeq;
|
||||
updateConfiguration(newConfig);
|
||||
return;
|
||||
}
|
||||
|
||||
// Always update the override of every process so the asset sequence of the process is
|
||||
// always greater than or equal to the global configuration.
|
||||
for (int i = processes.size() - 1; i >= 0; i--) {
|
||||
final WindowProcessController wpc = processes.get(i);
|
||||
wpc.updateAssetConfiguration(assetSeq);
|
||||
|
||||
Reference in New Issue
Block a user