Loading core/java/android/app/LoadedApk.java +34 −0 Original line number Diff line number Diff line Loading @@ -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); } } core/java/android/appwidget/AppWidgetHostView.java +7 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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)) { Loading Loading @@ -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) { Loading Loading @@ -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, Loading Loading @@ -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); Loading core/java/android/widget/RemoteViews.java +5 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } Loading Loading @@ -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) { Loading core/java/android/widget/RemoteViewsAdapter.java +1 −1 Original line number Diff line number Diff line Loading @@ -408,7 +408,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback } @Override protected Context getRemoteContext() { protected Context getRemoteContextEnsuringCorrectCachedApkPath() { return null; } Loading Loading
core/java/android/app/LoadedApk.java +34 −0 Original line number Diff line number Diff line Loading @@ -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); } }
core/java/android/appwidget/AppWidgetHostView.java +7 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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)) { Loading Loading @@ -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) { Loading Loading @@ -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, Loading Loading @@ -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); Loading
core/java/android/widget/RemoteViews.java +5 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } Loading Loading @@ -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) { Loading
core/java/android/widget/RemoteViewsAdapter.java +1 −1 Original line number Diff line number Diff line Loading @@ -408,7 +408,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback } @Override protected Context getRemoteContext() { protected Context getRemoteContextEnsuringCorrectCachedApkPath() { return null; } Loading