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

Commit 690d20bb authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Fix issue # 3227963: SecurityException: Neither user 10023 nor...

...current process has android.permission.WAKE_LOCK

When updating a system app, we would actually uninstall the package
of the system app, which also meant removing its uid...!  It was just
luck that we would get the same uid when installing the update after
that.  During that time, if anyone tried to do anything related to
that uid, it would be unknown.

This change tweaks how we go about replacing system apps by making
it more like normal apps -- to make this work, if we need to disable
the system app, we generate a new PackageSetting from the current
system app and replace it into our data structures, so we can update
that without trashing the current correct information about the (still
actually there) system app.

Also fixed a problem where we were not killing the currently running
app before installing, like we do when updating a normal application.

And fixed a problem where we were not deleting the /data .apk when
uninstalling a system app update.

And added a new option to the "pm" command to clear the data associated
with an app.

Change-Id: I0e879677849aa42950a3c360bf78ad820e87674b
parent 3ce86481
Loading
Loading
Loading
Loading
+59 −0
Original line number Diff line number Diff line
@@ -18,9 +18,11 @@ package com.android.commands.pm;

import com.android.internal.content.PackageHelper;

import android.app.ActivityManagerNative;
import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageInstallObserver;
import android.content.pm.IPackageManager;
@@ -100,6 +102,11 @@ public final class Pm {
            return;
        }

        if ("clear".equals(op)) {
            runClear();
            return;
        }

        if ("enable".equals(op)) {
            runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
            return;
@@ -809,6 +816,55 @@ public final class Pm {
        return obs.result;
    }

    class ClearDataObserver extends IPackageDataObserver.Stub {
        boolean finished;
        boolean result;

        @Override
        public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException {
            synchronized (this) {
                finished = true;
                result = succeeded;
                notifyAll();
            }
        }

    }

    private void runClear() {
        String pkg = nextArg();
        if (pkg == null) {
            System.err.println("Error: no package specified");
            showUsage();
            return;
        }

        ClearDataObserver obs = new ClearDataObserver();
        try {
            if (!ActivityManagerNative.getDefault().clearApplicationUserData(pkg, obs)) {
                System.err.println("Failed");
            }

            synchronized (obs) {
                while (!obs.finished) {
                    try {
                        obs.wait();
                    } catch (InterruptedException e) {
                    }
                }
            }

            if (obs.result) {
                System.err.println("Success");
            } else {
                System.err.println("Failed");
            }
        } catch (RemoteException e) {
            System.err.println(e.toString());
            System.err.println(PM_NOT_RUNNING_ERR);
        }
    }

    private static String enabledSettingToString(int state) {
        switch (state) {
            case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
@@ -944,6 +1000,7 @@ public final class Pm {
        System.err.println("       pm path PACKAGE");
        System.err.println("       pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH");
        System.err.println("       pm uninstall [-k] PACKAGE");
        System.err.println("       pm clear PACKAGE");
        System.err.println("       pm enable PACKAGE_OR_COMPONENT");
        System.err.println("       pm disable PACKAGE_OR_COMPONENT");
        System.err.println("       pm setInstallLocation [0/auto] [1/internal] [2/external]");
@@ -986,6 +1043,8 @@ public final class Pm {
        System.err.println("  -k: keep the data and cache directories around.");
        System.err.println("after the package removal.");
        System.err.println("");
        System.err.println("The clear command deletes all data associated with a package.");
        System.err.println("");
        System.err.println("The enable and disable commands change the enabled state of");
        System.err.println("a given package or component (written as \"package/class\").");
        System.err.println("");
+59 −33
Original line number Diff line number Diff line
@@ -3663,17 +3663,6 @@ class PackageManagerService extends IPackageManager.Stub {
                mAppDirs.remove(pkg.mPath);
            }

            PackageSetting ps = (PackageSetting)pkg.mExtras;
            if (ps != null && ps.sharedUser != null) {
                // XXX don't do this until the data is removed.
                if (false) {
                    ps.sharedUser.packages.remove(ps);
                    if (ps.sharedUser.packages.size() == 0) {
                        // Remove.
                    }
                }
            }

            int N = pkg.providers.size();
            StringBuilder r = null;
            int i;
@@ -5695,12 +5684,26 @@ class PackageManagerService extends IPackageManager.Stub {
                return;
            }
        }

        killApplication(packageName, oldPkg.applicationInfo.uid);

        res.removedInfo.uid = oldPkg.applicationInfo.uid;
        res.removedInfo.removedPackage = packageName;
        // Remove existing system package
        removePackageLI(oldPkg, true);
        synchronized (mPackages) {
            mSettings.disableSystemPackageLP(packageName);
            if (!mSettings.disableSystemPackageLP(packageName) && deletedPackage != null) {
                // We didn't need to disable the .apk as a current system package,
                // which means we are replacing another update that is already
                // installed.  We need to make sure to delete the older one's .apk.
                res.removedInfo.args = createInstallArgs(isExternal(pkg)
                        ? PackageManager.INSTALL_EXTERNAL : PackageManager.INSTALL_INTERNAL,
                        deletedPackage.applicationInfo.sourceDir,
                        deletedPackage.applicationInfo.publicSourceDir,
                        deletedPackage.applicationInfo.nativeLibraryDir);
            } else {
                res.removedInfo.args = null;
            }
        }
        
        // Successfully disabled the old package. Now proceed with re-installation
@@ -5739,17 +5742,6 @@ class PackageManagerService extends IPackageManager.Stub {
                }
                mSettings.writeLP();
            }
        } else {
            // If this is an update to an existing update, setup 
            // to remove the existing update.
            synchronized (mPackages) {
                PackageSetting ps = mSettings.getDisabledSystemPkg(packageName);
                if (ps != null && ps.codePathString != null &&
                        !ps.codePathString.equals(oldPkgSetting.codePathString)) {
                    res.removedInfo.args = createInstallArgs(0, oldPkgSetting.codePathString,
                            oldPkgSetting.resourcePathString, oldPkgSetting.nativeLibraryPathString);
                }
            }
        }
    }

@@ -6252,24 +6244,21 @@ class PackageManagerService extends IPackageManager.Stub {
            ps = mSettings.getDisabledSystemPkg(p.packageName);
        }
        if (ps == null) {
            Slog.w(TAG, "Attempt to delete system package "+ p.packageName);
            Slog.w(TAG, "Attempt to delete unknown system package "+ p.packageName);
            return false;
        } else {
            Log.i(TAG, "Deleting system pkg from data partition");
        }
        // Delete the updated package
        outInfo.isRemovedPackageSystemUpdate = true;
        final boolean deleteCodeAndResources;
        if (ps.versionCode < p.mVersionCode) {
            // Delete code and resources for downgrades
            deleteCodeAndResources = true;
            // Delete data for downgrades
            flags &= ~PackageManager.DONT_DELETE_DATA;
        } else {
            // Preserve data by setting flag
            deleteCodeAndResources = false;
            flags |= PackageManager.DONT_DELETE_DATA;
        }
        boolean ret = deleteInstalledPackageLI(p, deleteCodeAndResources, flags, outInfo,
        boolean ret = deleteInstalledPackageLI(p, true, flags, outInfo,
                writeSettings);
        if (!ret) {
            return false;
@@ -7850,6 +7839,12 @@ class PackageManagerService extends IPackageManager.Stub {
                    pkgFlags);
        }

        PackageSetting(PackageSetting orig) {
            super(orig.name, orig.realName, orig.codePath, orig.resourcePath,
                    orig.nativeLibraryPathString, orig.versionCode, orig.pkgFlags);
            copyFrom(orig);
        }

        @Override
        public String toString() {
            return "PackageSetting{"
@@ -8062,11 +8057,11 @@ class PackageManagerService extends IPackageManager.Stub {
            return s;
        }

        int disableSystemPackageLP(String name) {
        boolean disableSystemPackageLP(String name) {
            PackageSetting p = mPackages.get(name);
            if(p == null) {
                Log.w(TAG, "Package:"+name+" is not an installed package");
                return -1;
                return false;
            }
            PackageSetting dp = mDisabledSysPackages.get(name);
            // always make sure the system package code and resource paths dont change
@@ -8075,8 +8070,16 @@ class PackageManagerService extends IPackageManager.Stub {
                    p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
                }
                mDisabledSysPackages.put(name, p);

                // a little trick...  when we install the new package, we don't
                // want to modify the existing PackageSetting for the built-in
                // version.  so at this point we need a new PackageSetting that
                // is okay to much with.
                PackageSetting newp = new PackageSetting(p);
                replacePackageLP(name, newp);
                return true;
            }
            return removePackageLP(name);
            return false;
        }

        PackageSetting enableSystemPackageLP(String name) {
@@ -8410,6 +8413,19 @@ class PackageManagerService extends IPackageManager.Stub {
            return -1;
        }

        private void replacePackageLP(String name, PackageSetting newp) {
            PackageSetting p = mPackages.get(name);
            if (p != null) {
                if (p.sharedUser != null) {
                    p.sharedUser.packages.remove(p);
                    p.sharedUser.packages.add(newp);
                } else {
                    replaceUserIdLP(p.userId, newp);
                }
            }
            mPackages.put(name, newp);
        }

        private boolean addUserIdLP(int uid, Object obj, Object name) {
            if (uid >= FIRST_APPLICATION_UID + MAX_APPLICATION_UIDS) {
                return false;
@@ -8472,6 +8488,16 @@ class PackageManagerService extends IPackageManager.Stub {
            }
        }

        private void replaceUserIdLP(int uid, Object obj) {
            if (uid >= FIRST_APPLICATION_UID) {
                int N = mUserIds.size();
                final int index = uid - FIRST_APPLICATION_UID;
                if (index < N) mUserIds.set(index, obj);
            } else {
                mOtherUserIds.put(uid, obj);
            }
        }

        void writeLP() {
            //Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024);