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

Commit 9d6e509a authored by Iavor-Valentin Iftime's avatar Iavor-Valentin Iftime Committed by Android (Google) Code Review
Browse files

Merge "Check for NLS bind permission when rebinding services" into tm-qpr-dev

parents cb377cff 3e34d574
Loading
Loading
Loading
Loading
+73 −25
Original line number Diff line number Diff line
@@ -918,6 +918,23 @@ abstract public class ManagedServices {
        return false;
    }

    protected boolean isPackageOrComponentAllowedWithPermission(ComponentName component,
            int userId) {
        if (!(isPackageOrComponentAllowed(component.flattenToString(), userId)
                || isPackageOrComponentAllowed(component.getPackageName(), userId))) {
            return false;
        }
        return componentHasBindPermission(component, userId);
    }

    private boolean componentHasBindPermission(ComponentName component, int userId) {
        ServiceInfo info = getServiceInfo(component, userId);
        if (info == null) {
            return false;
        }
        return mConfig.bindPermission.equals(info.permission);
    }

    boolean isPackageOrComponentUserSet(String pkgOrComponent, int userId) {
        synchronized (mApproved) {
            ArraySet<String> services = mUserSetServices.get(userId);
@@ -975,6 +992,7 @@ abstract public class ManagedServices {
                    for (int uid : uidList) {
                        if (isPackageAllowed(pkgName, UserHandle.getUserId(uid))) {
                            anyServicesInvolved = true;
                            trimApprovedListsForInvalidServices(pkgName, UserHandle.getUserId(uid));
                        }
                    }
                }
@@ -1107,8 +1125,7 @@ abstract public class ManagedServices {

        synchronized (mMutex) {
            if (enabled) {
                if (isPackageOrComponentAllowed(component.flattenToString(), userId)
                        || isPackageOrComponentAllowed(component.getPackageName(), userId)) {
                if (isPackageOrComponentAllowedWithPermission(component, userId)) {
                    registerServiceLocked(component, userId);
                } else {
                    Slog.d(TAG, component + " no longer has permission to be bound");
@@ -1246,6 +1263,33 @@ abstract public class ManagedServices {
        return removed;
    }

    private void trimApprovedListsForInvalidServices(String packageName, int userId) {
        synchronized (mApproved) {
            final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
            if (approvedByType == null) {
                return;
            }
            for (int i = 0; i < approvedByType.size(); i++) {
                final ArraySet<String> approved = approvedByType.valueAt(i);
                for (int j = approved.size() - 1; j >= 0; j--) {
                    final String approvedPackageOrComponent = approved.valueAt(j);
                    if (TextUtils.equals(getPackageName(approvedPackageOrComponent), packageName)) {
                        final ComponentName component = ComponentName.unflattenFromString(
                                approvedPackageOrComponent);
                        if (component != null && !componentHasBindPermission(component, userId)) {
                            approved.removeAt(j);
                            if (DEBUG) {
                                Slog.v(TAG, "Removing " + approvedPackageOrComponent
                                        + " from approved list; no bind permission found "
                                        + mConfig.bindPermission);
                            }
                        }
                    }
                }
            }
        }
    }

    protected String getPackageName(String packageOrComponent) {
        final ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
        if (component != null) {
@@ -1432,12 +1476,7 @@ abstract public class ManagedServices {
            final int userId = componentsToBind.keyAt(i);
            final Set<ComponentName> add = componentsToBind.get(userId);
            for (ComponentName component : add) {
                try {
                    ServiceInfo info = mPm.getServiceInfo(component,
                            PackageManager.GET_META_DATA
                                    | PackageManager.MATCH_DIRECT_BOOT_AWARE
                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                            userId);
                ServiceInfo info = getServiceInfo(component, userId);
                if (info == null) {
                    Slog.w(TAG, "Not binding " + getCaption() + " service " + component
                            + ": service not found");
@@ -1451,9 +1490,6 @@ abstract public class ManagedServices {
                Slog.v(TAG,
                        "enabling " + getCaption() + " for " + userId + ": " + component);
                registerService(info, userId);
                } catch (RemoteException e) {
                    e.rethrowFromSystemServer();
                }
            }
        }
    }
@@ -1478,8 +1514,7 @@ abstract public class ManagedServices {
    void reregisterService(final ComponentName cn, final int userId) {
        // If rebinding a package that died, ensure it still has permission
        // after the rebind delay
        if (isPackageOrComponentAllowed(cn.getPackageName(), userId)
                || isPackageOrComponentAllowed(cn.flattenToString(), userId)) {
        if (isPackageOrComponentAllowedWithPermission(cn, userId)) {
            registerService(cn, userId);
        }
    }
@@ -1718,6 +1753,19 @@ abstract public class ManagedServices {
        }
    }

    private ServiceInfo getServiceInfo(ComponentName component, int userId) {
        try {
            return mPm.getServiceInfo(component,
                    PackageManager.GET_META_DATA
                            | PackageManager.MATCH_DIRECT_BOOT_AWARE
                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                    userId);
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
        }
        return null;
    }

    public class ManagedServiceInfo implements IBinder.DeathRecipient {
        public IInterface service;
        public ComponentName component;
+79 −0
Original line number Diff line number Diff line
@@ -33,8 +33,10 @@ import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -52,8 +54,10 @@ import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IInterface;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -871,6 +875,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
            return true;
        });

        mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>());
        service.addApprovedList("a", 0, true);

        service.reregisterService(cn, 0);
@@ -901,6 +906,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
            return true;
        });

        mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>());
        service.addApprovedList("a", 0, false);

        service.reregisterService(cn, 0);
@@ -931,6 +937,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
            return true;
        });

        mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>());
        service.addApprovedList("a/a", 0, true);

        service.reregisterService(cn, 0);
@@ -961,6 +968,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
            return true;
        });

        mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>());
        service.addApprovedList("a/a", 0, false);

        service.reregisterService(cn, 0);
