/* * 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.app.backup.IBackupManager; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.UserInfo; import android.media.IAudioService; import android.net.wifi.WifiManager; 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.os.UserManagerInternal; import android.telephony.TelephonyManager; import android.test.mock.MockContentResolver; import android.test.mock.MockContext; import android.view.IWindowManager; import org.junit.Assert; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import java.io.File; import java.util.ArrayList; import java.util.List; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; /** * 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 corresponding to {@link #CALLER_USER_HANDLE}. */ public static final int CALLER_UID = UserHandle.getUid(CALLER_USER_HANDLE, 20123); /** * UID used when a caller is on the system user. */ public static final int CALLER_SYSTEM_USER_UID = 20321; /** * 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 { public int callingUid = CALLER_UID; public int callingPid = CALLER_PID; public long clearCallingIdentity() { final long token = (((long) callingUid) << 32) | (callingPid); callingUid = SYSTEM_UID; callingPid = SYSTEM_PID; return token; } public void restoreCallingIdentity(long token) { callingUid = (int) (token >> 32); callingPid = (int) token; } public int getCallingUid() { return callingUid; } public int getCallingPid() { return callingPid; } public UserHandle getCallingUserHandle() { return new UserHandle(UserHandle.getUserId(getCallingUid())); } public boolean isCallerUidMyUid() { return callingUid == SYSTEM_UID; } } 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 void reboot(String reason) { } } public static class SystemPropertiesForMock { public boolean getBoolean(String key, boolean def) { return false; } public long getLong(String key, long def) { return 0; } public String get(String key, String def) { return null; } public String get(String key) { return null; } public void set(String key, String value) { } } public static class UserManagerForMock { public boolean isSplitSystemUser() { return false; } } public static class SettingsForMock { public int settingsSecureGetIntForUser(String name, int def, int userHandle) { return 0; } public void settingsSecurePutIntForUser(String name, int value, int userHandle) { } public void settingsSecurePutStringForUser(String name, String value, int userHandle) { } public void settingsGlobalPutStringForUser(String name, String value, int userHandle) { } public void settingsSecurePutInt(String name, int value) { } public void settingsGlobalPutInt(String name, int value) { } public void settingsSecurePutString(String name, String value) { } public void settingsGlobalPutString(String name, String value) { } public int settingsGlobalGetInt(String name, int value) { return 0; } public void securityLogSetLoggingEnabledProperty(boolean enabled) { } public boolean securityLogGetLoggingEnabledProperty() { return false; } public boolean securityLogIsLoggingEnabled() { return false; } } public static class StorageManagerForMock { public boolean isFileBasedEncryptionEnabled() { return false; } public boolean isNonDefaultBlockEncrypted() { return false; } public boolean isEncrypted() { return false; } public boolean isEncryptable() { return false; } } 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 File dataDir; public final File systemUserDataDir; public final MockBinder binder; public final EnvironmentForMock environment; public final SystemPropertiesForMock systemProperties; public final UserManager userManager; public final UserManagerInternal userManagerInternal; public final PackageManagerInternal packageManagerInternal; public final UserManagerForMock userManagerForMock; public final PowerManagerForMock powerManager; public final PowerManagerInternal powerManagerInternal; public final NotificationManager notificationManager; public final IWindowManager iwindowManager; public final IActivityManager iactivityManager; public final IPackageManager ipackageManager; public final IBackupManager ibackupManager; public final IAudioService iaudioService; public final LockPatternUtils lockPatternUtils; public final StorageManagerForMock storageManager; public final WifiManager wifiManager; public final SettingsForMock settings; public final MockContentResolver contentResolver; public final TelephonyManager telephonyManager; /** Note this is a partial mock, not a real mock. */ public final PackageManager packageManager; public final List callerPermissions = new ArrayList<>(); private final ArrayList mUserInfos = new ArrayList<>(); public DpmMockContext(Context context, File dataDir) { realTestContext = context; this.dataDir = dataDir; DpmTestUtils.clearDir(dataDir); binder = new MockBinder(); environment = mock(EnvironmentForMock.class); systemProperties= mock(SystemPropertiesForMock.class); userManager = mock(UserManager.class); userManagerInternal = mock(UserManagerInternal.class); userManagerForMock = mock(UserManagerForMock.class); packageManagerInternal = mock(PackageManagerInternal.class); powerManager = mock(PowerManagerForMock.class); powerManagerInternal = mock(PowerManagerInternal.class); notificationManager = mock(NotificationManager.class); iwindowManager = mock(IWindowManager.class); iactivityManager = mock(IActivityManager.class); ipackageManager = mock(IPackageManager.class); ibackupManager = mock(IBackupManager.class); iaudioService = mock(IAudioService.class); lockPatternUtils = mock(LockPatternUtils.class); storageManager = mock(StorageManagerForMock.class); wifiManager = mock(WifiManager.class); settings = mock(SettingsForMock.class); telephonyManager = mock(TelephonyManager.class); // Package manager is huge, so we use a partial mock instead. packageManager = spy(context.getPackageManager()); spiedContext = mock(Context.class); contentResolver = new MockContentResolver(); // Add the system user systemUserDataDir = addUser(UserHandle.USER_SYSTEM, UserInfo.FLAG_PRIMARY); // System user is always running. setUserRunning(UserHandle.USER_SYSTEM, true); } public File addUser(int userId, int flags) { // Set up (default) UserInfo for CALLER_USER_HANDLE. final UserInfo uh = new UserInfo(userId, "user" + userId, flags); when(userManager.getUserInfo(eq(userId))).thenReturn(uh); mUserInfos.add(uh); when(userManager.getUsers()).thenReturn(mUserInfos); when(userManager.getUsers(anyBoolean())).thenReturn(mUserInfos); when(userManager.isUserRunning(eq(new UserHandle(userId)))).thenReturn(true); when(userManager.getUserInfo(anyInt())).thenAnswer( new Answer() { @Override public UserInfo answer(InvocationOnMock invocation) throws Throwable { final int userId = (int) invocation.getArguments()[0]; for (UserInfo ui : mUserInfos) { if (ui.id == userId) { return ui; } } return null; } } ); when(userManager.getProfiles(anyInt())).thenAnswer( new Answer>() { @Override public List answer(InvocationOnMock invocation) throws Throwable { final int userId = (int) invocation.getArguments()[0]; return getProfiles(userId); } } ); when(userManager.getProfileIdsWithDisabled(anyInt())).thenAnswer( new Answer() { @Override public int[] answer(InvocationOnMock invocation) throws Throwable { final int userId = (int) invocation.getArguments()[0]; List profiles = getProfiles(userId); int[] results = new int[profiles.size()]; for (int i = 0; i < results.length; i++) { results[i] = profiles.get(i).id; } return results; } } ); // Create a data directory. final File dir = new File(dataDir, "user" + userId); DpmTestUtils.clearDir(dir); when(environment.getUserSystemDirectory(eq(userId))).thenReturn(dir); return dir; } private List getProfiles(int userId) { final ArrayList ret = new ArrayList(); UserInfo parent = null; for (UserInfo ui : mUserInfos) { if (ui.id == userId) { parent = ui; break; } } if (parent == null) { return ret; } ret.add(parent); for (UserInfo ui : mUserInfos) { if (ui.id == userId) { continue; } if (ui.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID && ui.profileGroupId == parent.profileGroupId) { ret.add(ui); } } return ret; } /** * Add multiple users at once. They'll all have flag 0. */ public void addUsers(int... userIds) { for (int userId : userIds) { addUser(userId, 0); } } public void setUserRunning(int userId, boolean isRunning) { when(userManager.isUserRunning(MockUtils.checkUserHandle(userId))) .thenReturn(isRunning); } @Override public Object getSystemService(String name) { switch (name) { case Context.USER_SERVICE: return userManager; case Context.POWER_SERVICE: return powerManager; case Context.WIFI_SERVICE: return wifiManager; } throw new UnsupportedOperationException(); } @Override public String getSystemServiceName(Class serviceClass) { return realTestContext.getSystemServiceName(serviceClass); } @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) { if (binder.callingPid != SYSTEM_PID) { // Unless called as the system process, can only call if the target user is the // calling user. // (The actual check is more complex; we may need to change it later.) Assert.assertEquals(UserHandle.getUserId(binder.getCallingUid()), user.getIdentifier()); } 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); resultReceiver.onReceive(spiedContext, intent); } @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); } @Override public ContentResolver getContentResolver() { return contentResolver; } }