Make DPM/DPMS unit-testable

- Now all services that DPMS uses are injectable.
- Introduce some wrappers to make static methods and final class mockable.
(e.g. for Binder.getCallingUid())

- In unit tests we replace those with Mockito mocks, except we use a partial
mock for PackageManager, because we use way too many methods of this and
most of them are okay to use directly.

- To install a partial mock to PackageManager, I needed to make
ApplicationPackageManager @hide public non-final.

- For a starter, added tests for DPM.setAmin().

Bug 24061108

Change-Id: I2afd51d8bc0038992d5f9be38c686260be775b75
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 7d1282b..cb2c9b7 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -67,6 +67,15 @@
             </intent-filter>
         </receiver>
 
+        <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmin"
+                android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data android:name="android.app.device_admin"
+                android:resource="@xml/device_admin_sample" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+            </intent-filter>
+        </receiver>
+
     </application>
 
     <instrumentation
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
new file mode 100644
index 0000000..cb439eb
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2015 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 com.android.internal.widget.LockPatternUtils;
+
+import android.app.IActivityManager;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Looper;
+import android.os.PowerManager.WakeLock;
+import android.os.PowerManagerInternal;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.view.IWindowManager;
+
+import java.io.File;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.when;
+
+/**
+ * Overrides {@link #DevicePolicyManagerService} for dependency injection.
+ */
+public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerService {
+    /**
+     * Overrides {@link #Owners} for dependency injection.
+     */
+    public static class OwnersTestable extends Owners {
+        public static final String LEGACY_FILE = "legacy.xml";
+        public static final String DEVICE_OWNER_FILE = "device_owner2.xml";
+        public static final String PROFILE_OWNER_FILE_BASE = "profile_owner.xml";
+
+        final private File mLegacyFile;
+        final private File mDeviceOwnerFile;
+        final private File mProfileOwnerBase;
+
+        public OwnersTestable(Context context, File dataDir) {
+            super(context);
+            mLegacyFile = new File(dataDir, LEGACY_FILE);
+            mDeviceOwnerFile = new File(dataDir, DEVICE_OWNER_FILE);
+            mProfileOwnerBase = new File(dataDir, PROFILE_OWNER_FILE_BASE);
+        }
+
+        @Override
+        File getLegacyConfigFileWithTestOverride() {
+            return mLegacyFile;
+        }
+
+        @Override
+        File getDeviceOwnerFileWithTestOverride() {
+            return mDeviceOwnerFile;
+        }
+
+        @Override
+        File getProfileOwnerFileWithTestOverride(int userId) {
+            return new File(mDeviceOwnerFile.getAbsoluteFile() + "-" + userId);
+        }
+    }
+
+    public final File dataDir;
+    public final File systemUserDataDir;
+    public final File secondUserDataDir;
+
+    public DevicePolicyManagerServiceTestable(DpmMockContext context, File dataDir) {
+        super(context);
+        this.dataDir = dataDir;
+
+        systemUserDataDir = new File(dataDir, "user0");
+        DpmTestUtils.clearDir(dataDir);
+
+        secondUserDataDir = new File(dataDir, "user" + DpmMockContext.CALLER_USER_HANDLE);
+        DpmTestUtils.clearDir(secondUserDataDir);
+
+        when(getContext().environment.getUserSystemDirectory(
+                eq(DpmMockContext.CALLER_USER_HANDLE))).thenReturn(secondUserDataDir);
+    }
+
+    @Override
+    DpmMockContext getContext() {
+        return (DpmMockContext) super.getContext();
+    }
+
+    @Override
+    protected Owners newOwners() {
+        return new OwnersTestable(getContext(), dataDir);
+    }
+
+    @Override
+    protected UserManager getUserManager() {
+        return getContext().userManager;
+    }
+
+    @Override
+    protected PackageManager getPackageManager() {
+        return getContext().packageManager;
+    }
+
+    @Override
+    protected PowerManagerInternal getPowerManagerInternal() {
+        return getContext().powerManagerInternal;
+    }
+
+    @Override
+    protected NotificationManager getNotificationManager() {
+        return getContext().notificationManager;
+    }
+
+    @Override
+    protected IWindowManager newIWindowManager() {
+        return getContext().iwindowManager;
+    }
+
+    @Override
+    protected IActivityManager getIActivityManager() {
+        return getContext().iactivityManager;
+    }
+
+    @Override
+    protected LockPatternUtils newLockPatternUtils(Context context) {
+        return getContext().lockPatternUtils;
+    }
+
+    @Override
+    protected Looper getMyLooper() {
+        return Looper.getMainLooper();
+    }
+
+    @Override
+    String getDevicePolicyFilePathForSystemUser() {
+        return systemUserDataDir.getAbsolutePath();
+    }
+
+    @Override
+    long binderClearCallingIdentity() {
+        return getContext().binder.clearCallingIdentity();
+    }
+
+    @Override
+    void binderRestoreCallingIdentity(long token) {
+        getContext().binder.restoreCallingIdentity(token);
+    }
+
+    @Override
+    int binderGetCallingUid() {
+        return getContext().binder.getCallingUid();
+    }
+
+    @Override
+    int binderGetCallingPid() {
+        return getContext().binder.getCallingPid();
+    }
+
+    @Override
+    UserHandle binderGetCallingUserHandle() {
+        return getContext().binder.getCallingUserHandle();
+    }
+
+    @Override
+    boolean binderIsCallingUidMyUid() {
+        return getContext().binder.isCallerUidMyUid();
+    }
+
+    @Override
+    File environmentGetUserSystemDirectory(int userId) {
+        return getContext().environment.getUserSystemDirectory(userId);
+    }
+
+    @Override
+    WakeLock powerManagerNewWakeLock(int levelAndFlags, String tag) {
+        return getContext().powerManager.newWakeLock(levelAndFlags, tag);
+    }
+
+    @Override
+    void powerManagerGoToSleep(long time, int reason, int flags) {
+        getContext().powerManager.goToSleep(time, reason, flags);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
new file mode 100644
index 0000000..7cce56c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2015 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 com.android.server.LocalServices;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManagerInternal;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
+
+import org.mockito.ArgumentCaptor;
+
+import java.util.List;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for {@link DevicePolicyManager} and {@link DevicePolicyManagerService}.
+ *
+ m FrameworksServicesTests &&
+ adb install \
+ -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+ adb shell am instrument -e class com.android.server.devicepolicy.DevicePolicyManagerTest \
+ -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+
+ (mmma frameworks/base/services/tests/servicestests/ for non-ninja build)
+ */
+public class DevicePolicyManagerTest extends DpmTestBase {
+
+    private DpmMockContext mContext;
+    public DevicePolicyManager dpm;
+    public DevicePolicyManagerServiceTestable dpms;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mContext = getContext();
+
+        when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
+                .thenReturn(true);
+
+        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+        dpms = new DevicePolicyManagerServiceTestable(mContext, dataDir);
+        dpm = new DevicePolicyManagerTestable(mContext, dpms);
+    }
+
+    public void testHasNoFeature() {
+        when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
+                .thenReturn(false);
+
+        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+        new DevicePolicyManagerServiceTestable(mContext, dataDir);
+
+        // If the device has no DPMS feature, it shouldn't register the local service.
+        assertNull(LocalServices.getService(DevicePolicyManagerInternal.class));
+    }
+
+    /**
+     * Caller doesn't have proper permissions.
+     */
+    public void testSetActiveAdmin_SecurityException() {
+        final ComponentName admin = new ComponentName(mRealTestContext, DummyDeviceAdmin.class);
+
+        // 1. Failure cases.
+
+        // Caller doesn't have MANAGE_DEVICE_ADMINS.
+        try {
+            dpm.setActiveAdmin(admin, false);
+            fail("Didn't throw SecurityException");
+        } catch (SecurityException expected) {
+        }
+
+        // Caller has MANAGE_DEVICE_ADMINS, but for different user.
+        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+        try {
+            dpm.setActiveAdmin(admin, false, DpmMockContext.CALLER_USER_HANDLE + 1);
+            fail("Didn't throw SecurityException");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    public void testSetActiveAdmin() {
+        final ComponentName admin = new ComponentName(mRealTestContext, DummyDeviceAdmin.class);
+
+        // 1. Prepare mock package manager (and other mocks)
+
+        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+        // Create ResolveInfo for the admin.
+        final Intent resolveIntent = new Intent();
+        resolveIntent.setComponent(admin);
+        final List<ResolveInfo> realResolveInfo =
+                mRealTestContext.getPackageManager().queryBroadcastReceivers(
+                        resolveIntent,
+                        PackageManager.GET_META_DATA
+                            | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
+        assertNotNull(realResolveInfo);
+        assertEquals(1, realResolveInfo.size());
+
+        // We need to rewrite the UID in the activity info.
+        realResolveInfo.get(0).activityInfo.applicationInfo.uid = DpmMockContext.CALLER_UID;
+
+        doReturn(realResolveInfo).when(mContext.packageManager).queryBroadcastReceivers(
+                any(Intent.class), // TODO check the intent too.
+                eq(PackageManager.GET_META_DATA
+                        | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
+                eq(DpmMockContext.CALLER_USER_HANDLE)
+        );
+
+        // 2. Everything is ready; call the method.
+        dpm.setActiveAdmin(admin, false);
+
+        // 3. Verify internal calls.
+
+        // Check if the boradcast is sent.
+        final ArgumentCaptor<Intent> intentCap = ArgumentCaptor.forClass(Intent.class);
+        final ArgumentCaptor<UserHandle> uhCap = ArgumentCaptor.forClass(UserHandle.class);
+
+        verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
+                intentCap.capture(),
+                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+
+        // First call from saveSettingsLocked().
+        assertEquals(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED,
+                intentCap.getAllValues().get(0).getAction());
+
+        // Second call from setActiveAdmin/sendAdminCommandLocked()
+        assertEquals(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
+                intentCap.getAllValues().get(1).getAction());
+
+        // TODO Verify other calls too.
+    }
+}
+
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java
new file mode 100644
index 0000000..325bf9f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTestable.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 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.DevicePolicyManager;
+
+/**
+ * Overrides {@link #DevicePolicyManager} for dependency injection.
+ */
+public class DevicePolicyManagerTestable extends DevicePolicyManager {
+    public final DevicePolicyManagerServiceTestable dpms;
+
+    public DevicePolicyManagerTestable(DpmMockContext context,
+            DevicePolicyManagerServiceTestable dpms) {
+        super(context, dpms);
+        this.dpms = dpms;
+    }
+
+    @Override
+    public int myUserId() {
+        return DpmMockContext.CALLER_USER_HANDLE;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index c2b8981..8644311 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -16,31 +16,328 @@
 
 package com.android.server.devicepolicy;
 
+import com.android.internal.widget.LockPatternUtils;
+
+import android.app.IActivityManager;
+import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.PowerManager.WakeLock;
+import android.os.PowerManagerInternal;
+import android.os.UserHandle;
 import android.os.UserManager;
+import android.test.mock.MockContext;
+import android.view.IWindowManager;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
 
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
 
-public class DpmMockContext extends ContextWrapper {
-    private final UserManager mMockUserManager;
+/**
+ * Context used throughout DPMS tests.
+ */
+public class DpmMockContext extends MockContext {
+    /**
+     * User-id of a non-system user we use throughout unit tests.
+     */
+    public static final int CALLER_USER_HANDLE = 20;
 
+    /**
+     * UID of the caller.
+     */
+    public static final int CALLER_UID = UserHandle.PER_USER_RANGE * CALLER_USER_HANDLE + 123;
 
-    public DpmMockContext(Context context) {
-        super(context);
-        mMockUserManager = mock(UserManager.class);
+    /**
+     * PID of the caller.
+     */
+    public static final int CALLER_PID = 22222;
+
+    /**
+     * UID of the system server.
+     */
+    public static final int SYSTEM_UID = android.os.Process.SYSTEM_UID;
+
+    /**
+     * PID of the system server.
+     */
+    public static final int SYSTEM_PID = 11111;
+
+    public static class MockBinder {
+        int mCallingUid = CALLER_UID;
+        int mCallingPid = CALLER_PID;
+
+        public long clearCallingIdentity() {
+            final long token = (((long) mCallingUid) << 32) | (mCallingPid);
+            mCallingUid = SYSTEM_UID;
+            mCallingPid = SYSTEM_PID;
+            return token;
+        }
+
+        public void restoreCallingIdentity(long token) {
+            mCallingUid = (int) (token >> 32);
+            mCallingPid = (int) token;
+        }
+
+        public int getCallingUid() {
+            return mCallingUid;
+        }
+
+        public int getCallingPid() {
+            return mCallingPid;
+        }
+
+        public UserHandle getCallingUserHandle() {
+            return new UserHandle(UserHandle.getUserId(getCallingUid()));
+        }
+
+        public boolean isCallerUidMyUid() {
+            return mCallingUid == SYSTEM_UID;
+        }
     }
 
-    public UserManager getMockUserManager() {
-        return mMockUserManager;
+    public static class EnvironmentForMock {
+        public File getUserSystemDirectory(int userId) {
+            return null;
+        }
+    }
+
+    public static class PowerManagerForMock {
+        public WakeLock newWakeLock(int levelAndFlags, String tag) {
+            return null;
+        }
+
+        public void goToSleep(long time, int reason, int flags) {
+        }
+    }
+
+    public final Context realTestContext;
+
+    /**
+     * Use this instance to verify unimplemented methods such as {@link #sendBroadcast}.
+     * (Spying on {@code this} instance will confuse mockito somehow and I got weired "wrong number
+     * of arguments" exceptions.)
+     */
+    public final Context spiedContext;
+
+    public final MockBinder binder;
+    public final EnvironmentForMock environment;
+    public final UserManager userManager;
+    public final PowerManagerForMock powerManager;
+    public final PowerManagerInternal powerManagerInternal;
+    public final NotificationManager notificationManager;
+    public final IWindowManager iwindowManager;
+    public final IActivityManager iactivityManager;
+    public final LockPatternUtils lockPatternUtils;
+
+    /** Note this is a partial mock, not a real mock. */
+    public final PackageManager packageManager;
+
+    public final List<String> callerPermissions = new ArrayList<>();
+
+    public DpmMockContext(Context context) {
+        realTestContext = context;
+        binder = new MockBinder();
+        environment = mock(EnvironmentForMock.class);
+        userManager = mock(UserManager.class);
+        powerManager = mock(PowerManagerForMock.class);
+        powerManagerInternal = mock(PowerManagerInternal.class);
+        notificationManager = mock(NotificationManager.class);
+        iwindowManager = mock(IWindowManager.class);
+        iactivityManager = mock(IActivityManager.class);
+        lockPatternUtils = mock(LockPatternUtils.class);
+
+        // Package manager is huge, so we use a partial mock instead.
+        packageManager = spy(context.getPackageManager());
+
+        spiedContext = mock(Context.class);
     }
 
     @Override
     public Object getSystemService(String name) {
         switch (name) {
             case Context.USER_SERVICE:
-                return mMockUserManager;
+                return userManager;
+            case Context.POWER_SERVICE:
+                return powerManager;
         }
-        return super.getSystemService(name);
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public PackageManager getPackageManager() {
+        return packageManager;
+    }
+
+    @Override
+    public void enforceCallingOrSelfPermission(String permission, String message) {
+        if (binder.getCallingUid() == SYSTEM_UID) {
+            return; // Assume system has all permissions.
+        }
+        if (!callerPermissions.contains(permission)) {
+            throw new SecurityException("Caller doesn't have " + permission + " : " + message);
+        }
+    }
+
+    @Override
+    public void sendBroadcast(Intent intent) {
+        spiedContext.sendBroadcast(intent);
+    }
+
+    @Override
+    public void sendBroadcast(Intent intent, String receiverPermission) {
+        spiedContext.sendBroadcast(intent, receiverPermission);
+    }
+
+    @Override
+    public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) {
+        spiedContext.sendBroadcastMultiplePermissions(intent, receiverPermissions);
+    }
+
+    @Override
+    public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
+        spiedContext.sendBroadcast(intent, receiverPermission, options);
+    }
+
+    @Override
+    public void sendBroadcast(Intent intent, String receiverPermission, int appOp) {
+        spiedContext.sendBroadcast(intent, receiverPermission, appOp);
+    }
+
+    @Override
+    public void sendOrderedBroadcast(Intent intent, String receiverPermission) {
+        spiedContext.sendOrderedBroadcast(intent, receiverPermission);
+    }
+
+    @Override
+    public void sendOrderedBroadcast(Intent intent, String receiverPermission,
+            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+            String initialData, Bundle initialExtras) {
+        spiedContext.sendOrderedBroadcast(intent, receiverPermission, resultReceiver, scheduler,
+                initialCode, initialData, initialExtras);
+    }
+
+    @Override
+    public void sendOrderedBroadcast(Intent intent, String receiverPermission, Bundle options,
+            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+            String initialData, Bundle initialExtras) {
+        spiedContext.sendOrderedBroadcast(intent, receiverPermission, options, resultReceiver,
+                scheduler,
+                initialCode, initialData, initialExtras);
+    }
+
+    @Override
+    public void sendOrderedBroadcast(Intent intent, String receiverPermission, int appOp,
+            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+            String initialData, Bundle initialExtras) {
+        spiedContext.sendOrderedBroadcast(intent, receiverPermission, appOp, resultReceiver,
+                scheduler,
+                initialCode, initialData, initialExtras);
+    }
+
+    @Override
+    public void sendBroadcastAsUser(Intent intent, UserHandle user) {
+        spiedContext.sendBroadcastAsUser(intent, user);
+    }
+
+    @Override
+    public void sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission) {
+        spiedContext.sendBroadcastAsUser(intent, user, receiverPermission);
+    }
+
+    @Override
+    public void sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission,
+            int appOp) {
+        spiedContext.sendBroadcastAsUser(intent, user, receiverPermission, appOp);
+    }
+
+    @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
+        spiedContext.sendOrderedBroadcastAsUser(intent, user, receiverPermission, resultReceiver,
+                scheduler, initialCode, initialData, initialExtras);
+    }
+
+    @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+            Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+        spiedContext.sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp,
+                resultReceiver,
+                scheduler, initialCode, initialData, initialExtras);
+    }
+
+    @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver,
+            Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+        spiedContext.sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp, options,
+                resultReceiver, scheduler, initialCode, initialData, initialExtras);
+    }
+
+    @Override
+    public void sendStickyBroadcast(Intent intent) {
+        spiedContext.sendStickyBroadcast(intent);
+    }
+
+    @Override
+    public void sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver resultReceiver,
+            Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+        spiedContext.sendStickyOrderedBroadcast(intent, resultReceiver, scheduler, initialCode,
+                initialData, initialExtras);
+    }
+
+    @Override
+    public void removeStickyBroadcast(Intent intent) {
+        spiedContext.removeStickyBroadcast(intent);
+    }
+
+    @Override
+    public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
+        spiedContext.sendStickyBroadcastAsUser(intent, user);
+    }
+
+    @Override
+    public void sendStickyOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+            String initialData, Bundle initialExtras) {
+        spiedContext.sendStickyOrderedBroadcastAsUser(intent, user, resultReceiver, scheduler, initialCode,
+                initialData, initialExtras);
+    }
+
+    @Override
+    public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
+        spiedContext.removeStickyBroadcastAsUser(intent, user);
+    }
+
+    @Override
+    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+        return spiedContext.registerReceiver(receiver, filter);
+    }
+
+    @Override
+    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
+            String broadcastPermission, Handler scheduler) {
+        return spiedContext.registerReceiver(receiver, filter, broadcastPermission, scheduler);
+    }
+
+    @Override
+    public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
+            IntentFilter filter, String broadcastPermission, Handler scheduler) {
+        return spiedContext.registerReceiverAsUser(receiver, user, filter, broadcastPermission,
+                scheduler);
+    }
+
+    @Override
+    public void unregisterReceiver(BroadcastReceiver receiver) {
+        spiedContext.unregisterReceiver(receiver);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index 445260b..77270c8 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -19,14 +19,25 @@
 import android.content.Context;
 import android.test.AndroidTestCase;
 
+import java.io.File;
+
 public class DpmTestBase extends AndroidTestCase {
-    private DpmMockContext mMockContext;
+    public static final String TAG = "DpmTest";
+
+    protected Context mRealTestContext;
+    protected DpmMockContext mMockContext;
+
+    public File dataDir;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
 
+        mRealTestContext = super.getContext();
         mMockContext = new DpmMockContext(super.getContext());
+
+        dataDir = new File(mRealTestContext.getCacheDir(), "test-data");
+        DpmTestUtils.clearDir(dataDir);
     }
 
     @Override
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java
new file mode 100644
index 0000000..a8e2c3c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 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.os.FileUtils;
+import android.util.Log;
+import android.util.Printer;
+
+import org.junit.Assert;
+
+import java.io.File;
+
+public class DpmTestUtils {
+    private DpmTestUtils() {
+    }
+
+    public static void clearDir(File dir) {
+        if (dir.exists()) {
+            Assert.assertTrue("failed to delete dir", FileUtils.deleteContents(dir));
+        }
+        dir.mkdirs();
+    }
+
+    public static Printer LOG_PRINTER = new Printer() {
+        @Override
+        public void println(String x) {
+            Log.i(DpmTestBase.TAG, x);
+        }
+    };
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
new file mode 100644
index 0000000..c47d194
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2015 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;
+
+public class DummyDeviceAdmin extends DeviceAdminReceiver {
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
new file mode 100644
index 0000000..f2a2bf7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 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 com.google.common.base.Objects;
+
+import android.os.UserHandle;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.mockito.Mockito;
+
+public class MockUtils {
+    private MockUtils() {
+    }
+
+    public static UserHandle checkUserHandle(final int userId) {
+        final Matcher<UserHandle> m = new BaseMatcher<UserHandle>() {
+            @Override
+            public boolean matches(Object item) {
+                if (item == null) return false;
+                return Objects.equal(((UserHandle) item).getIdentifier(), userId);
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("UserHandle: user-id= \"" + userId + "\"");
+            }
+        };
+        return Mockito.argThat(m);
+    }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
index 3b88fb1..a07d615 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
@@ -16,12 +16,11 @@
 
 package com.android.server.devicepolicy;
 
+import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.OwnersTestable;
+
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.pm.UserInfo;
-import android.os.FileUtils;
 import android.os.UserHandle;
-import android.test.AndroidTestCase;
 import android.util.Log;
 
 import java.io.BufferedReader;
@@ -31,8 +30,6 @@
 import java.io.InputStreamReader;
 import java.util.ArrayList;
 
-import junit.framework.Assert;
-
 import static org.mockito.Mockito.when;
 
 /**
@@ -47,58 +44,11 @@
  (mmma frameworks/base/services/tests/servicestests/ for non-ninja build)
  */
 public class OwnersTest extends DpmTestBase {
-    private static final String TAG = "DeviceOwnerTest";
-
-    private static final String LEGACY_FILE = "legacy.xml";
-    private static final String DEVICE_OWNER_FILE = "device_owner2.xml";
-    private static final String PROFILE_OWNER_FILE_BASE = "profile_owner.xml";
-
-    private File mDataDir;
-
-    private class OwnersSub extends Owners {
-        final File mLegacyFile;
-        final File mDeviceOwnerFile;
-        final File mProfileOwnerBase;
-
-        public OwnersSub() {
-            super(getContext());
-            mLegacyFile = new File(mDataDir, LEGACY_FILE);
-            mDeviceOwnerFile = new File(mDataDir, DEVICE_OWNER_FILE);
-            mProfileOwnerBase = new File(mDataDir, PROFILE_OWNER_FILE_BASE);
-        }
-
-        @Override
-        File getLegacyConfigFileWithTestOverride() {
-            return mLegacyFile;
-        }
-
-        @Override
-        File getDeviceOwnerFileWithTestOverride() {
-            return mDeviceOwnerFile;
-        }
-
-        @Override
-        File getProfileOwnerFileWithTestOverride(int userId) {
-            return new File(mDeviceOwnerFile.getAbsoluteFile() + "-" + userId);
-        }
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mDataDir = new File(getContext().getCacheDir(), "OwnersTest");
-        if (mDataDir.exists()) {
-            assertTrue("failed to delete dir", FileUtils.deleteContents(mDataDir));
-        }
-        mDataDir.mkdirs();
-        Log.i(TAG, "Created " + mDataDir);
-    }
-
     private String readAsset(String assetPath) throws IOException {
         final StringBuilder sb = new StringBuilder();
         try (BufferedReader br = new BufferedReader(
-                new InputStreamReader((getContext().getResources().getAssets().open(assetPath))))) {
+                new InputStreamReader(
+                        mRealTestContext.getResources().getAssets().open(assetPath)))) {
             String line;
             while ((line = br.readLine()) != null) {
                 sb.append(line);
@@ -126,7 +76,7 @@
             ui.id = userId;
             userInfos.add(ui);
         }
-        when(getContext().getMockUserManager().getUsers()).thenReturn(userInfos);
+        when(getContext().userManager.getUsers()).thenReturn(userInfos);
     }
 
     public void testUpgrade01() throws Exception {
@@ -134,9 +84,10 @@
 
         // First, migrate.
         {
-            final OwnersSub owners = new OwnersSub();
+            final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
 
-            createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test01/input.xml"));
+            createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
+                    readAsset("OwnersTest/test01/input.xml"));
 
             owners.load();
 
@@ -160,7 +111,7 @@
 
         // Then re-read and check.
         {
-            final OwnersSub owners = new OwnersSub();
+            final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
             owners.load();
 
             assertFalse(owners.hasDeviceOwner());
@@ -176,9 +127,10 @@
 
         // First, migrate.
         {
-            final OwnersSub owners = new OwnersSub();
+            final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
 
-            createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test02/input.xml"));
+            createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
+                    readAsset("OwnersTest/test02/input.xml"));
 
             owners.load();
 
@@ -204,7 +156,7 @@
 
         // Then re-read and check.
         {
-            final OwnersSub owners = new OwnersSub();
+            final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
             owners.load();
 
             assertTrue(owners.hasDeviceOwner());
@@ -223,9 +175,10 @@
 
         // First, migrate.
         {
-            final OwnersSub owners = new OwnersSub();
+            final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
 
-            createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test03/input.xml"));
+            createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
+                    readAsset("OwnersTest/test03/input.xml"));
 
             owners.load();
 
@@ -259,7 +212,7 @@
 
         // Then re-read and check.
         {
-            final OwnersSub owners = new OwnersSub();
+            final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
             owners.load();
 
             assertFalse(owners.hasDeviceOwner());
@@ -286,9 +239,10 @@
 
         // First, migrate.
         {
-            final OwnersSub owners = new OwnersSub();
+            final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
 
-            createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test04/input.xml"));
+            createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
+                    readAsset("OwnersTest/test04/input.xml"));
 
             owners.load();
 
@@ -327,7 +281,7 @@
 
         // Then re-read and check.
         {
-            final OwnersSub owners = new OwnersSub();
+            final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
             owners.load();
 
             assertTrue(owners.hasDeviceOwner());
@@ -359,9 +313,10 @@
 
         // First, migrate.
         {
-            final OwnersSub owners = new OwnersSub();
+            final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
 
-            createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test05/input.xml"));
+            createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
+                    readAsset("OwnersTest/test05/input.xml"));
 
             owners.load();
 
@@ -386,7 +341,7 @@
 
         // Then re-read and check.
         {
-            final OwnersSub owners = new OwnersSub();
+            final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
             owners.load();
 
             assertFalse(owners.hasDeviceOwner());
@@ -405,9 +360,10 @@
 
         // First, migrate.
         {
-            final OwnersSub owners = new OwnersSub();
+            final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
 
-            createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test06/input.xml"));
+            createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
+                    readAsset("OwnersTest/test06/input.xml"));
 
             owners.load();
 
@@ -431,7 +387,7 @@
 
         // Then re-read and check.
         {
-            final OwnersSub owners = new OwnersSub();
+            final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
             owners.load();
 
             assertFalse(owners.hasDeviceOwner());
@@ -447,10 +403,11 @@
     public void testRemoveExistingFiles() throws Exception {
         addUsersToUserManager(10, 11, 20, 21);
 
-        final OwnersSub owners = new OwnersSub();
+        final OwnersTestable owners = new OwnersTestable(getContext(), dataDir);
 
         // First, migrate to create new-style config files.
-        createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test04/input.xml"));
+        createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
+                readAsset("OwnersTest/test04/input.xml"));
 
         owners.load();