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

Commit cf2bb175 authored by Makoto Onuki's avatar Makoto Onuki Committed by Android (Google) Code Review
Browse files

Merge "Use a factory class for dependency injection, add more tests."

parents 9265189f b643fb0e
Loading
Loading
Loading
Loading
+375 −413

File changed.

Preview size limit exceeded, changes collapsed.

+0 −14
Original line number Diff line number Diff line
@@ -230,20 +230,6 @@ class Owners {
        return mDeviceOwner != null;
    }

    static boolean isInstalledForUser(String packageName, int userHandle) {
        try {
            PackageInfo pi = (AppGlobals.getPackageManager())
                    .getPackageInfo(packageName, 0, userHandle);
            if (pi != null && pi.applicationInfo.flags != 0) {
                return true;
            }
        } catch (RemoteException re) {
            throw new RuntimeException("Package manager has died", re);
        }

        return false;
    }

    private boolean readLegacyOwnerFile(File file) {
        if (!file.exists()) {
            // Already migrated or the device has no owners.
+0 −135
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 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 com.android.server.devicepolicy;

import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.UserHandle;
import android.provider.Settings;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

/**
 * Tests for application restrictions persisting via profile owner:
 *   make -j FrameworksServicesTests
 *   runtest --path frameworks/base/services/tests/servicestests/ \
 *       src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java
 */
public class ApplicationRestrictionsTest extends AndroidTestCase {

    static DevicePolicyManager sDpm;
    static ComponentName sAdminReceiver;
    private static final String RESTRICTED_APP = "com.example.restrictedApp";
    static boolean sAddBack = false;

    public static class AdminReceiver extends DeviceAdminReceiver {

        @Override
        public void onDisabled(Context context, Intent intent) {
            if (sAddBack) {
                sDpm.setActiveAdmin(sAdminReceiver, false);
                sAddBack = false;
            }

            super.onDisabled(context, intent);
        }
    }

    @Override
    public void setUp() {
        final Context context = getContext();
        sAdminReceiver = new ComponentName(mContext.getPackageName(),
                AdminReceiver.class.getName());
        sDpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
        Settings.Secure.putInt(context.getContentResolver(),
                Settings.Secure.USER_SETUP_COMPLETE, 0);
        sDpm.setProfileOwner(sAdminReceiver, "Test", UserHandle.myUserId());
        Settings.Secure.putInt(context.getContentResolver(),
                Settings.Secure.USER_SETUP_COMPLETE, 1);
        // Remove the admin if already registered. It's async, so add it back
        // when the admin gets a broadcast. Otherwise add it back right away.
        if (sDpm.isAdminActive(sAdminReceiver)) {
            sAddBack = true;
            sDpm.removeActiveAdmin(sAdminReceiver);
        } else {
            sDpm.setActiveAdmin(sAdminReceiver, false);
        }
    }

    @Override
    public void tearDown() {
        Settings.Secure.putInt(getContext().getContentResolver(),
                Settings.Secure.USER_SETUP_COMPLETE, 0);
        sDpm.removeActiveAdmin(sAdminReceiver);
        Settings.Secure.putInt(getContext().getContentResolver(),
                Settings.Secure.USER_SETUP_COMPLETE, 1);
    }

    public void testSettingRestrictions() {
        Bundle restrictions = new Bundle();
        restrictions.putString("KEY_STRING", "Foo");
        assertNotNull(sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP));
        sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, restrictions);
        Bundle returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP);
        assertNotNull(returned);
        assertEquals(returned.size(), 1);
        assertEquals(returned.get("KEY_STRING"), "Foo");
        sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, new Bundle());
        returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP);
        assertEquals(returned.size(), 0);
    }

    public void testRestrictionTypes() {
        Bundle restrictions = new Bundle();
        restrictions.putString("KEY_STRING", "Foo");
        restrictions.putInt("KEY_INT", 7);
        restrictions.putBoolean("KEY_BOOLEAN", true);
        restrictions.putBoolean("KEY_BOOLEAN_2", false);
        restrictions.putString("KEY_STRING_2", "Bar");
        restrictions.putStringArray("KEY_STR_ARRAY", new String[] { "Foo", "Bar" });
        sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, restrictions);
        Bundle returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP);
        assertTrue(returned.getBoolean("KEY_BOOLEAN"));
        assertFalse(returned.getBoolean("KEY_BOOLEAN_2"));
        assertFalse(returned.getBoolean("KEY_BOOLEAN_3"));
        assertEquals(returned.getInt("KEY_INT"), 7);
        assertTrue(returned.get("KEY_BOOLEAN") instanceof Boolean);
        assertTrue(returned.get("KEY_INT") instanceof Integer);
        assertEquals(returned.get("KEY_STRING"), "Foo");
        assertEquals(returned.get("KEY_STRING_2"), "Bar");
        assertTrue(returned.getStringArray("KEY_STR_ARRAY") instanceof String[]);
        sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, new Bundle());
    }

    public void testTextEscaping() {
        String fancyText = "<This contains XML/> <JSON> "
                + "{ \"One\": { \"OneOne\": \"11\", \"OneTwo\": \"12\" }, \"Two\": \"2\" } <JSON/>";
        Bundle restrictions = new Bundle();
        restrictions.putString("KEY_FANCY_TEXT", fancyText);
        sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, restrictions);
        Bundle returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP);
        assertEquals(returned.getString("KEY_FANCY_TEXT"), fancyText);
    }
}
+136 −113
Original line number Diff line number Diff line
@@ -19,11 +19,11 @@ import com.android.internal.widget.LockPatternUtils;

