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

Commit 39107f48 authored by Adnan Begovic's avatar Adnan Begovic
Browse files

prebundled: Handle prebundled packages per-user.

  Also add migration step for reading old file to go towards
  per-user system file structure

TICKET: CYNGNOS-1006
Change-Id: I743e8efaa074c9b84291fdc8d3d15763cc39e79d
parent 0d07a437
Loading
Loading
Loading
Loading
+39 −17
Original line number Diff line number Diff line
@@ -285,6 +285,7 @@ public class PackageManagerService extends IPackageManager.Stub {
    private static final boolean DEBUG_VERIFY = false;
    private static final boolean DEBUG_DEXOPT = false;
    private static final boolean DEBUG_ABI_SELECTION = false;
    private static final boolean DEBUG_PREBUNDLED_SCAN = false;
    private static final int RADIO_UID = Process.PHONE_UID;
    private static final int LOG_UID = Process.LOG_UID;
@@ -1503,7 +1504,7 @@ public class PackageManagerService extends IPackageManager.Stub {
            mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
            mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),
                    mSdkVersion, mOnlyCore);
                    mSdkVersion, mOnlyCore, mInstaller);
            String customResolverActivity = Resources.getSystem().getString(
                    R.string.config_customResolverActivity);
@@ -1659,24 +1660,24 @@ public class PackageManagerService extends IPackageManager.Stub {
            // overlay packages if they reside in VENDOR_OVERLAY_DIR.
            File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
            scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0, null);
            // Find base frameworks (resource packages without code).
            scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR
                    | PackageParser.PARSE_IS_PRIVILEGED,
                    scanFlags | SCAN_NO_DEX, 0);
                    scanFlags | SCAN_NO_DEX, 0, null);
            // Collected privileged system packages.
            final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
            scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR
                    | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);
                    | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0, null);
            // Collect ordinary system packages.
            final File systemAppDir = new File(Environment.getRootDirectory(), "app");
            scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0, null);
            // Collect all vendor packages.
            File vendorAppDir = new File("/vendor/app");
@@ -1686,16 +1687,16 @@ public class PackageManagerService extends IPackageManager.Stub {
                // failed to look up canonical path, continue with original one
            }
            scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0, null);
            // Collect all OEM packages.
            final File oemAppDir = new File(Environment.getOemDirectory(), "app");
            scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0, null);
            // Collect all prebundled packages.
            scanDirLI(Environment.getPrebundledDirectory(),
                    PackageParser.PARSE_IS_PREBUNDLED_DIR, scanFlags, 0);
                    PackageParser.PARSE_IS_PREBUNDLED_DIR, scanFlags, 0, UserHandle.OWNER);
            if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
            mInstaller.moveFiles();
