Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4416c3d6 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Fix issue #2643754: Launcher is caching widget layouts for too long

With the .apk file names now changing during an update, we need
to make sure to flush all caches related to a package when the
package is removed.  Otherwise we can continue to use the old
package, since its old file may still exist if we try to load it
too soon.

Change-Id: I15f08dffca3feac999dbca4f24bef12a30ca0a66
parent 5e5202bd
Loading
Loading
Loading
Loading
+42 −20
Original line number Diff line number Diff line
@@ -194,6 +194,7 @@ public final class ActivityThread {
            }
            WeakReference<Resources> wr = mActiveResources.get(key);
            r = wr != null ? wr.get() : null;
            //if (r != null) Slog.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate());
            if (r != null && r.getAssets().isUpToDate()) {
                if (false) {
                    Slog.w(TAG, "Returning cached resources " + r + " " + resDir
@@ -1752,6 +1753,10 @@ public final class ActivityThread {
            Debug.getMemoryInfo(outInfo);
        }

        public void dispatchPackageBroadcast(int cmd, String[] packages) {
            queueOrSendMessage(H.DISPATCH_PACKAGE_BROADCAST, packages, cmd);
        }
        
        @Override
        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
            long nativeMax = Debug.getNativeHeapSize() / 1024;
@@ -1976,6 +1981,7 @@ public final class ActivityThread {
        public static final int SUICIDE                 = 130;
        public static final int REMOVE_PROVIDER         = 131;
        public static final int ENABLE_JIT              = 132;
        public static final int DISPATCH_PACKAGE_BROADCAST = 133;
        String codeToString(int code) {
            if (localLOGV) {
                switch (code) {
@@ -2012,6 +2018,7 @@ public final class ActivityThread {
                    case SUICIDE: return "SUICIDE";
                    case REMOVE_PROVIDER: return "REMOVE_PROVIDER";
                    case ENABLE_JIT: return "ENABLE_JIT";
                    case DISPATCH_PACKAGE_BROADCAST: return "DISPATCH_PACKAGE_BROADCAST";
                }
            }
            return "(unknown)";
@@ -2132,6 +2139,9 @@ public final class ActivityThread {
                case ENABLE_JIT:
                    ensureJitEnabled();
                    break;
                case DISPATCH_PACKAGE_BROADCAST:
                    handleDispatchPackageBroadcast(msg.arg1, (String[])msg.obj);
                    break;
            }
        }

@@ -2244,7 +2254,7 @@ public final class ActivityThread {
            = new HashMap<String, WeakReference<PackageInfo>>();
    Display mDisplay = null;
    DisplayMetrics mDisplayMetrics = null;
    HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources
    final HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources
            = new HashMap<ResourcesKey, WeakReference<Resources> >();
    final ArrayList<ActivityRecord> mRelaunchingActivities
            = new ArrayList<ActivityRecord>();
@@ -2271,6 +2281,8 @@ public final class ActivityThread {
            }
            PackageInfo packageInfo = ref != null ? ref.get() : null;
            //Slog.i(TAG, "getPackageInfo " + packageName + ": " + packageInfo);
            //if (packageInfo != null) Slog.i(TAG, "isUptoDate " + packageInfo.mResDir
            //        + ": " + packageInfo.mResources.getAssets().isUpToDate());
            if (packageInfo != null && (packageInfo.mResources == null
                    || packageInfo.mResources.getAssets().isUpToDate())) {
                if (packageInfo.isSecurityViolation()
@@ -2358,21 +2370,6 @@ public final class ActivityThread {
        }
    }

    public final boolean hasPackageInfo(String packageName) {
        synchronized (mPackages) {
            WeakReference<PackageInfo> ref;
            ref = mPackages.get(packageName);
            if (ref != null && ref.get() != null) {
                return true;
            }
            ref = mResourcePackages.get(packageName);
            if (ref != null && ref.get() != null) {
                return true;
            }
            return false;
        }
    }

    ActivityThread() {
    }

@@ -4054,6 +4051,31 @@ public final class ActivityThread {
        }
    }

    final void handleDispatchPackageBroadcast(int cmd, String[] packages) {
        boolean hasPkgInfo = false;
        if (packages != null) {
            for (int i=packages.length-1; i>=0; i--) {
                //Slog.i(TAG, "Cleaning old package: " + packages[i]);
                if (!hasPkgInfo) {
                    WeakReference<PackageInfo> ref;
                    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;
                        }
                    }
                }
                mPackages.remove(packages[i]);
                mResourcePackages.remove(packages[i]);
            }
        }
        ContextImpl.ApplicationPackageManager.handlePackageBroadcast(cmd, packages,
                hasPkgInfo);
    }
        
    final void handleLowMemory() {
        ArrayList<ComponentCallbacks> callbacks
                = new ArrayList<ComponentCallbacks>();
+20 −0
Original line number Diff line number Diff line
@@ -393,6 +393,15 @@ public abstract class ApplicationThreadNative extends Binder
            mi.writeToParcel(reply, 0);
            return true;
        }

        case DISPATCH_PACKAGE_BROADCAST_TRANSACTION:
        {
            data.enforceInterface(IApplicationThread.descriptor);
            int cmd = data.readInt();
            String[] packages = data.readStringArray();
            dispatchPackageBroadcast(cmd, packages);
            return true;
        }
        }

        return super.onTransact(code, data, reply, flags);
@@ -806,5 +815,16 @@ class ApplicationThreadProxy implements IApplicationThread {
        data.recycle();
        reply.recycle();
    }
    
    public void dispatchPackageBroadcast(int cmd, String[] packages) throws RemoteException {
        Parcel data = Parcel.obtain();
        data.writeInterfaceToken(IApplicationThread.descriptor);
        data.writeInt(cmd);
        data.writeStringArray(packages);
        mRemote.transact(DISPATCH_PACKAGE_BROADCAST_TRANSACTION, data, null,
                IBinder.FLAG_ONEWAY);
        data.recycle();
        
    }
}
+22 −65
Original line number Diff line number Diff line
@@ -2244,33 +2244,7 @@ class ContextImpl extends Context {
            return null;
        }

        private void establishPackageRemovedReceiver() {
            // mContext.registerReceiverInternal() winds up acquiring the
            // main ActivityManagerService.this lock.  If we hold our usual
            // sSync global lock at the same time, we impose a required ordering
            // on those two locks, which is not good for deadlock prevention.
            // Use a dedicated lock around initialization of
            // sPackageRemovedReceiver to avoid this.
            synchronized (sPackageRemovedSync) {
                if (sPackageRemovedReceiver == null) {
                    sPackageRemovedReceiver = new PackageRemovedReceiver();
                    IntentFilter filter = new IntentFilter(
                            Intent.ACTION_PACKAGE_REMOVED);
                    filter.addDataScheme("package");
                    mContext.registerReceiverInternal(sPackageRemovedReceiver,
                            filter, null, null, null);
                    // Register for events related to sdcard installation.
                    IntentFilter sdFilter = new IntentFilter();
                    sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
                    mContext.registerReceiverInternal(sPackageRemovedReceiver,
                            sdFilter, null, null, null);
                }
            }
        }
        
        private void putCachedIcon(ResourceName name, Drawable dr) {
            establishPackageRemovedReceiver();

            synchronized (sSync) {
                sIconCache.put(name, new WeakReference<Drawable>(dr));
                if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable for "
@@ -2278,29 +2252,17 @@ class ContextImpl extends Context {
            }
        }

        private static final class PackageRemovedReceiver extends BroadcastReceiver {
            @Override
            public void onReceive(Context context, Intent intent) {
                String pkgList[] = null;
                String action = intent.getAction();
        static final void handlePackageBroadcast(int cmd, String[] pkgList,
                boolean hasPkgInfo) {
            boolean immediateGc = false;
                if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
            if (cmd == IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE) {
                immediateGc = true;
                } else {
                    Uri data = intent.getData();
                    if (data != null) {
                        String ssp = data.getSchemeSpecificPart();
                        if (ssp != null) {
                            pkgList = new String[] { ssp };
                        }
                    }
            }
            if (pkgList != null && (pkgList.length > 0)) {
                boolean needCleanup = false;
                    boolean hasPkgInfo = false;
                for (String ssp : pkgList) {
                    synchronized (sSync) {
                        if (sIconCache.size() > 0) {
                            Iterator<ResourceName> it = sIconCache.keySet().iterator();
                            while (it.hasNext()) {
                                ResourceName nm = it.next();
@@ -2310,7 +2272,9 @@ class ContextImpl extends Context {
                                    needCleanup = true;
                                }
                            }
                            it = sStringCache.keySet().iterator();
                        }
                        if (sStringCache.size() > 0) {
                            Iterator<ResourceName> it = sStringCache.keySet().iterator();
                            while (it.hasNext()) {
                                ResourceName nm = it.next();
                                if (nm.packageName.equals(ssp)) {
@@ -2320,8 +2284,6 @@ class ContextImpl extends Context {
                                }
                            }
                        }
                        if (!hasPkgInfo) {
                            hasPkgInfo = ActivityThread.currentActivityThread().hasPackageInfo(ssp);
                    }
                }
                if (needCleanup || hasPkgInfo) {
@@ -2334,7 +2296,6 @@ class ContextImpl extends Context {
                }
            }
        }
        }
        
        private static final class ResourceName {
            final String packageName;
@@ -2400,8 +2361,6 @@ class ContextImpl extends Context {
        }

        private void putCachedString(ResourceName name, CharSequence cs) {
            establishPackageRemovedReceiver();

            synchronized (sSync) {
                sStringCache.put(name, new WeakReference<CharSequence>(cs));
            }
@@ -2665,8 +2624,6 @@ class ContextImpl extends Context {
        private final IPackageManager mPM;

        private static final Object sSync = new Object();
        private static final Object sPackageRemovedSync = new Object();
        private static BroadcastReceiver sPackageRemovedReceiver;
        private static HashMap<ResourceName, WeakReference<Drawable> > sIconCache
                = new HashMap<ResourceName, WeakReference<Drawable> >();
        private static HashMap<ResourceName, WeakReference<CharSequence> > sStringCache
+4 −0
Original line number Diff line number Diff line
@@ -100,6 +100,9 @@ public interface IApplicationThread extends IInterface {
            throws RemoteException;
    void setSchedulingGroup(int group) throws RemoteException;
    void getMemoryInfo(Debug.MemoryInfo outInfo) throws RemoteException;
    static final int PACKAGE_REMOVED = 0;
    static final int EXTERNAL_STORAGE_UNAVAILABLE = 1;
    void dispatchPackageBroadcast(int cmd, String[] packages) throws RemoteException;
    
    String descriptor = "android.app.IApplicationThread";

@@ -135,4 +138,5 @@ public interface IApplicationThread extends IInterface {
    int SCHEDULE_DESTROY_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+30;
    int GET_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+31;
    int SCHEDULE_SUICIDE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+32;
    int DISPATCH_PACKAGE_BROADCAST_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+33;
}
+18 −0
Original line number Diff line number Diff line
@@ -12269,6 +12269,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
        }
    }
    
    private final void sendPackageBroadcastLocked(int cmd, String[] packages) {
        for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
            ProcessRecord r = mLruProcesses.get(i);
            if (r.thread != null) {
                try {
                    r.thread.dispatchPackageBroadcast(cmd, packages);
                } catch (RemoteException ex) {
                }
            }
        }
    }
    
    private final int broadcastIntentLocked(ProcessRecord callerApp,
            String callerPackage, Intent intent, String resolvedType,
            IIntentReceiver resultTo, int resultCode, String resultData,
@@ -12315,6 +12327,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
                            for (String pkg : list) {
                                forceStopPackageLocked(pkg, -1, false, true, true);
                            }
                            sendPackageBroadcastLocked(
                                    IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE, list);
                        }
                    } else {
                        Uri data = intent.getData();
@@ -12324,6 +12338,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
                                forceStopPackageLocked(ssp,
                                        intent.getIntExtra(Intent.EXTRA_UID, -1), false, true, true);
                            }
                            if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
                                sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
                                        new String[] {ssp});
                            }
                        }
                    }
                }