import android.app.IActivityManager;
import android.app.NotificationManager;
import android.app.backup.IBackupManager;
import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.media.IAudioService;
import android.os.Looper;
import android.os.PowerManager.WakeLock;
import android.os.PowerManagerInternal;
import android.os.UserHandle;
import android.os.UserManager;
@@ -73,12 +73,29 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
        }
    }

    public final DpmMockContext context;

    public DevicePolicyManagerServiceTestable(DpmMockContext context, File dataDir) {
        this(new MockInjector(context, dataDir));
    }

    private DevicePolicyManagerServiceTestable(MockInjector injector) {
        super(injector);
        this.context = injector.context;
    }

    private static class MockInjector extends Injector {

        public final DpmMockContext context;

        public final File dataDir;

        public final File systemUserDataDir;
        public final File secondUserDataDir;

    public DevicePolicyManagerServiceTestable(DpmMockContext context, File dataDir) {
        private MockInjector(DpmMockContext context, File dataDir) {
            super(context);
            this.context = context;
            this.dataDir = dataDir;

            systemUserDataDir = new File(dataDir, "user0");
@@ -87,58 +104,53 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
            secondUserDataDir = new File(dataDir, "user" + DpmMockContext.CALLER_USER_HANDLE);
            DpmTestUtils.clearDir(secondUserDataDir);

        when(getContext().environment.getUserSystemDirectory(
            when(context.environment.getUserSystemDirectory(
                    eq(DpmMockContext.CALLER_USER_HANDLE))).thenReturn(secondUserDataDir);
        }

    @Override
    DpmMockContext getContext() {
        return (DpmMockContext) super.getContext();
    }

        @Override
        Owners newOwners() {
        return new OwnersTestable(getContext(), dataDir);
            return new OwnersTestable(context, dataDir);
        }

        @Override
        UserManager getUserManager() {
        return getContext().userManager;
    }

    @Override
    PackageManager getPackageManager() {
        return getContext().packageManager;
            return context.userManager;
        }

        @Override
        PowerManagerInternal getPowerManagerInternal() {
        return getContext().powerManagerInternal;
            return context.powerManagerInternal;
        }

        @Override
        NotificationManager getNotificationManager() {
        return getContext().notificationManager;
            return context.notificationManager;
        }

        @Override
        IWindowManager getIWindowManager() {
        return getContext().iwindowManager;
            return context.iwindowManager;
        }

        @Override
        IActivityManager getIActivityManager() {
        return getContext().iactivityManager;
            return context.iactivityManager;
        }

        @Override
        IPackageManager getIPackageManager() {
        return getContext().ipackageManager;
            return context.ipackageManager;
        }

        @Override
    LockPatternUtils newLockPatternUtils(Context context) {
        return getContext().lockPatternUtils;
        IBackupManager getIBackupManager() {
            return context.ibackupManager;
        }

        @Override
        IAudioService getIAudioService() {
            return context.iaudioService;
        }

        @Override
@@ -146,6 +158,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
            return Looper.getMainLooper();
        }

        @Override
        LockPatternUtils newLockPatternUtils() {
            return context.lockPatternUtils;
        }

        @Override
        String getDevicePolicyFilePathForSystemUser() {
            return systemUserDataDir.getAbsolutePath();
@@ -153,66 +170,72 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi

        @Override
        long binderClearCallingIdentity() {
        return getContext().binder.clearCallingIdentity();
            return context.binder.clearCallingIdentity();
        }

        @Override
        void binderRestoreCallingIdentity(long token) {
        getContext().binder.restoreCallingIdentity(token);
            context.binder.restoreCallingIdentity(token);
        }

        @Override
        int binderGetCallingUid() {
        return getContext().binder.getCallingUid();
            return context.binder.getCallingUid();
        }

        @Override
        int binderGetCallingPid() {
        return getContext().binder.getCallingPid();
            return context.binder.getCallingPid();
        }

        @Override
        UserHandle binderGetCallingUserHandle() {
        return getContext().binder.getCallingUserHandle();
            return context.binder.getCallingUserHandle();
        }

        @Override
        boolean binderIsCallingUidMyUid() {
        return getContext().binder.isCallerUidMyUid();
            return context.binder.isCallerUidMyUid();
        }

        @Override
        File environmentGetUserSystemDirectory(int userId) {
        return getContext().environment.getUserSystemDirectory(userId);
            return context.environment.getUserSystemDirectory(userId);
        }

        @Override
        void powerManagerGoToSleep(long time, int reason, int flags) {
        getContext().powerManager.goToSleep(time, reason, flags);
            context.powerManager.goToSleep(time, reason, flags);
        }

        @Override
        boolean systemPropertiesGetBoolean(String key, boolean def) {
        return getContext().systemProperties.getBoolean(key, def);
            return context.systemProperties.getBoolean(key, def);
        }

        @Override
        long systemPropertiesGetLong(String key, long def) {
        return getContext().systemProperties.getLong(key, def);
            return context.systemProperties.getLong(key, def);
        }

        @Override
        String systemPropertiesGet(String key, String def) {
        return getContext().systemProperties.get(key, def);
            return context.systemProperties.get(key, def);
        }

        @Override
        String systemPropertiesGet(String key) {
        return getContext().systemProperties.get(key);
            return context.systemProperties.get(key);
        }

        @Override
        void systemPropertiesSet(String key, String value) {
        getContext().systemProperties.set(key, value);
            context.systemProperties.set(key, value);
        }

        @Override
        boolean userManagerIsSplitSystemUser() {
            return context.userManagerForMock.isSplitSystemUser();
        }
    }
}
+190 −2
Original line number Diff line number Diff line
@@ -30,15 +30,24 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.content.pm.PackageInfo;
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.util.Pair;

import org.mockito.ArgumentCaptor;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -87,6 +96,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
        setUpPackageManagerForAdmin(admin3);

        setUpApplicationInfo(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
        setUpPackageInfo();
        setUpUserManager();
    }

    /**
@@ -132,7 +143,85 @@ public class DevicePolicyManagerTest extends DpmTestBase {
                eq(DpmMockContext.CALLER_USER_HANDLE));
    }

    public void testHasNoFeature() {
    /**
     * Set up a mock result for {@link IPackageManager#getPackageInfo(String, int, int)} for user
     * {@link DpmMockContext#CALLER_USER_HANDLE} as well as the system user.
     */
    private void setUpPackageInfo() throws Exception {
        final PackageInfo pi = mRealTestContext.getPackageManager().getPackageInfo(
                admin1.getPackageName(), 0);
        assertTrue(pi.applicationInfo.flags != 0);

        doReturn(pi).when(mContext.ipackageManager).getPackageInfo(
                eq(admin1.getPackageName()),
                eq(0),
                eq(DpmMockContext.CALLER_USER_HANDLE));
        doReturn(pi).when(mContext.ipackageManager).getPackageInfo(
                eq(admin1.getPackageName()),
                eq(0),
                eq(UserHandle.USER_SYSTEM));
    }

    private void setUpUserManager() {
        // Emulate UserManager.set/getApplicationRestriction().
        final Map<Pair<String, UserHandle>, Bundle> appRestrictions = new HashMap<>();

        // UM.setApplicationRestrictions() will save to appRestrictions.
        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Throwable {
                String pkg = (String) invocation.getArguments()[0];
                Bundle bundle = (Bundle) invocation.getArguments()[1];
                UserHandle user = (UserHandle) invocation.getArguments()[2];

                appRestrictions.put(Pair.create(pkg, user), bundle);

                return null;
            }
        }).when(mContext.userManager).setApplicationRestrictions(
                anyString(), any(Bundle.class), any(UserHandle.class));

        // UM.getApplicationRestrictions() will read from appRestrictions.
        doAnswer(new Answer<Bundle>() {
            @Override
            public Bundle answer(InvocationOnMock invocation) throws Throwable {
                String pkg = (String) invocation.getArguments()[0];
                UserHandle user = (UserHandle) invocation.getArguments()[1];

                return appRestrictions.get(Pair.create(pkg, user));
            }
        }).when(mContext.userManager).getApplicationRestrictions(
                anyString(), any(UserHandle.class));

        // System user is always running.
        when(mContext.userManager.isUserRunning(MockUtils.checkUserHandle(UserHandle.USER_SYSTEM)))
                .thenReturn(true);

        // Set up (default) UserInfo for CALLER_USER_HANDLE.
        final UserInfo uh = new UserInfo(DpmMockContext.CALLER_USER_HANDLE,
                "user" + DpmMockContext.CALLER_USER_HANDLE, 0);

        when(mContext.userManager.getUserInfo(eq(DpmMockContext.CALLER_USER_HANDLE)))
                .thenReturn(uh);
    }

    private void setAsProfileOwner(ComponentName admin) {
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);

        final UserInfo uh = new UserInfo(DpmMockContext.CALLER_USER_HANDLE, "user", 0);

        // DO needs to be an DA.
        dpm.setActiveAdmin(admin, /* replace =*/ false);

        // Fire!
        assertTrue(dpm.setProfileOwner(admin, "owner-name", DpmMockContext.CALLER_USER_HANDLE));

        // Check
        assertEquals(admin1, dpm.getProfileOwnerAsUser(DpmMockContext.CALLER_USER_HANDLE));
    }

    public void testHasNoFeature() throws Exception {
        when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
                .thenReturn(false);

@@ -399,6 +488,105 @@ public class DevicePolicyManagerTest extends DpmTestBase {

        // TODO Check other internal calls.
    }

    /**
     * Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs
     * successfully.
     */
    public void testSetDeviceOwner() throws Exception {
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);

        // Call from a process on the system user.
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;

        // DO needs to be an DA.
        dpm.setActiveAdmin(admin1, /* replace =*/ false);

        // Fire!
        assertTrue(dpm.setDeviceOwner(admin1.getPackageName(), "owner-name"));

        // Verify internal calls.
        verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
                eq(admin1.getPackageName()));

        // TODO We should check if the caller has called clearCallerIdentity().
        verify(mContext.ibackupManager, times(1)).setBackupServiceActive(
                eq(UserHandle.USER_SYSTEM), eq(false));

        verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
                MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
                MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));

        assertEquals(admin1.getPackageName(), dpm.getDeviceOwner());

        // TODO Test getDeviceOwnerName() too.  To do so, we need to change
        // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
    }

    /**
     * Test for: {@link DevicePolicyManager#setDeviceOwner} Package doesn't exist.
     */
    public void testSetDeviceOwner_noSuchPackage() {
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);

        // Call from a process on the system user.
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;

        // DO needs to be an DA.
        dpm.setActiveAdmin(admin1, /* replace =*/ false);
        try {
            dpm.setDeviceOwner("a.b.c");
            fail("Didn't throw IllegalArgumentException");
        } catch (IllegalArgumentException expected) {
        }
    }

    public void testSetDeviceOwner_failures() throws Exception {
        // TODO Test more failure cases.  Basically test all chacks in enforceCanSetDeviceOwner().
    }

    public void testSetProfileOwner() throws Exception {
        setAsProfileOwner(admin1);
    }

    public void testSetProfileOwner_failures() throws Exception {
        // TODO Test more failure cases.  Basically test all chacks in enforceCanSetProfileOwner().
    }

    public void testSetGetApplicationRestriction() {
        setAsProfileOwner(admin1);

        {
            Bundle rest = new Bundle();
            rest.putString("KEY_STRING", "Foo1");
            dpm.setApplicationRestrictions(admin1, "pkg1", rest);
        }

        {
            Bundle rest = new Bundle();
            rest.putString("KEY_STRING", "Foo2");
            dpm.setApplicationRestrictions(admin1, "pkg2", rest);
        }

        {
            Bundle returned = dpm.getApplicationRestrictions(admin1, "pkg1");
            assertNotNull(returned);
            assertEquals(returned.size(), 1);
            assertEquals(returned.get("KEY_STRING"), "Foo1");
        }

        {
            Bundle returned = dpm.getApplicationRestrictions(admin1, "pkg2");
            assertNotNull(returned);
            assertEquals(returned.size(), 1);
            assertEquals(returned.get("KEY_STRING"), "Foo2");
        }

        dpm.setApplicationRestrictions(admin1, "pkg2", new Bundle());
        assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg2").size());
    }
}
Loading