Check if APK paths are valid right before creating the context.
The check has to be done in RemoteViews and in AppWidgetHostView right before creating the context used to inflate the app widget. Further, the APK is cached potentially in two places: in the APK with code and the APK without codes, so both places are updated if present. Test: manual, see bug for details Fix: 202369942 Change-Id: I5718f67711a3332a942d3c037eef7f30379549a4
This commit is contained in:
@@ -2134,4 +2134,38 @@ public final class LoadedApk {
|
||||
final IBinder mService;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the Apk paths in the cache are correct, and update them if they are not.
|
||||
* @hide
|
||||
*/
|
||||
public static void checkAndUpdateApkPaths(ApplicationInfo expectedAppInfo) {
|
||||
// Get the LoadedApk from the cache
|
||||
ActivityThread activityThread = ActivityThread.currentActivityThread();
|
||||
if (activityThread == null) {
|
||||
Log.e(TAG, "Cannot find activity thread");
|
||||
return;
|
||||
}
|
||||
checkAndUpdateApkPaths(activityThread, expectedAppInfo, /* cacheWithCode */ true);
|
||||
checkAndUpdateApkPaths(activityThread, expectedAppInfo, /* cacheWithCode */ false);
|
||||
}
|
||||
|
||||
private static void checkAndUpdateApkPaths(ActivityThread activityThread,
|
||||
ApplicationInfo expectedAppInfo, boolean cacheWithCode) {
|
||||
String expectedCodePath = expectedAppInfo.getCodePath();
|
||||
LoadedApk loadedApk = activityThread.peekPackageInfo(
|
||||
expectedAppInfo.packageName, /* includeCode= */ cacheWithCode);
|
||||
// If there is load apk cached, or if the cache is valid, don't do anything.
|
||||
if (loadedApk == null || loadedApk.getApplicationInfo() == null
|
||||
|| loadedApk.getApplicationInfo().getCodePath().equals(expectedCodePath)) {
|
||||
return;
|
||||
}
|
||||
// Duplicate framework logic
|
||||
List<String> oldPaths = new ArrayList<>();
|
||||
LoadedApk.makePaths(activityThread, expectedAppInfo, oldPaths);
|
||||
|
||||
// Force update the LoadedApk instance, which should update the reference in the cache
|
||||
loadedApk.updateApplicationInfo(expectedAppInfo, oldPaths);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityOptions;
|
||||
import android.app.LoadedApk;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -554,7 +555,7 @@ public class AppWidgetHostView extends FrameLayout {
|
||||
}
|
||||
// Prepare a local reference to the remote Context so we're ready to
|
||||
// inflate any requested LayoutParams.
|
||||
mRemoteContext = getRemoteContext();
|
||||
mRemoteContext = getRemoteContextEnsuringCorrectCachedApkPath();
|
||||
|
||||
int layoutId = rvToApply.getLayoutId();
|
||||
if (rvToApply.canRecycleView(mView)) {
|
||||
@@ -616,7 +617,7 @@ public class AppWidgetHostView extends FrameLayout {
|
||||
private void inflateAsync(@NonNull RemoteViews remoteViews) {
|
||||
// Prepare a local reference to the remote Context so we're ready to
|
||||
// inflate any requested LayoutParams.
|
||||
mRemoteContext = getRemoteContext();
|
||||
mRemoteContext = getRemoteContextEnsuringCorrectCachedApkPath();
|
||||
int layoutId = remoteViews.getLayoutId();
|
||||
|
||||
if (mLastExecutionSignal != null) {
|
||||
@@ -718,8 +719,10 @@ public class AppWidgetHostView extends FrameLayout {
|
||||
* purposes of reading remote resources.
|
||||
* @hide
|
||||
*/
|
||||
protected Context getRemoteContext() {
|
||||
protected Context getRemoteContextEnsuringCorrectCachedApkPath() {
|
||||
try {
|
||||
ApplicationInfo expectedAppInfo = mInfo.providerInfo.applicationInfo;
|
||||
LoadedApk.checkAndUpdateApkPaths(expectedAppInfo);
|
||||
// Return if cloned successfully, otherwise default
|
||||
Context newContext = mContext.createApplicationContext(
|
||||
mInfo.providerInfo.applicationInfo,
|
||||
@@ -765,7 +768,7 @@ public class AppWidgetHostView extends FrameLayout {
|
||||
|
||||
try {
|
||||
if (mInfo != null) {
|
||||
Context theirContext = getRemoteContext();
|
||||
Context theirContext = getRemoteContextEnsuringCorrectCachedApkPath();
|
||||
mRemoteContext = theirContext;
|
||||
LayoutInflater inflater = (LayoutInflater)
|
||||
theirContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
@@ -34,6 +34,7 @@ import android.app.Activity;
|
||||
import android.app.ActivityOptions;
|
||||
import android.app.ActivityThread;
|
||||
import android.app.Application;
|
||||
import android.app.LoadedApk;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.RemoteInput;
|
||||
import android.appwidget.AppWidgetHostView;
|
||||
@@ -5475,7 +5476,8 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
// user. So build a context that loads resources from that user but
|
||||
// still returns the current users userId so settings like data / time formats
|
||||
// are loaded without requiring cross user persmissions.
|
||||
final Context contextForResources = getContextForResources(context);
|
||||
final Context contextForResources =
|
||||
getContextForResourcesEnsuringCorrectCachedApkPaths(context);
|
||||
if (colorResources != null) {
|
||||
colorResources.apply(contextForResources);
|
||||
}
|
||||
@@ -5853,13 +5855,14 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
}
|
||||
}
|
||||
|
||||
private Context getContextForResources(Context context) {
|
||||
private Context getContextForResourcesEnsuringCorrectCachedApkPaths(Context context) {
|
||||
if (mApplication != null) {
|
||||
if (context.getUserId() == UserHandle.getUserId(mApplication.uid)
|
||||
&& context.getPackageName().equals(mApplication.packageName)) {
|
||||
return context;
|
||||
}
|
||||
try {
|
||||
LoadedApk.checkAndUpdateApkPaths(mApplication);
|
||||
return context.createApplicationContext(mApplication,
|
||||
Context.CONTEXT_RESTRICTED);
|
||||
} catch (NameNotFoundException e) {
|
||||
|
||||
@@ -408,7 +408,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Context getRemoteContext() {
|
||||
protected Context getRemoteContextEnsuringCorrectCachedApkPath() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user