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

Commit 42d61605 authored by Todd Kennedy's avatar Todd Kennedy
Browse files

Auto udpate package list

Change-Id: I4e4f1666f5cdfb74800435642f564bc98e1fad4e
Fixes: 69963506
Test: Manual. Can add users w/o blocking
parent dc4cb146
Loading
Loading
Loading
Loading
+74 −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 android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.PackageManagerInternal.PackageListObserver;

import com.android.server.LocalServices;

import java.util.List;

/**
 * All of the package name installed on the system.
 * <p>A self observable list that automatically removes the listener when it goes out of scope.
 *
 * @hide Only for use within the system server.
 */
public class PackageList implements PackageListObserver, AutoCloseable {
    private final PackageListObserver mWrappedObserver;
    private final List<String> mPackageNames;

    /**
     * Create a new object.
     * <p>Ownership of the given {@link List} transfers to this object and should not
     * be modified by the caller.
     */
    public PackageList(@NonNull List<String> packageNames, @Nullable PackageListObserver observer) {
        mPackageNames = packageNames;
        mWrappedObserver = observer;
    }

    @Override
    public void onPackageAdded(String packageName) {
        if (mWrappedObserver != null) {
            mWrappedObserver.onPackageAdded(packageName);
        }
    }

    @Override
    public void onPackageRemoved(String packageName) {
        if (mWrappedObserver != null) {
            mWrappedObserver.onPackageRemoved(packageName);
        }
    }

    @Override
    public void close() throws Exception {
        LocalServices.getService(PackageManagerInternal.class).removePackageListObserver(this);
    }