@@ -1771,10 +1772,10 @@ public class PackageManagerService extends IPackageManager.Stub {
            if (!mOnlyCore) {
                EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                        SystemClock.uptimeMillis());
                scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
                scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0, null);
                scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
                        scanFlags | SCAN_REQUIRE_KNOWN, 0);
                        scanFlags | SCAN_REQUIRE_KNOWN, 0, null);
                /**
                 * Remove disable package settings for any updated system
@@ -4351,7 +4352,8 @@ public class PackageManagerService extends IPackageManager.Stub {
        return true;
    }
    private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
    private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime,
            UserHandle user) {
        final File[] files = dir.listFiles();
        if (ArrayUtils.isEmpty(files)) {
            Log.d(TAG, "No files in app dir " + dir);
@@ -4363,10 +4365,13 @@ public class PackageManagerService extends IPackageManager.Stub {
                    + " flags=0x" + Integer.toHexString(parseFlags));
        }
        int prebundledUserId = user == null ? UserHandle.USER_OWNER : user.getIdentifier();
        boolean isPrebundled = (parseFlags & PackageParser.PARSE_IS_PREBUNDLED_DIR) != 0;
        if (isPrebundled) {
            synchronized (mPackages) {
                mSettings.readPrebundledPackagesLPr();
                if (DEBUG_PREBUNDLED_SCAN) Log.d(TAG, "Reading prebundled packages for user "
                        + prebundledUserId);
                mSettings.readPrebundledPackagesLPr(prebundledUserId);
            }
        }
@@ -4379,7 +4384,7 @@ public class PackageManagerService extends IPackageManager.Stub {
            }
            try {
                scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
                        scanFlags, currentTime, null);
                        scanFlags, currentTime, user);
                if (isPrebundled) {
                    final PackageParser.Package pkg;
                    try {
@@ -4388,7 +4393,16 @@ public class PackageManagerService extends IPackageManager.Stub {
                        throw PackageManagerException.from(e);
                    }
                    synchronized (mPackages) {
                        mSettings.markPrebundledPackageInstalledLPr(pkg.packageName);
                        if (DEBUG_PREBUNDLED_SCAN) Log.d(TAG,
                                "Marking prebundled packages for user " + prebundledUserId);
                        mSettings.markPrebundledPackageInstalledLPr(prebundledUserId,
                                pkg.packageName);
                        // do this for every other user
                        for (UserInfo userInfo : sUserManager.getUsers(true)) {
                            if (userInfo.id == prebundledUserId) continue;
                            mSettings.markPrebundledPackageInstalledLPr(userInfo.id,
                                    pkg.packageName);
                        }
                    }
                }
            } catch (PackageManagerException e) {
@@ -4408,7 +4422,9 @@ public class PackageManagerService extends IPackageManager.Stub {
        if (isPrebundled) {
            synchronized (mPackages) {
                mSettings.writePrebundledPackagesLPr();
                if (DEBUG_PREBUNDLED_SCAN) Log.d(TAG, "Writing prebundled packages for user "
                        + prebundledUserId);
                mSettings.writePrebundledPackagesLPr(prebundledUserId);
            }
        }
    }
@@ -4512,8 +4528,8 @@ public class PackageManagerService extends IPackageManager.Stub {
        if ((parseFlags & PackageParser.PARSE_IS_PREBUNDLED_DIR) != 0) {
            synchronized (mPackages) {
                PackageSetting existingSettings = mSettings.peekPackageLPr(pkg.packageName);
                if (mSettings.wasPrebundledPackageInstalledLPr(pkg.packageName) &&
                        existingSettings == null) {
                if (mSettings.wasPrebundledPackageInstalledLPr(user.getIdentifier()
                        , pkg.packageName) && existingSettings == null) {
                    // The prebundled app was installed at some point in time, but now it is
                    // gone.  Assume that the user uninstalled it intentionally: do not reinstall.
                    throw new PackageManagerException(INSTALL_FAILED_UNINSTALLED_PREBUNDLE,
@@ -14262,6 +14278,12 @@ public class PackageManagerService extends IPackageManager.Stub {
        if (mInstaller != null) {
            mInstaller.createUserConfig(userHandle);
            mSettings.createNewUserLILPw(this, mInstaller, userHandle, path);
            // Set flag to monitor and not change apk file paths when
            // scanning install directories.
            final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;
            scanDirLI(Environment.getPrebundledDirectory(),
                    PackageParser.PARSE_IS_PREBUNDLED_DIR, scanFlags, 0,
                    new UserHandle(userHandle));
        }
    }
+114 −15
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import static android.content.pm.PackageManager.INSTALL_FAILED_UNINSTALLED_PREBUNDLE;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.PACKAGE_INFO_GID;
@@ -182,8 +183,6 @@ final class Settings {
    // List of replaced system applications
    private final ArrayMap<String, PackageSetting> mDisabledSysPackages =
        new ArrayMap<String, PackageSetting>();
    private final HashSet<String> mPrebundledPackages =
            new HashSet<String>();

    private static int mFirstAvailableUid = 0;

@@ -222,6 +221,10 @@ final class Settings {
    final SparseArray<PersistentPreferredIntentResolver> mPersistentPreferredActivities =
            new SparseArray<PersistentPreferredIntentResolver>();

    // The persistent prebundled packages for a user
    final SparseArray<HashSet<String>> mPrebundledPackages =
            new SparseArray<HashSet<String>>();

    // For every user, it is used to find to which other users the intent can be forwarded.
    final SparseArray<CrossProfileIntentResolver> mCrossProfileIntentResolvers =
            new SparseArray<CrossProfileIntentResolver>();
@@ -283,12 +286,12 @@ final class Settings {
        mSettingsFilename = new File(mSystemDir, "packages.xml");
        mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
        mPackageListFilename = new File(mSystemDir, "packages.list");
        mPrebundledPackagesFilename = new File(mSystemDir, "prebundled-packages.list");
        FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);

        // Deprecated: Needed for migration
        mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
        mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
        mPrebundledPackagesFilename = new File(mSystemDir, "prebundled-packages.list");
    }

    PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,
@@ -892,6 +895,15 @@ final class Settings {
        return pir;
    }

    HashSet<String> editPrebundledPackagesLPw(int userId) {
        HashSet<String> hashSet = mPrebundledPackages.get(userId);
        if (hashSet == null) {
            hashSet = new HashSet<String>();
            mPrebundledPackages.put(userId, hashSet);
        }
        return hashSet;
    }

    PersistentPreferredIntentResolver editPersistentPreferredActivitiesLPw(int userId) {
        PersistentPreferredIntentResolver ppir = mPersistentPreferredActivities.get(userId);
        if (ppir == null) {
@@ -919,6 +931,10 @@ final class Settings {
                "package-restrictions-backup.xml");
    }

    private File getUserPrebundledStateFile(int userId) {
        return new File(Environment.getUserSystemDirectory(userId), "prebundled-packages.list");
    }

    void writeAllUsersPackageRestrictionsLPr() {
        List<UserInfo> users = getAllUsers();
        if (users == null) return;
@@ -1785,12 +1801,41 @@ final class Settings {
        //Debug.stopMethodTracing();
    }

    void writePrebundledPackagesLPr() {
    // Migrate from previous prebundled packages file to new one
    void migratePrebundedPackagesIfNeededLPr(List<UserInfo> users, Installer installer) {
        if (mPrebundledPackagesFilename.exists()) {
            // Read old file
            editPrebundledPackagesLPw(UserHandle.USER_OWNER);
            readPrebundledPackagesOldLPw();
            mPrebundledPackagesFilename.delete();
            // Migrate to new file based on user
            writePrebundledPackagesLPr(UserHandle.USER_OWNER);
        } else {
            if (users == null) {
                readPrebundledPackagesLPr(UserHandle.USER_OWNER);
            } else {
                for (UserInfo user : users) {
                    editPrebundledPackagesLPw(user.id);
                    readPrebundledPackagesLPr(user.id);
                    // mark all existing users as having packages installed from OWNER
                    try {
                        markAllAsInstalledForUser(user.id, installer);
                    } catch (PackageManagerException e) {
                        Log.d(TAG, e.toString());
                    }
                }
            }
        }
    }

    void writePrebundledPackagesLPr(int userId) {
        editPrebundledPackagesLPw(userId);
        PrintWriter writer = null;
        try {
            writer = new PrintWriter(
                    new BufferedWriter(new FileWriter(mPrebundledPackagesFilename, false)));
            for (String packageName : mPrebundledPackages) {
                    new BufferedWriter(new FileWriter(getUserPrebundledStateFile(userId), false)));

            for (String packageName : mPrebundledPackages.get(userId)) {
                writer.println(packageName);
            }
        } catch (IOException e) {
@@ -1802,18 +1847,31 @@ final class Settings {
        }
    }

    void readPrebundledPackagesLPr() {
    // This is done for an intermediate migration step on upgrade
    void readPrebundledPackagesOldLPw() {
        if (!mPrebundledPackagesFilename.exists()) {
            return;
        }

        readPrebundledPackagesForUserFromFileLPr(UserHandle.USER_OWNER,
                mPrebundledPackagesFilename);
    }

    void readPrebundledPackagesLPr(int userId) {
        if (!getUserPrebundledStateFile(userId).exists()) {
            return;
        }
        readPrebundledPackagesForUserFromFileLPr(userId, getUserPrebundledStateFile(userId));
    }

    private void readPrebundledPackagesForUserFromFileLPr(int userId, File file) {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader(mPrebundledPackagesFilename));
            reader = new BufferedReader(new FileReader(file));
            String packageName = reader.readLine();
            while (packageName != null) {
                if (!TextUtils.isEmpty(packageName)) {
                    mPrebundledPackages.add(packageName);
                    mPrebundledPackages.get(userId).add(packageName);
                }
                packageName = reader.readLine();
            }
@@ -1828,12 +1886,45 @@ final class Settings {
        }
    }

    void markPrebundledPackageInstalledLPr(String packageName) {
        mPrebundledPackages.add(packageName);
    private void markAllAsInstalledForUser(int userHandle, Installer installer)
            throws PackageManagerException {
        if (mPrebundledPackages.get(userHandle) == null) {
            throw new PackageManagerException(INSTALL_FAILED_UNINSTALLED_PREBUNDLE,
                    "Failure migrating prebundled packages to existing user " + userHandle);
        }

    boolean wasPrebundledPackageInstalledLPr(String packageName) {
        return mPrebundledPackages.contains(packageName);
        // grab all the packages from the user account, move them over
        for (String s : mPrebundledPackages.get(UserHandle.USER_OWNER)) {
            mPrebundledPackages.get(userHandle).add(s);
        }

        for (PackageSetting ps : mPackages.values()) {
            if (ps.pkg == null || ps.pkg.applicationInfo == null) {
                continue;
            }
            // Mark the app as installed
            boolean setInstalled =
                    wasPrebundledPackageInstalledLPr(UserHandle.USER_OWNER, ps.name);
            ps.setInstalled(setInstalled, userHandle);
            // Tell the installer to create the user data for the application
            installer.createUserData(ps.name,
                    UserHandle.getUid(userHandle, ps.appId), userHandle,
                    ps.pkg.applicationInfo.seinfo);
        }
        // Write the package restrications
        writePackageRestrictionsLPr(userHandle);
    }

    void markPrebundledPackageInstalledLPr(int userId, String packageName) {
        editPrebundledPackagesLPw(userId);
        mPrebundledPackages.get(userId).add(packageName);
    }

    boolean wasPrebundledPackageInstalledLPr(int userId, String packageName) {
        if (mPrebundledPackages.get(userId) == null) {
            return false;
        }
        return mPrebundledPackages.get(userId).contains(packageName);
    }

    void writeDisabledSysPackageLPr(XmlSerializer serializer, final PackageSetting pkg)
@@ -2051,7 +2142,7 @@ final class Settings {
    }

    boolean readLPw(PackageManagerService service, List<UserInfo> users, int sdkVersion,
            boolean onlyCore) {
            boolean onlyCore, Installer installer) {
        FileInputStream str = null;
        if (mBackupSettingsFilename.exists()) {
            try {
@@ -2269,6 +2360,8 @@ final class Settings {
            }
        }

        migratePrebundedPackagesIfNeededLPr(users, installer);

        /*
         * Make sure all the updated system packages have their shared users
         * associated with them.
@@ -3171,7 +3264,9 @@ final class Settings {
                continue;
            }
            // Only system apps are initially installed.
            ps.setInstalled((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0, userHandle);
            boolean setInstalled = ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0) ||
                    wasPrebundledPackageInstalledLPr(UserHandle.USER_OWNER, ps.name);
            ps.setInstalled(setInstalled, userHandle);
            // Need to create a data directory for all apps under this user.
            installer.createUserData(ps.name,
                    UserHandle.getUid(userHandle, ps.appId), userHandle,
@@ -3179,6 +3274,7 @@ final class Settings {
        }
        readDefaultPreferredAppsLPw(service, userHandle);
        writePackageRestrictionsLPr(userHandle);
        writePrebundledPackagesLPr(userHandle);
    }

    void removeUserLPw(int userId) {
@@ -3187,10 +3283,13 @@ final class Settings {
            entry.getValue().removeUser(userId);
        }
        mPreferredActivities.remove(userId);
        mPrebundledPackages.remove(userId);
        File file = getUserPackagesStateFile(userId);
        file.delete();
        file = getUserPackagesStateBackupFile(userId);
        file.delete();
        file = getUserPrebundledStateFile(userId);
        file.delete();
        removeCrossProfileIntentFiltersLPw(userId);
    }