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

Commit 23ab7f54 authored by Amith Yamasani's avatar Amith Yamasani
Browse files

Kernel mapping for package scope by user

Inform the kernel via configfs, of userids that
should be excluded when an app is not installed
for them.

Also push userid to remove_userid when a user is
removed so that the exclude list of that user can
be cleaned up in one command for all packages.

Test: runtest -x ....KernelPackageMappingTests.java
Change-Id: Ib94b1a0b737f45b2d03deb9650f0f0eb68e363d9
parent b3f417ec
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

# We only want this apk build for tests.
LOCAL_MODULE_TAGS := tests

# Include all test java files.
LOCAL_SRC_FILES := \
    $(call all-java-files-under, src)

LOCAL_STATIC_JAVA_LIBRARIES := \
    android-support-test \
    frameworks-base-testutils

LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := FrameworksCorePackageManagerTests

LOCAL_CERTIFICATE := platform

include $(BUILD_PACKAGE)
+31 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2017 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          android:installLocation="internalOnly"
          package="com.android.frameworks.coretests.packagemanager"
          android:sharedUserId="android.uid.system">

    <application>
        <uses-library android:name="android.test.runner" />
    </application>

    <instrumentation
            android:name="android.support.test.runner.AndroidJUnitRunner"
            android:targetPackage="com.android.frameworks.coretests.packagemanager"
            android:label="Frameworks PackageManager Core Tests" />

</manifest>
+109 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.content.pm;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import android.content.Context;
import android.os.FileUtils;
import android.os.Process;
import android.os.ServiceManager;
import android.os.UserManager;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.util.Log;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.io.File;
import java.io.IOException;

/**
 * This test needs to be run without any secondary users on the device,
 * and selinux needs to be disabled with "adb shell setenforce 0".
 */
@RunWith(AndroidJUnit4.class)
public class KernelPackageMappingTests {

    private static final String TAG = "KernelPackageMapping";
    private static final String SDCARDFS_PATH = "/config/sdcardfs";

    private UserInfo mSecondaryUser;

    private static File getKernelPackageDir(String packageName) {
        return new File(new File(SDCARDFS_PATH), packageName);
    }

    private static File getKernelPackageFile(String packageName, String filename) {
        return new File(getKernelPackageDir(packageName), filename);
    }

    private UserManager getUserManager() {
        UserManager um = (UserManager) InstrumentationRegistry.getContext().getSystemService(
                Context.USER_SERVICE);
        return um;
    }

    private IPackageManager getIPackageManager() {
        IPackageManager ipm = IPackageManager.Stub.asInterface(
                ServiceManager.getService("package"));
        return ipm;
    }

    private static String getContent(File file) {
        try {
            return FileUtils.readTextFile(file, 0, null).trim();
        } catch (IOException ioe) {
            Log.w(TAG, "Couldn't read file " + file.getAbsolutePath() + "\n" + ioe);
            return "<error>";
        }
    }

    @Test
    public void testInstalledPrimary() throws Exception {
        assertEquals("1000", getContent(getKernelPackageFile("com.android.settings", "appid")));
    }

    @Test
    public void testInstalledAll() throws Exception {
        assertEquals("", getContent(getKernelPackageFile("com.android.settings",
                "excluded_userids")));
    }

    @Test
    public void testNotInstalledSecondary() throws Exception {
        mSecondaryUser = getUserManager().createUser("Secondary", 0);
        assertEquals(Integer.toString(mSecondaryUser.id),
                getContent(
                        getKernelPackageFile("com.android.frameworks.coretests.packagemanager",
                                "excluded_userids")));
    }

    @After
    public void shutDown() throws Exception {
        if (mSecondaryUser != null) {
            getUserManager().removeUser(mSecondaryUser.id);
        }
    }
}
+20 −0
Original line number Diff line number Diff line
@@ -2141,6 +2141,7 @@ public class PackageManagerService extends IPackageManager.Stub {
                    pkgSetting.setInstalled(install, UserHandle.USER_SYSTEM);
                }
            }
            scheduleWritePackageRestrictionsLocked(UserHandle.USER_SYSTEM);
        }
    }
@@ -13251,6 +13252,7 @@ public class PackageManagerService extends IPackageManager.Stub {
                    pkgSetting.setHidden(false, userId);
                    pkgSetting.setInstallReason(installReason, userId);
                    mSettings.writePackageRestrictionsLPr(userId);
                    mSettings.writeKernelMappingLPr(pkgSetting);
                    installed = true;
                }
            }
