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

Commit 041d55c1 authored by Sudheer Shanka's avatar Sudheer Shanka Committed by Android (Google) Code Review
Browse files

Merge "Update StorageManagerService handling of packages info."

parents f95d6a17 2ac25a96
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -702,6 +702,18 @@ public abstract class PackageManagerInternal {
     */
    public abstract SparseArray<String> getAppsWithSharedUserIds();

    /**
     * Get the value of attribute android:sharedUserId for the given packageName if specified,
     * otherwise {@code null}.
     */
    public abstract String getSharedUserIdForPackage(@NonNull String packageName);

    /**
     * Get all packages which specified the given sharedUserId as android:sharedUserId attribute
     * or an empty array if no package specified it.
     */
    public abstract String[] getPackagesForSharedUserId(@NonNull String sharedUserId, int userId);

    /**
     * Return if device is currently in a "core" boot environment, typically
     * used to support full-disk encryption. Only apps marked with
+3 −1
Original line number Diff line number Diff line
@@ -101,9 +101,11 @@ public abstract class StorageManagerInternal {
     * Delete storage sandbox for the given package.
     *
     * @param packageName The package for which the sandbox needs to be destroyed.
     * @param sharedUserId The sharedUserId if specified by the package.
     * @param userId The userId in which the sandbox needs to be destroyed.
     */
    public abstract void destroySandboxForApp(@NonNull String packageName, int userId);
    public abstract void destroySandboxForApp(@NonNull String packageName,
            @Nullable String sharedUserId, int userId);

    /**
     * @return Labels of storage volumes that are visible to the given userId.
+58 −144
Original line number Diff line number Diff line
@@ -112,7 +112,6 @@ import android.util.TimeUtils;
import android.util.Xml;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.AppFuseMount;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.FuseUnavailableMountException;
@@ -323,12 +322,6 @@ class StorageManagerService extends IStorageManager.Stub
    @GuardedBy("mPackagesLock")
    private final SparseArray<ArraySet<String>> mPackages = new SparseArray<>();

    @GuardedBy("mPackagesLock")
    private final ArrayMap<String, Integer> mAppIds = new ArrayMap<>();

    @GuardedBy("mPackagesLock")
    private final SparseArray<String> mSandboxIds = new SparseArray<>();

    /**
     * List of volumes visible to any user.
     * TODO: may be have a map of userId -> volumes?
@@ -876,13 +869,12 @@ class StorageManagerService extends IStorageManager.Stub
            try {
                mVold.reset();

                pushPackagesInfo();
                // Tell vold about all existing and started users
                for (UserInfo user : users) {
                    mVold.onUserAdded(user.id, user.serialNumber);
                }
                for (int userId : systemUnlockedUsers) {
                    mVold.onUserStarted(userId, getPackagesArrayForUser(userId));
                    sendUserStartedCallback(userId);
                    mStoraged.onUserStarted(userId);
                }
                mVold.onSecureKeyguardStateChanged(mSecureKeyguardShowing);
@@ -899,7 +891,7 @@ class StorageManagerService extends IStorageManager.Stub
        // staging area is ready so it's ready for zygote-forked apps to
        // bind mount against.
        try {
            mVold.onUserStarted(userId, getPackagesArrayForUser(userId));
            sendUserStartedCallback(userId);
            mStoraged.onUserStarted(userId);
        } catch (Exception e) {
            Slog.wtf(TAG, e);
@@ -932,11 +924,52 @@ class StorageManagerService extends IStorageManager.Stub
            Slog.wtf(TAG, e);
        }

        synchronized (mPackagesLock) {
            mPackages.delete(userId);
        }

        synchronized (mLock) {
            mSystemUnlockedUsers = ArrayUtils.removeInt(mSystemUnlockedUsers, userId);
        }
    }

    private void sendUserStartedCallback(int userId) throws Exception {
        if (!ENABLE_ISOLATED_STORAGE) {
            mVold.onUserStarted(userId, EmptyArray.STRING, EmptyArray.INT, EmptyArray.STRING);
        }

        final String[] packages;
        final int[] appIds;
        final String[] sandboxIds;
        final SparseArray<String> sharedUserIds = mPmInternal.getAppsWithSharedUserIds();
        final List<ApplicationInfo> appInfos =
                mContext.getPackageManager().getInstalledApplicationsAsUser(
                        PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
        synchronized (mPackagesLock) {
            final ArraySet<String> userPackages = new ArraySet<>();
            final ArrayMap<String, Integer> packageToAppId = new ArrayMap<>();
            for (int i = appInfos.size() - 1; i >= 0; --i) {
                final ApplicationInfo appInfo = appInfos.get(i);
                if (appInfo.isInstantApp()) {
                    continue;
                }
                userPackages.add(appInfo.packageName);
                packageToAppId.put(appInfo.packageName, UserHandle.getAppId(appInfo.uid));
            }
            mPackages.put(userId, userPackages);

            packages = new String[userPackages.size()];
            appIds = new int[userPackages.size()];
            sandboxIds = new String[userPackages.size()];
            for (int i = userPackages.size() - 1; i >= 0; --i) {
                packages[i] = userPackages.valueAt(i);
                appIds[i] = packageToAppId.get(packages[i]);
                sandboxIds[i] = getSandboxId(packages[i], sharedUserIds.get(appIds[i]));
            }
        }
        mVold.onUserStarted(userId, packages, appIds, sandboxIds);
    }

    @Override
    public void onAwakeStateChanged(boolean isAwake) {
        // Ignored
@@ -1454,111 +1487,12 @@ class StorageManagerService extends IStorageManager.Stub
    }

    private void start() {
        collectPackagesInfo();
        connect();
    }

    @VisibleForTesting
    void collectPackagesInfo() {
        if (!ENABLE_ISOLATED_STORAGE) return;

        resetPackageData();
        final SparseArray<String> sharedUserIds = mPmInternal.getAppsWithSharedUserIds();
        final int[] userIds = mUmInternal.getUserIds();
        for (int userId : userIds) {
            final List<ApplicationInfo> appInfos
                    = mContext.getPackageManager().getInstalledApplicationsAsUser(
                            PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
            synchronized (mPackagesLock) {
                final ArraySet<String> userPackages = getAvailablePackagesForUserPL(userId);
                for (int i = appInfos.size() - 1; i >= 0; --i) {
                    if (appInfos.get(i).isInstantApp()) {
                        continue;
                    }
                    final String packageName = appInfos.get(i).packageName;
                    userPackages.add(packageName);

                    final int appId = UserHandle.getAppId(appInfos.get(i).uid);
                    mAppIds.put(packageName, appId);
                    mSandboxIds.put(appId, getSandboxId(packageName, sharedUserIds.get(appId)));
                }
            }
        }
    }

    private void resetPackageData() {
        synchronized (mPackagesLock) {
            mPackages.clear();
            mAppIds.clear();
            mSandboxIds.clear();
        }
    }

    private static String getSandboxId(String packageName, String sharedUserId) {
        return sharedUserId == null ? packageName : SHARED_SANDBOX_ID_PREFIX + sharedUserId;
    }
    private void pushPackagesInfo() throws RemoteException {
        if (!ENABLE_ISOLATED_STORAGE) return;

        // Arrays to fill up from {@link #mAppIds}
        final String[] allPackageNames;
        final int[] appIdsForPackages;

        // Arrays to fill up from {@link #mSandboxIds}
        final int[] allAppIds;
        final String[] sandboxIdsForApps;
        synchronized (mPackagesLock) {
            allPackageNames = new String[mAppIds.size()];
            appIdsForPackages = new int[mAppIds.size()];
            for (int i = mAppIds.size() - 1; i >= 0; --i) {
                allPackageNames[i] = mAppIds.keyAt(i);
                appIdsForPackages[i] = mAppIds.valueAt(i);
            }

            allAppIds = new int[mSandboxIds.size()];
            sandboxIdsForApps = new String[mSandboxIds.size()];
            for (int i = mSandboxIds.size() - 1; i >= 0; --i) {
                allAppIds[i] = mSandboxIds.keyAt(i);
                sandboxIdsForApps[i] = mSandboxIds.valueAt(i);
            }
        }
        mVold.addAppIds(allPackageNames, appIdsForPackages);
        mVold.addSandboxIds(allAppIds, sandboxIdsForApps);
    }

    @GuardedBy("mPackagesLock")
    private ArraySet<String> getAvailablePackagesForUserPL(int userId) {
        ArraySet<String> userPackages = mPackages.get(userId);
        if (userPackages == null) {
            userPackages = new ArraySet<>();
            mPackages.put(userId, userPackages);
        }
        return userPackages;
    }

    private String[] getPackagesArrayForUser(int userId) {
        if (!ENABLE_ISOLATED_STORAGE) return EmptyArray.STRING;

        final ArraySet<String> userPackages;
        synchronized (mPackagesLock) {
            userPackages = getAvailablePackagesForUserPL(userId);
            if (!userPackages.isEmpty()) {
                return userPackages.toArray(new String[0]);
            }
        }
        final List<ApplicationInfo> appInfos =
                mContext.getPackageManager().getInstalledApplicationsAsUser(
                        PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
        synchronized (mPackagesLock) {
            for (int i = appInfos.size() - 1; i >= 0; --i) {
                if (appInfos.get(i).isInstantApp()) {
                    continue;
                }
                userPackages.add(appInfos.get(i).packageName);
            }
            return userPackages.toArray(new String[0]);
        }
    }

    private void connect() {
        IBinder binder = ServiceManager.getService("storaged");
@@ -3122,15 +3056,8 @@ class StorageManagerService extends IStorageManager.Stub
            throw new SecurityException("Shady looking path " + path);
        }

        final int uid = mPmInternal.getPackageUid(packageName,
                PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
        final String sandboxId;
        synchronized (mPackagesLock) {
            sandboxId = mSandboxIds.get(UserHandle.getAppId(uid));
        }
        if (uid < 0 || sandboxId == null) {
            throw new IllegalArgumentException("Unknown package " + packageName);
        }
        final String sharedUserId = mPmInternal.getSharedUserIdForPackage(packageName);
        final String sandboxId = getSandboxId(packageName, sharedUserId);

        final Matcher m = PATTERN_TRANSLATE.matcher(path);
        if (m.matches()) {
@@ -3139,7 +3066,9 @@ class StorageManagerService extends IStorageManager.Stub

            // Does path belong to any packages belonging to this UID? If so,
            // they get to go straight through to legacy paths.
            final String[] pkgs = mContext.getPackageManager().getPackagesForUid(uid);
            final String[] pkgs = (sharedUserId == null)
                    ? new String[] {packageName}
                    : mPmInternal.getPackagesForSharedUserId(sharedUserId, userId);
            for (String pkg : pkgs) {
                if (devicePath.startsWith("Android/data/" + pkg + "/") ||
                        devicePath.startsWith("Android/media/" + pkg + "/") ||
@@ -3758,16 +3687,14 @@ class StorageManagerService extends IStorageManager.Stub
                int userId) {
            final String sandboxId;
            synchronized (mPackagesLock) {
                final ArraySet<String> userPackages = getAvailablePackagesForUserPL(userId);
                final ArraySet<String> userPackages = mPackages.get(userId);
                // If userPackages is empty, it means the user is not started yet, so no need to
                // do anything now.
                if (userPackages.isEmpty() || userPackages.contains(packageName)) {
                if (userPackages == null || userPackages.contains(packageName)) {
                    return;
                }
                userPackages.add(packageName);
                mAppIds.put(packageName, appId);
                sandboxId = getSandboxId(packageName, sharedUserId);
                mSandboxIds.put(appId, sandboxId);
            }

            try {
@@ -3778,34 +3705,21 @@ class StorageManagerService extends IStorageManager.Stub
        }

        @Override
        public void destroySandboxForApp(String packageName, int userId) {
        public void destroySandboxForApp(String packageName, String sharedUserId, int userId) {
            if (!ENABLE_ISOLATED_STORAGE) {
                return;
            }
            final int appId;
            final String sandboxId;
            final String sandboxId = getSandboxId(packageName, sharedUserId);
            synchronized (mPackagesLock) {
                final ArraySet<String> userPackages = getAvailablePackagesForUserPL(userId);
                final ArraySet<String> userPackages = mPackages.get(userId);
                // If the userPackages is null, it means the user is not started but we still
                // need to delete the sandbox data though.
                if (userPackages != null) {
                    userPackages.remove(packageName);
                appId = mAppIds.get(packageName);
                sandboxId = mSandboxIds.get(appId);

                // If the package is not uninstalled in any other users, remove appId and sandboxId
                // corresponding to it from the internal state.
                boolean installedInAnyUser = false;
                for (int i = mPackages.size() - 1; i >= 0; --i) {
                    if (mPackages.valueAt(i).contains(packageName)) {
                        installedInAnyUser = true;
                        break;
                    }
                }
                if (!installedInAnyUser) {
                    mAppIds.remove(packageName);
                    mSandboxIds.remove(appId);
                }
            }
            try {
                mVold.destroySandboxForApp(packageName, appId, sandboxId, userId);
                mVold.destroySandboxForApp(packageName, sandboxId, userId);
            } catch (Exception e) {
                Slog.wtf(TAG, e);
            }
+50 −1
Original line number Diff line number Diff line
@@ -322,6 +322,7 @@ import dalvik.system.CloseGuard;
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
import libcore.util.EmptyArray;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -9530,7 +9531,8 @@ public class PackageManagerService extends IPackageManager.Stub
                    }
                }
                if (deleteSandboxData && getStorageManagerInternal() != null) {
                    getStorageManagerInternal().destroySandboxForApp(pkg.packageName, realUserId);
                    getStorageManagerInternal().destroySandboxForApp(pkg.packageName,
                            pkg.mSharedUserId, realUserId);
                }
            } catch (PackageManagerException e) {
                // Should not happen
@@ -22941,6 +22943,20 @@ public class PackageManagerService extends IPackageManager.Stub
            }
        }
        @Override
        public String getSharedUserIdForPackage(String packageName) {
            synchronized (mPackages) {
                return getSharedUserIdForPackageLocked(packageName);
            }
        }
        @Override
        public String[] getPackagesForSharedUserId(String sharedUserId, int userId) {
            synchronized (mPackages) {
                return getPackagesForSharedUserIdLocked(sharedUserId, userId);
            }
        }
        @Override
        public boolean isOnlyCoreApps() {
            return PackageManagerService.this.isOnlyCoreApps();
@@ -22953,6 +22969,7 @@ public class PackageManagerService extends IPackageManager.Stub
        }
    }
    @GuardedBy("mPackages")
    private SparseArray<String> getAppsWithSharedUserIdsLocked() {
        final SparseArray<String> sharedUserIds = new SparseArray<>();
        synchronized (mPackages) {
@@ -22963,6 +22980,38 @@ public class PackageManagerService extends IPackageManager.Stub
        return sharedUserIds;
    }
    @GuardedBy("mPackages")
    private String getSharedUserIdForPackageLocked(String packageName) {
        final PackageSetting ps = mSettings.mPackages.get(packageName);
        return (ps != null && ps.isSharedUser()) ? ps.sharedUser.name : null;
    }
    @GuardedBy("mPackages")
    private String[] getPackagesForSharedUserIdLocked(String sharedUserId, int userId) {
        try {
            final SharedUserSetting sus = mSettings.getSharedUserLPw(
                    sharedUserId, 0, 0, false);
            if (sus == null) {
                return EmptyArray.STRING;
            }
            String[] res = new String[sus.packages.size()];
            final Iterator<PackageSetting> it = sus.packages.iterator();
            int i = 0;
            while (it.hasNext()) {
                PackageSetting ps = it.next();
                if (ps.getInstalled(userId)) {
                    res[i++] = ps.name;
                } else {
                    res = ArrayUtils.removeElement(String.class, res, res[i]);
                }
            }
            return res;
        } catch (PackageManagerException e) {
            // Should not happen
        }
        return EmptyArray.STRING;
    }
    @Override
    public void grantDefaultPermissionsToEnabledCarrierApps(String[] packageNames, int userId) {
        enforceSystemOrPhoneCaller("grantPermissionsToEnabledCarrierApps");
+5 −24
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@ import android.os.UserManagerInternal;
import android.os.storage.StorageManagerInternal;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.SparseArray;

import org.junit.Before;
import org.junit.Test;
@@ -38,9 +37,6 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.ArrayList;
import java.util.List;

@SmallTest
@RunWith(AndroidJUnit4.class)
public class StorageManagerServiceTest {
@@ -83,29 +79,14 @@ public class StorageManagerServiceTest {

        when(mUmi.getUserIds()).thenReturn(new int[] { 0 });

        {
            final SparseArray<String> res = new SparseArray<>();
            res.put(UID_COLORS, NAME_COLORS);
            when(mPmi.getAppsWithSharedUserIds()).thenReturn(res);
        }

        {
            final List<ApplicationInfo> res = new ArrayList<>();
            res.add(buildApplicationInfo(PKG_GREY, UID_GREY));
            res.add(buildApplicationInfo(PKG_RED, UID_COLORS));
            res.add(buildApplicationInfo(PKG_BLUE, UID_COLORS));
            when(mPm.getInstalledApplicationsAsUser(anyInt(), anyInt())).thenReturn(res);
        }

        when(mPmi.getPackageUid(eq(PKG_GREY), anyInt(), anyInt())).thenReturn(UID_GREY);
        when(mPmi.getPackageUid(eq(PKG_RED), anyInt(), anyInt())).thenReturn(UID_COLORS);
        when(mPmi.getPackageUid(eq(PKG_BLUE), anyInt(), anyInt())).thenReturn(UID_COLORS);
        when(mPmi.getSharedUserIdForPackage(eq(PKG_GREY))).thenReturn(null);
        when(mPmi.getSharedUserIdForPackage(eq(PKG_RED))).thenReturn(NAME_COLORS);
        when(mPmi.getSharedUserIdForPackage(eq(PKG_BLUE))).thenReturn(NAME_COLORS);

        when(mPm.getPackagesForUid(eq(UID_GREY))).thenReturn(new String[] { PKG_GREY });
        when(mPm.getPackagesForUid(eq(UID_COLORS))).thenReturn(new String[] { PKG_RED, PKG_BLUE });
        when(mPmi.getPackagesForSharedUserId(eq(NAME_COLORS), anyInt()))
                .thenReturn(new String[] { PKG_RED, PKG_BLUE });

        mService = new StorageManagerService(mContext);
        mService.collectPackagesInfo();
    }

    @Test