    /**
     * Returns the names of packages installed on the system.
     * <p>The list is a copy-in-time and the actual set of installed packages may differ. Real
     * time updates to the package list are sent via the {@link PackageListObserver} callback.
     */
    public @NonNull List<String> getPackageNames() {
        return mPackageNames;
    }
}
+37 −0
Original line number Diff line number Diff line
@@ -53,6 +53,14 @@ public abstract class PackageManagerInternal {
    @Retention(RetentionPolicy.SOURCE)
    public @interface KnownPackage {}

    /** Observer called whenever the list of packages changes */
    public interface PackageListObserver {
        /** A package was added to the system. */
        void onPackageAdded(@NonNull String packageName);
        /** A package was removed from the system. */
        void onPackageRemoved(@NonNull String packageName);
    }

    /**
     * Provider for package names.
     */
@@ -434,6 +442,35 @@ public abstract class PackageManagerInternal {
     */
    public abstract @Nullable PackageParser.Package getPackage(@NonNull String packageName);

    /**
     * Returns a list without a change observer.
     *
     * {@see #getPackageList(PackageListObserver)}
     */
    public @NonNull PackageList getPackageList() {
        return getPackageList(null);
    }

    /**
     * Returns the list of packages installed at the time of the method call.
     * <p>The given observer is notified when the list of installed packages
     * changes [eg. a package was installed or uninstalled]. It will not be
     * notified if a package is updated.
     * <p>The package list will not be updated automatically as packages are
     * installed / uninstalled. Any changes must be handled within the observer.
     */
    public abstract @NonNull PackageList getPackageList(@Nullable PackageListObserver observer);

    /**
     * Removes the observer.
     * <p>Generally not needed. {@link #getPackageList(PackageListObserver)} will automatically
     * remove the observer.
     * <p>Does nothing if the observer isn't currently registered.
     * <p>Observers are notified asynchronously and it's possible for an observer to be
     * invoked after its been removed.
     */
    public abstract void removePackageListObserver(@NonNull PackageListObserver observer);

    /**
     * Returns a package object for the disabled system package name.
     */
+65 −3
Original line number Diff line number Diff line
@@ -163,10 +163,12 @@ import android.content.pm.PackageCleanItem;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageList;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
import android.content.pm.PackageManager.PackageInfoFlags;
import android.content.pm.PackageManagerInternal.PackageListObserver;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.ActivityIntentInfo;
import android.content.pm.PackageParser.Package;
@@ -757,6 +759,9 @@ public class PackageManagerService extends IPackageManager.Stub
    @GuardedBy("mPackages")
    final SparseArray<Map<String, Integer>> mChangedPackagesSequenceNumbers = new SparseArray<>();
    @GuardedBy("mPackages")
    final private ArraySet<PackageListObserver> mPackageListObservers = new ArraySet<>();
    class PackageParserCallback implements PackageParser.Callback {
        @Override public final boolean hasFeature(String feature) {
            return PackageManagerService.this.hasSystemFeature(feature, 0);
@@ -2095,6 +2100,10 @@ public class PackageManagerService extends IPackageManager.Stub
                }
            }
            if (allNewUsers && !update) {
                notifyPackageAdded(packageName);
            }
            // Log current value of "unknown sources" setting
            EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
                    getUnknownSourcesSettings());
@@ -12983,6 +12992,34 @@ public class PackageManagerService extends IPackageManager.Stub
        });
    }
    @Override
    public void notifyPackageAdded(String packageName) {
        final PackageListObserver[] observers;
        synchronized (mPackages) {
            if (mPackageListObservers.size() == 0) {
                return;
            }
            observers = (PackageListObserver[]) mPackageListObservers.toArray();
        }
        for (int i = observers.length - 1; i >= 0; --i) {
            observers[i].onPackageAdded(packageName);
        }
    }
    @Override
    public void notifyPackageRemoved(String packageName) {
        final PackageListObserver[] observers;
        synchronized (mPackages) {
            if (mPackageListObservers.size() == 0) {
                return;
            }
            observers = (PackageListObserver[]) mPackageListObservers.toArray();
        }
        for (int i = observers.length - 1; i >= 0; --i) {
            observers[i].onPackageRemoved(packageName);
        }
    }
    /**
     * Sends a broadcast for the given action.
     * <p>If {@code isInstantApp} is {@code true}, then the broadcast is protected with
@@ -17640,6 +17677,7 @@ public class PackageManagerService extends IPackageManager.Stub
                        removedPackage, extras,
                        Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
                        null, null, broadcastUsers, instantUserIds);
                    packageSender.notifyPackageRemoved(removedPackage);
                }
            }
            if (removedAppId >= 0) {
@@ -20395,10 +20433,9 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
            }
        }
        sUserManager.systemReady();
        // If we upgraded grant all default permissions before kicking off.
        for (int userId : grantPermissionsUserIds) {
            mDefaultPermissionPolicy.grantDefaultPermissions(mPackages.values(), userId);
            mDefaultPermissionPolicy.grantDefaultPermissions(userId);
        }
        if (grantPermissionsUserIds == EMPTY_INT_ARRAY) {
@@ -22445,8 +22482,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    }
    void onNewUserCreated(final int userId) {
        mDefaultPermissionPolicy.grantDefaultPermissions(userId);
        synchronized(mPackages) {
            mDefaultPermissionPolicy.grantDefaultPermissions(mPackages.values(), userId);
            // If permission review for legacy apps is required, we represent
            // dagerous permissions for such apps as always granted runtime
            // permissions to keep per user flag state whether review is needed.
@@ -22932,6 +22969,29 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
            }
        }
        @Override
        public PackageList getPackageList(PackageListObserver observer) {
            synchronized (mPackages) {
                final int N = mPackages.size();
                final ArrayList<String> list = new ArrayList<>(N);
                for (int i = 0; i < N; i++) {
                    list.add(mPackages.keyAt(i));
                }
                final PackageList packageList = new PackageList(list, observer);
                if (observer != null) {
                    mPackageListObservers.add(packageList);
                }
                return packageList;
            }
        }
        @Override
        public void removePackageListObserver(PackageListObserver observer) {
            synchronized (mPackages) {
                mPackageListObservers.remove(observer);
            }
        }
        @Override
        public PackageParser.Package getDisabledPackage(String packageName) {
            synchronized (mPackages) {
@@ -23594,4 +23654,6 @@ interface PackageSender {
        final IIntentReceiver finishedReceiver, final int[] userIds, int[] instantUserIds);
    void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
        boolean includeStopped, int appId, int[] userIds, int[] instantUserIds);
    void notifyPackageAdded(String packageName);
    void notifyPackageRemoved(String packageName);
}
+18 −9
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageList;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
@@ -252,11 +253,11 @@ public final class DefaultPermissionGrantPolicy {
        }
    }

    public void grantDefaultPermissions(Collection<PackageParser.Package> packages, int userId) {
    public void grantDefaultPermissions(int userId) {
        if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_EMBEDDED, 0)) {
            grantAllRuntimePermissions(packages, userId);
            grantAllRuntimePermissions(userId);
        } else {
            grantPermissionsToSysComponentsAndPrivApps(packages, userId);
            grantPermissionsToSysComponentsAndPrivApps(userId);
            grantDefaultSystemHandlerPermissions(userId);
            grantDefaultPermissionExceptions(userId);
        }
@@ -278,10 +279,14 @@ public final class DefaultPermissionGrantPolicy {
        }
    }

    private void grantAllRuntimePermissions(
            Collection<PackageParser.Package> packages, int userId) {
    private void grantAllRuntimePermissions(int userId) {
        Log.i(TAG, "Granting all runtime permissions for user " + userId);
        for (PackageParser.Package pkg : packages) {
        final PackageList packageList = mServiceInternal.getPackageList();
        for (String packageName : packageList.getPackageNames()) {
            final PackageParser.Package pkg = mServiceInternal.getPackage(packageName);
            if (pkg == null) {
                continue;
            }
            grantRuntimePermissionsForPackage(userId, pkg);
        }
    }
@@ -290,10 +295,14 @@ public final class DefaultPermissionGrantPolicy {
        mHandler.sendEmptyMessage(MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS);
    }

    private void grantPermissionsToSysComponentsAndPrivApps(
            Collection<PackageParser.Package> packages, int userId) {
    private void grantPermissionsToSysComponentsAndPrivApps(int userId) {
        Log.i(TAG, "Granting permissions to platform components for user " + userId);
        for (PackageParser.Package pkg : packages) {
        final PackageList packageList = mServiceInternal.getPackageList();
        for (String packageName : packageList.getPackageNames()) {
            final PackageParser.Package pkg = mServiceInternal.getPackage(packageName);
            if (pkg == null) {
                continue;
            }
            if (!isSysComponentOrPersistentPlatformSignedPrivApp(pkg)
                    || !doesPackageSupportRuntimePermissions(pkg)
                    || pkg.requestedPermissions.isEmpty()) {
+75 −57
Original line number Diff line number Diff line
@@ -17,28 +17,30 @@
package com.android.server.pm;

import android.content.IIntentReceiver;

import android.os.Bundle;
import android.support.test.runner.AndroidJUnit4;

import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.io.File;

// runtest -c com.android.server.pm.PackageManagerServiceTest frameworks-services

@SmallTest
public class PackageManagerServiceTest extends AndroidTestCase {
    @Override
    protected void setUp() throws Exception {
        super.setUp();
// bit FrameworksServicesTests:com.android.server.pm.PackageManagerServiceTest
@RunWith(AndroidJUnit4.class)
public class PackageManagerServiceTest {
    @Before
    public void setUp() throws Exception {
    }

    @Override
    protected void tearDown() throws Exception {
        super.tearDown();
    @After
    public void tearDown() throws Exception {
    }

    @Test
    public void testPackageRemoval() throws Exception {
        class PackageSenderImpl implements PackageSender {
            public void sendPackageBroadcast(final String action, final String pkg,
@@ -51,6 +53,14 @@ public class PackageManagerServiceTest extends AndroidTestCase {
                    boolean sendBootComplete, boolean includeStopped, int appId,
                    int[] userIds, int[] instantUserIds) {
            }

            @Override
            public void notifyPackageAdded(String packageName) {
            }

            @Override
            public void notifyPackageRemoved(String packageName) {
            }
        }

        PackageSenderImpl sender = new PackageSenderImpl();
@@ -59,12 +69,12 @@ public class PackageManagerServiceTest extends AndroidTestCase {
                new PackageManagerService.PackageRemovedInfo(sender);

        // Initial conditions: nothing there
      assertNull(pri.removedUsers);
      assertNull(pri.broadcastUsers);
        Assert.assertNull(pri.removedUsers);
        Assert.assertNull(pri.broadcastUsers);

        // populateUsers with nothing leaves nothing
        pri.populateUsers(null, setting);
      assertNull(pri.broadcastUsers);
        Assert.assertNull(pri.broadcastUsers);

        // Create a real (non-null) PackageSetting and confirm that the removed
        // users are copied properly
@@ -73,17 +83,25 @@ public class PackageManagerServiceTest extends AndroidTestCase {
                "primaryCpuAbiString", "secondaryCpuAbiString",
                "cpuAbiOverrideString", 0, 0, 0, "parentPackageName", null, 0,
                null, null);
      pri.populateUsers(new int[] {1, 2, 3, 4, 5}, setting);
      assertNotNull(pri.broadcastUsers);
      assertEquals(5, pri.broadcastUsers.length);
        pri.populateUsers(new int[] {
                1, 2, 3, 4, 5
        }, setting);
        Assert.assertNotNull(pri.broadcastUsers);
        Assert.assertEquals(5, pri.broadcastUsers.length);
        Assert.assertNotNull(pri.instantUserIds);
        Assert.assertEquals(0, pri.instantUserIds.length);

        // Exclude a user
        pri.broadcastUsers = null;
        final int EXCLUDED_USER_ID = 4;
        setting.setInstantApp(true, EXCLUDED_USER_ID);
      pri.populateUsers(new int[] {1, 2, 3, EXCLUDED_USER_ID, 5}, setting);
      assertNotNull(pri.broadcastUsers);
      assertEquals(5 - 1, pri.broadcastUsers.length);
        pri.populateUsers(new int[] {
                1, 2, 3, EXCLUDED_USER_ID, 5
        }, setting);
        Assert.assertNotNull(pri.broadcastUsers);
        Assert.assertEquals(4, pri.broadcastUsers.length);
        Assert.assertNotNull(pri.instantUserIds);
        Assert.assertEquals(1, pri.instantUserIds.length);

        // TODO: test that sendApplicationHiddenForUser() actually fills in
        // broadcastUsers