@@ -16345,6 +16347,7 @@ public class PackageManagerService extends IPackageManager.Stub {
            //note that the new package setting would have already been
            //added to mPackages. It hasn't been persisted yet.
            mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_INCOMPLETE);
            // TODO: Remove this write? It's also written at the end of this method
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings");
            mSettings.writeLPr();
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -16418,6 +16421,7 @@ public class PackageManagerService extends IPackageManager.Stub {
                } else if (!previousUserIds.contains(userId)) {
                    ps.setInstallReason(installReason, userId);
                }
                mSettings.writeKernelMappingLPr(ps);
            }
            res.name = pkgName;
            res.uid = newPackage.applicationInfo.uid;
@@ -17597,6 +17601,7 @@ public class PackageManagerService extends IPackageManager.Stub {
        // writer
        synchronized (mPackages) {
            boolean installedStateChanged = false;
            if (deletedPs != null) {
                if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
                    clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL);
@@ -17644,6 +17649,9 @@ public class PackageManagerService extends IPackageManager.Stub {
                        if (DEBUG_REMOVE) {
                            Slog.d(TAG, "    user " + userId + " => " + installed);
                        }
                        if (installed != ps.getInstalled(userId)) {
                            installedStateChanged = true;
                        }
                        ps.setInstalled(installed, userId);
                    }
                }
@@ -17653,6 +17661,9 @@ public class PackageManagerService extends IPackageManager.Stub {
                // Save settings now
                mSettings.writeLPr();
            }
            if (installedStateChanged) {
                mSettings.writeKernelMappingLPr(ps);
            }
        }
        if (removedAppId != -1) {
            // A user ID was deleted here. Go through all users and remove it
@@ -17795,6 +17806,7 @@ public class PackageManagerService extends IPackageManager.Stub {
                    UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG);
            if (applyUserRestrictions) {
                boolean installedStateChanged = false;
                if (DEBUG_REMOVE) {
                    Slog.d(TAG, "Propagating install state across reinstall");
                }
@@ -17803,6 +17815,9 @@ public class PackageManagerService extends IPackageManager.Stub {
                    if (DEBUG_REMOVE) {
                        Slog.d(TAG, "    user " + userId + " => " + installed);
                    }
                    if (installed != ps.getInstalled(userId)) {
                        installedStateChanged = true;
                    }
                    ps.setInstalled(installed, userId);
                    mSettings.writeRuntimePermissionsForUserLPr(userId, false);
@@ -17810,6 +17825,9 @@ public class PackageManagerService extends IPackageManager.Stub {
                // Regardless of writeSettings we need to ensure that this restriction
                // state propagation is persisted
                mSettings.writeAllUsersPackageRestrictionsLPr();
                if (installedStateChanged) {
                    mSettings.writeKernelMappingLPr(ps);
                }
            }
            // can downgrade to reader here
            if (writeSettings) {
@@ -18013,6 +18031,7 @@ public class PackageManagerService extends IPackageManager.Stub {
                    // broadcasts will be sent correctly.
                    if (DEBUG_REMOVE) Slog.d(TAG, "Not installed by other users, full delete");
                    ps.setInstalled(true, user.getIdentifier());
                    mSettings.writeKernelMappingLPr(ps);
                }
            } else {
                // This is a system app, so we assume that the
@@ -18122,6 +18141,7 @@ public class PackageManagerService extends IPackageManager.Stub {
                    ps.readUserState(nextUserId).domainVerificationStatus, 0,
                    PackageManager.INSTALL_REASON_UNKNOWN);
        }
        mSettings.writeKernelMappingLPr(ps);
    }
    private boolean clearPackageStateForUserLIF(PackageSetting ps, int userId,
+22 −0
Original line number Diff line number Diff line
@@ -40,6 +40,9 @@ import java.util.Set;
 * Settings base class for pending and resolved classes.
 */
abstract class PackageSettingBase extends SettingBase {

    private static final int[] EMPTY_INT_ARRAY = new int[0];

    /**
     * Indicates the state of installation. Used by PackageManager to figure out
     * incomplete installations. Say a package is being installed (the state is
@@ -502,6 +505,25 @@ abstract class PackageSettingBase extends SettingBase {
        userState.delete(userId);
    }

    public int[] getNotInstalledUserIds() {
        int count = 0;
        int userStateCount = userState.size();
        for (int i = 0; i < userStateCount; i++) {
            if (userState.valueAt(i).installed == false) {
                count++;
            }
        }
        if (count == 0) return EMPTY_INT_ARRAY;
        int[] excludedUserIds = new int[count];
        int idx = 0;
        for (int i = 0; i < userStateCount; i++) {
            if (userState.valueAt(i).installed == false) {
                excludedUserIds[idx++] = userState.keyAt(i);
            }
        }
        return excludedUserIds;
    }

    IntentFilterVerificationInfo getIntentFilterVerificationInfo() {
        return verificationInfo;
    }
Loading