@@ -1117,6 +1125,58 @@ public class ManagedServicesTest extends UiServiceTestCase {
        }
    }

    @Test
    public void testUpgradeAppNoPermissionNoRebind() throws Exception {
        Context context = spy(getContext());
        doReturn(true).when(context).bindServiceAsUser(any(), any(), anyInt(), any());

        ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles,
                mIpm,
                APPROVAL_BY_COMPONENT);

        List<String> packages = new ArrayList<>();
        packages.add("package");
        addExpectedServices(service, packages, 0);

        final ComponentName unapprovedComponent = ComponentName.unflattenFromString("package/C1");
        final ComponentName approvedComponent = ComponentName.unflattenFromString("package/C2");

        // Both components are approved initially
        mExpectedPrimaryComponentNames.clear();
        mExpectedPrimaryPackages.clear();
        mExpectedPrimaryComponentNames.put(0, "package/C1:package/C2");
        mExpectedSecondaryComponentNames.clear();
        mExpectedSecondaryPackages.clear();

        loadXml(service);

        //Component package/C1 loses bind permission
        when(mIpm.getServiceInfo(any(), anyLong(), anyInt())).thenAnswer(
                (Answer<ServiceInfo>) invocation -> {
                    ComponentName invocationCn = invocation.getArgument(0);
                    if (invocationCn != null) {
                        ServiceInfo serviceInfo = new ServiceInfo();
                        serviceInfo.packageName = invocationCn.getPackageName();
                        serviceInfo.name = invocationCn.getClassName();
                        if (invocationCn.equals(unapprovedComponent)) {
                            serviceInfo.permission = "none";
                        } else {
                            serviceInfo.permission = service.getConfig().bindPermission;
                        }
                        serviceInfo.metaData = null;
                        return serviceInfo;
                    }
                    return null;
                }
        );

        // Trigger package update
        service.onPackagesChanged(false, new String[]{"package"}, new int[]{0});

        assertFalse(service.isComponentEnabledForCurrentProfiles(unapprovedComponent));
        assertTrue(service.isComponentEnabledForCurrentProfiles(approvedComponent));
    }

    @Test
    public void testSetPackageOrComponentEnabled() throws Exception {
        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
@@ -1820,6 +1880,25 @@ public class ManagedServicesTest extends UiServiceTestCase {
        assertTrue(profiles.isProfileUser(13));
    }

    private void mockServiceInfoWithMetaData(List<ComponentName> componentNames,
            ManagedServices service, ArrayMap<ComponentName, Bundle> metaDatas)
            throws RemoteException {
        when(mIpm.getServiceInfo(any(), anyLong(), anyInt())).thenAnswer(
                (Answer<ServiceInfo>) invocation -> {
                    ComponentName invocationCn = invocation.getArgument(0);
                    if (invocationCn != null && componentNames.contains(invocationCn)) {
                        ServiceInfo serviceInfo = new ServiceInfo();
                        serviceInfo.packageName = invocationCn.getPackageName();
                        serviceInfo.name = invocationCn.getClassName();
                        serviceInfo.permission = service.getConfig().bindPermission;
                        serviceInfo.metaData = metaDatas.get(invocationCn);
                        return serviceInfo;
                    }
                    return null;
                }
        );
    }

    private void resetComponentsAndPackages() {
        ArrayMap<Integer, ArrayMap<Integer, String>> empty = new ArrayMap(1);
        ArrayMap<Integer, String> emptyPkgs = new ArrayMap(0);