Merge "Add unit tests for LockSettingsService"

This commit is contained in:
Rubin Xu
2017-01-25 18:38:28 +00:00
committed by Android (Google) Code Review
13 changed files with 1422 additions and 116 deletions

View File

@@ -19,6 +19,8 @@ package android.service.gatekeeper;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
/**
* Response object for a GateKeeper verification request.
* @hide
@@ -35,12 +37,28 @@ public final class GateKeeperResponse implements Parcelable {
private byte[] mPayload;
private boolean mShouldReEnroll;
/** Default constructor for response with generic response code **/
private GateKeeperResponse(int responseCode) {
mResponseCode = responseCode;
}
private GateKeeperResponse(int responseCode, int timeout) {
mResponseCode = responseCode;
@VisibleForTesting
public static GateKeeperResponse createGenericResponse(int responseCode) {
return new GateKeeperResponse(responseCode);
}
private static GateKeeperResponse createRetryResponse(int timeout) {
GateKeeperResponse response = new GateKeeperResponse(RESPONSE_RETRY);
response.mTimeout = timeout;
return response;
}
@VisibleForTesting
public static GateKeeperResponse createOkResponse(byte[] payload, boolean shouldReEnroll) {
GateKeeperResponse response = new GateKeeperResponse(RESPONSE_OK);
response.mPayload = payload;
response.mShouldReEnroll = shouldReEnroll;
return response;
}
@Override
@@ -53,17 +71,20 @@ public final class GateKeeperResponse implements Parcelable {
@Override
public GateKeeperResponse createFromParcel(Parcel source) {
int responseCode = source.readInt();
GateKeeperResponse response = new GateKeeperResponse(responseCode);
final GateKeeperResponse response;
if (responseCode == RESPONSE_RETRY) {
response.setTimeout(source.readInt());
response = createRetryResponse(source.readInt());
} else if (responseCode == RESPONSE_OK) {
response.setShouldReEnroll(source.readInt() == 1);
final boolean shouldReEnroll = source.readInt() == 1;
byte[] payload = null;
int size = source.readInt();
if (size > 0) {
byte[] payload = new byte[size];
payload = new byte[size];
source.readByteArray(payload);
response.setPayload(payload);
}
response = createOkResponse(payload, shouldReEnroll);
} else {
response = createGenericResponse(responseCode);
}
return response;
}
@@ -104,17 +125,4 @@ public final class GateKeeperResponse implements Parcelable {
public int getResponseCode() {
return mResponseCode;
}
private void setTimeout(int timeout) {
mTimeout = timeout;
}
private void setShouldReEnroll(boolean shouldReEnroll) {
mShouldReEnroll = shouldReEnroll;
}
private void setPayload(byte[] payload) {
mPayload = payload;
}
}

View File

@@ -43,6 +43,7 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.SparseIntArray;
import com.android.internal.annotations.VisibleForTesting;
import com.google.android.collect.Lists;
import libcore.util.HexEncoding;
@@ -239,7 +240,8 @@ public class LockPatternUtils {
mHandler = looper != null ? new Handler(looper) : null;
}
private ILockSettings getLockSettings() {
@VisibleForTesting
public ILockSettings getLockSettings() {
if (mLockSettingsService == null) {
ILockSettings service = ILockSettings.Stub.asInterface(
ServiceManager.getService("lock_settings"));

View File

@@ -23,6 +23,7 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -70,6 +71,7 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.ICheckCredentialProgressCallback;
import com.android.internal.widget.ILockSettings;
@@ -123,20 +125,23 @@ public class LockSettingsService extends ILockSettings.Stub {
private final Object mSeparateChallengeLock = new Object();
private final Injector mInjector;
private final Context mContext;
private final Handler mHandler;
private final LockSettingsStorage mStorage;
@VisibleForTesting
protected final LockSettingsStorage mStorage;
private final LockSettingsStrongAuth mStrongAuth;
private final SynchronizedStrongAuthTracker mStrongAuthTracker;
private LockPatternUtils mLockPatternUtils;
private final LockPatternUtils mLockPatternUtils;
private final NotificationManager mNotificationManager;
private final UserManager mUserManager;
private final IActivityManager mActivityManager;
private final KeyStore mKeyStore;
private boolean mFirstCallToVold;
private IGateKeeperService mGateKeeperService;
private NotificationManager mNotificationManager;
private UserManager mUserManager;
private final KeyStore mKeyStore = KeyStore.getInstance();
protected IGateKeeperService mGateKeeperService;
/**
* The UIDs that are used for system credential storage in keystore.
*/
@@ -177,7 +182,9 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
private class SynchronizedStrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
@VisibleForTesting
protected static class SynchronizedStrongAuthTracker
extends LockPatternUtils.StrongAuthTracker {
public SynchronizedStrongAuthTracker(Context context) {
super(context);
}
@@ -196,8 +203,8 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
void register() {
mStrongAuth.registerStrongAuthTracker(this.mStub);
void register(LockSettingsStrongAuth strongAuth) {
strongAuth.registerStrongAuthTracker(this.mStub);
}
}
@@ -211,7 +218,7 @@ public class LockSettingsService extends ILockSettings.Stub {
public void tieManagedProfileLockIfNecessary(int managedUserId, String managedUserPassword) {
if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + managedUserId);
// Only for managed profile
if (!UserManager.get(mContext).getUserInfo(managedUserId).isManagedProfile()) {
if (!mUserManager.getUserInfo(managedUserId).isManagedProfile()) {
return;
}
// Do not tie managed profile when work challenge is enabled
@@ -258,38 +265,103 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
public LockSettingsService(Context context) {
mContext = context;
mHandler = new Handler();
mStrongAuth = new LockSettingsStrongAuth(context);
// Open the database
static class Injector {
mLockPatternUtils = new LockPatternUtils(context);
protected Context mContext;
public Injector(Context context) {
mContext = context;
}
public Context getContext() {
return mContext;
}
public Handler getHandler() {
return new Handler();
}
public LockSettingsStorage getStorage() {
final LockSettingsStorage storage = new LockSettingsStorage(mContext);
storage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() {
@Override
public void initialize(SQLiteDatabase db) {
// Get the lockscreen default from a system property, if available
boolean lockScreenDisable = SystemProperties.getBoolean(
"ro.lockscreen.disable.default", false);
if (lockScreenDisable) {
storage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
}
}
});
return storage;
}
public LockSettingsStrongAuth getStrongAuth() {
return new LockSettingsStrongAuth(mContext);
}
public SynchronizedStrongAuthTracker getStrongAuthTracker() {
return new SynchronizedStrongAuthTracker(mContext);
}
public IActivityManager getActivityManager() {
return ActivityManager.getService();
}
public LockPatternUtils getLockPatternUtils() {
return new LockPatternUtils(mContext);
}
public NotificationManager getNotificationManager() {
return (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
}
public UserManager getUserManager() {
return (UserManager) mContext.getSystemService(Context.USER_SERVICE);
}
public KeyStore getKeyStore() {
return KeyStore.getInstance();
}
public IStorageManager getStorageManager() {
final IBinder service = ServiceManager.getService("mount");
if (service != null) {
return IStorageManager.Stub.asInterface(service);
}
return null;
}
}
public LockSettingsService(Context context) {
this(new Injector(context));
}
@VisibleForTesting
protected LockSettingsService(Injector injector) {
mInjector = injector;
mContext = injector.getContext();
mKeyStore = injector.getKeyStore();
mHandler = injector.getHandler();
mStrongAuth = injector.getStrongAuth();
mActivityManager = injector.getActivityManager();
mLockPatternUtils = injector.getLockPatternUtils();
mFirstCallToVold = true;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_STARTING);
filter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
@Override
public void initialize(SQLiteDatabase db) {
// Get the lockscreen default from a system property, if available
boolean lockScreenDisable = SystemProperties.getBoolean(
"ro.lockscreen.disable.default", false);
if (lockScreenDisable) {
mStorage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
}
}
});
mNotificationManager = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
mStrongAuthTracker = new SynchronizedStrongAuthTracker(mContext);
mStrongAuthTracker.register();
injector.getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter,
null, null);
mStorage = injector.getStorage();
mNotificationManager = injector.getNotificationManager();
mUserManager = injector.getUserManager();
mStrongAuthTracker = injector.getStrongAuthTracker();
mStrongAuthTracker.register(mStrongAuth);
}
/**
@@ -748,7 +820,8 @@ public class LockSettingsService extends ILockSettings.Stub {
ks.unlock(userHandle, password);
}
private String getDecryptedPasswordForTiedProfile(int userId)
@VisibleForTesting
protected String getDecryptedPasswordForTiedProfile(int userId)
throws KeyStoreException, UnrecoverableKeyException,
NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
@@ -814,7 +887,7 @@ public class LockSettingsService extends ILockSettings.Stub {
};
try {
ActivityManager.getService().unlockUser(userId, token, secret, listener);
mActivityManager.unlockUser(userId, token, secret, listener);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -961,7 +1034,8 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
private void tieProfileLockToParent(int userId, String password) {
@VisibleForTesting
protected void tieProfileLockToParent(int userId, String password) {
if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId);
byte[] randomLockSeed = password.getBytes(StandardCharsets.UTF_8);
byte[] encryptionResult;
@@ -1085,8 +1159,8 @@ public class LockSettingsService extends ILockSettings.Stub {
private void addUserKeyAuth(int userId, byte[] token, byte[] secret)
throws RemoteException {
final UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
final IStorageManager storageManager = getStorageManager();
final UserInfo userInfo = mUserManager.getUserInfo(userId);
final IStorageManager storageManager = mInjector.getStorageManager();
final long callingId = Binder.clearCallingIdentity();
try {
storageManager.addUserKeyAuth(userId, userInfo.serialNumber, token, secret);
@@ -1097,7 +1171,7 @@ public class LockSettingsService extends ILockSettings.Stub {
private void fixateNewestUserKeyAuth(int userId)
throws RemoteException {
final IStorageManager storageManager = getStorageManager();
final IStorageManager storageManager = mInjector.getStorageManager();
final long callingId = Binder.clearCallingIdentity();
try {
storageManager.fixateNewestUserKeyAuth(userId);
@@ -1396,7 +1470,7 @@ public class LockSettingsService extends ILockSettings.Stub {
// we should, within the first minute of decrypting the phone if this
// service can't connect to vold, it restarts, and then the new instance
// does successfully connect.
final IStorageManager service = getStorageManager();
final IStorageManager service = mInjector.getStorageManager();
String password;
long identity = Binder.clearCallingIdentity();
try {
@@ -1561,14 +1635,6 @@ public class LockSettingsService extends ILockSettings.Stub {
Secure.LOCK_SCREEN_OWNER_INFO
};
private IStorageManager getStorageManager() {
final IBinder service = ServiceManager.getService("mount");
if (service != null) {
return IStorageManager.Stub.asInterface(service);
}
return null;
}
private class GateKeeperDiedRecipient implements IBinder.DeathRecipient {
@Override
public void binderDied() {

View File

@@ -77,7 +77,8 @@ class LockSettingsShellCommand extends ShellCommand {
}
return 0;
} catch (Exception e) {
getErrPrintWriter().println("Error while executing command: " + e);
getErrPrintWriter().println("Error while executing command: " + cmd);
e.printStackTrace(getErrPrintWriter());
return -1;
}
}

View File

@@ -119,9 +119,13 @@ class LockSettingsStorage {
boolean isBaseZeroPattern;
}
public LockSettingsStorage(Context context, Callback callback) {
public LockSettingsStorage(Context context) {
mContext = context;
mOpenHelper = new DatabaseHelper(context, callback);
mOpenHelper = new DatabaseHelper(context);
}
public void setDatabaseOnCreateCallback(Callback callback) {
mOpenHelper.setCallback(callback);
}
public void writeKeyValue(String key, String value, int userId) {
@@ -472,11 +476,14 @@ class LockSettingsStorage {
private static final int DATABASE_VERSION = 2;
private final Callback mCallback;
private Callback mCallback;
public DatabaseHelper(Context context, Callback callback) {
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
setWriteAheadLoggingEnabled(true);
}
public void setCallback(Callback callback) {
mCallback = callback;
}
@@ -492,7 +499,9 @@ class LockSettingsStorage {
@Override
public void onCreate(SQLiteDatabase db) {
createTable(db);
mCallback.initialize(db);
if (mCallback != null) {
mCallback.initialize(db);
}
}
@Override

View File

@@ -0,0 +1,138 @@
/*
* Copyright (C) 2016 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;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.IActivityManager;
import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.UserInfo;
import android.database.sqlite.SQLiteDatabase;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IProgressListener;
import android.os.RemoteException;
import android.os.UserManager;
import android.os.storage.IStorageManager;
import android.security.KeyStore;
import android.service.gatekeeper.GateKeeperResponse;
import android.service.gatekeeper.IGateKeeperService;
import android.test.AndroidTestCase;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.VerifyCredentialResponse;
import com.android.server.LockSettingsService.SynchronizedStrongAuthTracker;
import com.android.server.LockSettingsStorage.CredentialHash;
import com.android.server.MockGateKeeperService.AuthToken;
import com.android.server.MockGateKeeperService.VerifyHandle;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.io.File;
import java.util.Arrays;
public class BaseLockSettingsServiceTests extends AndroidTestCase {
protected static final int PRIMARY_USER_ID = 0;
protected static final int MANAGED_PROFILE_USER_ID = 12;
protected static final int SECONDARY_USER_ID = 20;
private static final UserInfo PRIMARY_USER_INFO = new UserInfo(PRIMARY_USER_ID, null, null,
UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
private static final UserInfo MANAGED_PROFILE_INFO = new UserInfo(MANAGED_PROFILE_USER_ID, null,
null, UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_MANAGED_PROFILE);
private static final UserInfo SECONDARY_USER_INFO = new UserInfo(SECONDARY_USER_ID, null, null,
UserInfo.FLAG_INITIALIZED);
LockSettingsService mService;
MockLockSettingsContext mContext;
LockSettingsStorageTestable mStorage;
LockPatternUtils mLockPatternUtils;
MockGateKeeperService mGateKeeperService;
NotificationManager mNotificationManager;
UserManager mUserManager;
MockStorageManager mStorageManager;
IActivityManager mActivityManager;
KeyStore mKeyStore;
@Override
protected void setUp() throws Exception {
super.setUp();
mLockPatternUtils = mock(LockPatternUtils.class);
mGateKeeperService = new MockGateKeeperService();
mNotificationManager = mock(NotificationManager.class);
mUserManager = mock(UserManager.class);
mStorageManager = new MockStorageManager();
mActivityManager = mock(IActivityManager.class);
mContext = new MockLockSettingsContext(getContext(), mUserManager, mNotificationManager);
mStorage = new LockSettingsStorageTestable(mContext,
new File(getContext().getFilesDir(), "locksettings"));
File storageDir = mStorage.mStorageDir;
if (storageDir.exists()) {
FileUtils.deleteContents(storageDir);
} else {
storageDir.mkdirs();
}
mService = new LockSettingsServiceTestable(mContext, mLockPatternUtils,
mStorage, mGateKeeperService, mKeyStore, mStorageManager, mActivityManager);
when(mUserManager.getUserInfo(eq(PRIMARY_USER_ID))).thenReturn(PRIMARY_USER_INFO);
when(mUserManager.getProfiles(eq(PRIMARY_USER_ID))).thenReturn(Arrays.asList(
new UserInfo[] {PRIMARY_USER_INFO, MANAGED_PROFILE_INFO}));
when(mUserManager.getUserInfo(eq(MANAGED_PROFILE_USER_ID))).thenReturn(
MANAGED_PROFILE_INFO);
when(mUserManager.getProfileParent(eq(MANAGED_PROFILE_USER_ID))).thenReturn(
PRIMARY_USER_INFO);
when(mUserManager.getUserInfo(eq(SECONDARY_USER_ID))).thenReturn(SECONDARY_USER_INFO);
when(mActivityManager.unlockUser(anyInt(), any(), any(), any())).thenAnswer(
new Answer<Boolean>() {
@Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
mStorageManager.unlockUser((int)args[0], (byte[])args[2],
(IProgressListener) args[3]);
return true;
}
});
when(mLockPatternUtils.getLockSettings()).thenReturn(mService);
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
mStorage.closeDatabase();
File db = getContext().getDatabasePath("locksettings.db");
assertTrue(!db.exists() || db.delete());
File storageDir = mStorage.mStorageDir;
assertTrue(FileUtils.deleteContents(storageDir));
}
}

View File

@@ -0,0 +1,116 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.server;
import static org.mockito.Mockito.mock;
import android.app.IActivityManager;
import android.content.Context;
import android.os.Handler;
import android.os.storage.IStorageManager;
import android.security.KeyStore;
import android.service.gatekeeper.IGateKeeperService;
import com.android.internal.widget.LockPatternUtils;
import java.io.FileNotFoundException;
public class LockSettingsServiceTestable extends LockSettingsService {
private static class MockInjector extends LockSettingsService.Injector {
private LockSettingsStorage mLockSettingsStorage;
private KeyStore mKeyStore;
private IActivityManager mActivityManager;
private LockPatternUtils mLockPatternUtils;
private IStorageManager mStorageManager;
public MockInjector(Context context, LockSettingsStorage storage, KeyStore keyStore,
IActivityManager activityManager, LockPatternUtils lockPatternUtils,
IStorageManager storageManager) {
super(context);
mLockSettingsStorage = storage;
mKeyStore = keyStore;
mActivityManager = activityManager;
mLockPatternUtils = lockPatternUtils;
mStorageManager = storageManager;
}
@Override
public Handler getHandler() {
return mock(Handler.class);
}
@Override
public LockSettingsStorage getStorage() {
return mLockSettingsStorage;
}
@Override
public LockSettingsStrongAuth getStrongAuth() {
return mock(LockSettingsStrongAuth.class);
}
@Override
public SynchronizedStrongAuthTracker getStrongAuthTracker() {
return mock(SynchronizedStrongAuthTracker.class);
}
@Override
public IActivityManager getActivityManager() {
return mActivityManager;
}
@Override
public LockPatternUtils getLockPatternUtils() {
return mLockPatternUtils;
}
@Override
public KeyStore getKeyStore() {
return mKeyStore;
}
@Override
public IStorageManager getStorageManager() {
return mStorageManager;
}
}
protected LockSettingsServiceTestable(Context context, LockPatternUtils lockPatternUtils,
LockSettingsStorage storage, IGateKeeperService gatekeeper, KeyStore keystore,
IStorageManager storageManager, IActivityManager mActivityManager) {
super(new MockInjector(context, storage, keystore, mActivityManager, lockPatternUtils,
storageManager));
mGateKeeperService = gatekeeper;
}
@Override
protected void tieProfileLockToParent(int userId, String password) {
mStorage.writeChildProfileLock(userId, password.getBytes());
}
@Override
protected String getDecryptedPasswordForTiedProfile(int userId) throws FileNotFoundException {
byte[] storedData = mStorage.readChildProfileLock(userId);
if (storedData == null) {
throw new FileNotFoundException("Child profile lock file not found");
}
return new String(storedData);
}
}

View File

@@ -0,0 +1,228 @@
/*
* Copyright (C) 2016 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;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
import android.os.RemoteException;
import android.service.gatekeeper.GateKeeperResponse;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.VerifyCredentialResponse;
import com.android.server.LockSettingsStorage.CredentialHash;
import com.android.server.MockGateKeeperService.VerifyHandle;
/**
* runtest frameworks-services -c com.android.server.LockSettingsServiceTests
*/
public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
@Override
protected void setUp() throws Exception {
super.setUp();
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
}
public void testCreatePasswordPrimaryUser() throws RemoteException {
testCreateCredential(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD);
}
public void testCreatePatternPrimaryUser() throws RemoteException {
testCreateCredential(PRIMARY_USER_ID, "123456789", CREDENTIAL_TYPE_PATTERN);
}
public void testChangePasswordPrimaryUser() throws RemoteException {
testChangeCredentials(PRIMARY_USER_ID, "78963214", CREDENTIAL_TYPE_PATTERN,
"asdfghjk", CREDENTIAL_TYPE_PASSWORD);
}
public void testChangePatternPrimaryUser() throws RemoteException {
testChangeCredentials(PRIMARY_USER_ID, "!£$%^&*(())", CREDENTIAL_TYPE_PASSWORD,
"1596321", CREDENTIAL_TYPE_PATTERN);
}
public void testChangePasswordFailPrimaryUser() throws RemoteException {
final long sid = 1234;
final String FAILED_MESSAGE = "Failed to enroll password";
initializeStorageWithCredential(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD, sid);
try {
mService.setLockCredential("newpwd", CREDENTIAL_TYPE_PASSWORD, "badpwd",
PRIMARY_USER_ID);
fail("Did not fail when enrolling using incorrect credential");
} catch (RemoteException expected) {
assertTrue(expected.getMessage().equals(FAILED_MESSAGE));
}
try {
mService.setLockCredential("newpwd", CREDENTIAL_TYPE_PASSWORD, null, PRIMARY_USER_ID);
fail("Did not fail when enrolling using incorrect credential");
} catch (RemoteException expected) {
assertTrue(expected.getMessage().equals(FAILED_MESSAGE));
}
assertVerifyCredentials(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD, sid);
}
public void testClearPasswordPrimaryUser() throws RemoteException {
final String PASSWORD = "password";
initializeStorageWithCredential(PRIMARY_USER_ID, PASSWORD, CREDENTIAL_TYPE_PASSWORD, 1234);
mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, PASSWORD, PRIMARY_USER_ID);
assertFalse(mService.havePassword(PRIMARY_USER_ID));
assertFalse(mService.havePattern(PRIMARY_USER_ID));
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
}
public void testManagedProfileUnifiedChallenge() throws RemoteException {
final String UnifiedPassword = "testManagedProfileUnifiedChallenge-pwd";
mService.setLockCredential(UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PRIMARY_USER_ID);
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
assertTrue(primarySid != 0);
assertTrue(profileSid != 0);
assertTrue(profileSid != primarySid);
// clear auth token and wait for verify challenge from primary user to re-generate it.
mGateKeeperService.clearAuthToken(MANAGED_PROFILE_USER_ID);
// verify credential
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
// Verify that we have a new auth token for the profile
assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
/* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new
* credential as part of verifyCredential() before the new credential is committed in
* StorageManager. So we relax the check in our mock StorageManager to allow that.
*/
mStorageManager.setIgnoreBadUnlock(true);
// Change primary password and verify that profile SID remains
mService.setLockCredential("pwd", LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
UnifiedPassword, PRIMARY_USER_ID);
mStorageManager.setIgnoreBadUnlock(false);
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
}
public void testManagedProfileSeparateChallenge() throws RemoteException {
final String primaryPassword = "testManagedProfileSeparateChallenge-primary";
final String profilePassword = "testManagedProfileSeparateChallenge-profile";
mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PRIMARY_USER_ID);
/* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new
* credential as part of verifyCredential() before the new credential is committed in
* StorageManager. So we relax the check in our mock StorageManager to allow that.
*/
mStorageManager.setIgnoreBadUnlock(true);
mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
MANAGED_PROFILE_USER_ID);
mStorageManager.setIgnoreBadUnlock(false);
final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
assertTrue(primarySid != 0);
assertTrue(profileSid != 0);
assertTrue(profileSid != primarySid);
// clear auth token and make sure verify challenge from primary user does not regenerate it.
mGateKeeperService.clearAuthToken(MANAGED_PROFILE_USER_ID);
// verify primary credential
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
assertNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
// verify profile credential
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
MANAGED_PROFILE_USER_ID).getResponseCode());
assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
// Change primary credential and make sure we don't affect profile
mStorageManager.setIgnoreBadUnlock(true);
mService.setLockCredential("pwd", LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
primaryPassword, PRIMARY_USER_ID);
mStorageManager.setIgnoreBadUnlock(false);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
MANAGED_PROFILE_USER_ID).getResponseCode());
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
}
private void testCreateCredential(int userId, String credential, int type)
throws RemoteException {
mService.setLockCredential(credential, type, null, userId);
assertVerifyCredentials(userId, credential, type, -1);
}
private void testChangeCredentials(int userId, String newCredential, int newType,
String oldCredential, int oldType) throws RemoteException {
final long sid = 1234;
initializeStorageWithCredential(userId, oldCredential, oldType, sid);
mService.setLockCredential(newCredential, newType, oldCredential, userId);
assertVerifyCredentials(userId, newCredential, newType, sid);
}
private void assertVerifyCredentials(int userId, String credential, int type, long sid)
throws RemoteException{
final long challenge = 54321;
VerifyCredentialResponse response = mService.verifyCredential(credential, type, challenge,
userId);
assertEquals(GateKeeperResponse.RESPONSE_OK, response.getResponseCode());
if (sid != -1) assertEquals(sid, mGateKeeperService.getSecureUserId(userId));
final int incorrectType;
if (type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) {
assertTrue(mService.havePassword(userId));
assertFalse(mService.havePattern(userId));
incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
} else if (type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN){
assertFalse(mService.havePassword(userId));
assertTrue(mService.havePattern(userId));
incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
} else {
assertFalse(mService.havePassword(userId));
assertFalse(mService.havePassword(userId));
incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
}
// check for bad type
assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential(credential,
incorrectType, challenge, userId).getResponseCode());
// check for bad credential
assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential("0" + credential,
type, challenge, userId).getResponseCode());
}
private void initializeStorageWithCredential(int userId, String credential, int type, long sid) {
byte[] oldHash = new VerifyHandle(credential.getBytes(), sid).toBytes();
if (type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) {
mStorage.writeCredentialHash(CredentialHash.create(oldHash,
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD), userId);
} else {
mStorage.writeCredentialHash(CredentialHash.create(oldHash,
LockPatternUtils.CREDENTIAL_TYPE_PATTERN), userId);
}
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.server;
import android.content.Context;
import java.io.File;
public class LockSettingsStorageTestable extends LockSettingsStorage {
public File mStorageDir;
public LockSettingsStorageTestable(Context context, File storageDir) {
super(context);
mStorageDir = storageDir;
}
@Override
String getLockPatternFilename(int userId) {
return new File(mStorageDir,
super.getLockPatternFilename(userId).replace('/', '-')).getAbsolutePath();
}
@Override
String getLockPasswordFilename(int userId) {
return new File(mStorageDir,
super.getLockPasswordFilename(userId).replace('/', '-')).getAbsolutePath();
}
@Override
String getChildProfileLockFile(int userId) {
return new File(mStorageDir,
super.getChildProfileLockFile(userId).replace('/', '-')).getAbsolutePath();
}
}

View File

@@ -20,6 +20,7 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.app.NotificationManager;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.UserInfo;
@@ -60,46 +61,22 @@ public class LockSettingsStorageTests extends AndroidTestCase {
assertTrue(FileUtils.deleteContents(mStorageDir));
assertTrue(!mDb.exists() || mDb.delete());
final Context ctx = getContext();
final UserManager mockUserManager = mock(UserManager.class);
// User 2 is a profile of user 1.
when(mockUserManager.getProfileParent(eq(2))).thenReturn(new UserInfo(1, "name", 0));
// User 3 is a profile of user 0.
when(mockUserManager.getProfileParent(eq(3))).thenReturn(new UserInfo(0, "name", 0));
setContext(new ContextWrapper(ctx) {
@Override
public Object getSystemService(String name) {
if (USER_SERVICE.equals(name)) {
return mockUserManager;
}
return super.getSystemService(name);
}
});
mStorage = new LockSettingsStorage(getContext(), new LockSettingsStorage.Callback() {
@Override
public void initialize(SQLiteDatabase db) {
mStorage.writeKeyValue(db, "initializedKey", "initialValue", 0);
}
}) {
@Override
String getLockPatternFilename(int userId) {
return new File(mStorageDir,
super.getLockPatternFilename(userId).replace('/', '-')).getAbsolutePath();
}
@Override
String getLockPasswordFilename(int userId) {
return new File(mStorageDir,
super.getLockPasswordFilename(userId).replace('/', '-')).getAbsolutePath();
}
@Override
String getChildProfileLockFile(int userId) {
return new File(mStorageDir,
super.getChildProfileLockFile(userId).replace('/', '-')).getAbsolutePath();
}
};
MockLockSettingsContext context = new MockLockSettingsContext(getContext(), mockUserManager,
mock(NotificationManager.class));
mStorage = new LockSettingsStorageTestable(context,
new File(getContext().getFilesDir(), "locksettings"));
mStorage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() {
@Override
public void initialize(SQLiteDatabase db) {
mStorage.writeKeyValue(db, "initializedKey", "initialValue", 0);
}
});
}
@Override
@@ -323,7 +300,7 @@ public class LockSettingsStorageTests extends AndroidTestCase {
}
public void testFileLocation_Owner() {
LockSettingsStorage storage = new LockSettingsStorage(getContext(), null);
LockSettingsStorage storage = new LockSettingsStorage(getContext());
assertEquals("/data/system/gesture.key", storage.getLegacyLockPatternFilename(0));
assertEquals("/data/system/password.key", storage.getLegacyLockPasswordFilename(0));
@@ -332,21 +309,21 @@ public class LockSettingsStorageTests extends AndroidTestCase {
}
public void testFileLocation_SecondaryUser() {
LockSettingsStorage storage = new LockSettingsStorage(getContext(), null);
LockSettingsStorage storage = new LockSettingsStorage(getContext());
assertEquals("/data/system/users/1/gatekeeper.pattern.key", storage.getLockPatternFilename(1));
assertEquals("/data/system/users/1/gatekeeper.password.key", storage.getLockPasswordFilename(1));
}
public void testFileLocation_ProfileToSecondary() {
LockSettingsStorage storage = new LockSettingsStorage(getContext(), null);
LockSettingsStorage storage = new LockSettingsStorage(getContext());
assertEquals("/data/system/users/2/gatekeeper.pattern.key", storage.getLockPatternFilename(2));
assertEquals("/data/system/users/2/gatekeeper.password.key", storage.getLockPasswordFilename(2));
}
public void testFileLocation_ProfileToOwner() {
LockSettingsStorage storage = new LockSettingsStorage(getContext(), null);
LockSettingsStorage storage = new LockSettingsStorage(getContext());
assertEquals("/data/system/users/3/gatekeeper.pattern.key", storage.getLockPatternFilename(3));
assertEquals("/data/system/users/3/gatekeeper.password.key", storage.getLockPasswordFilename(3));

View File

@@ -0,0 +1,185 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.server;
import android.os.IBinder;
import android.os.RemoteException;
import android.service.gatekeeper.GateKeeperResponse;
import android.service.gatekeeper.IGateKeeperService;
import android.util.ArrayMap;
import junit.framework.AssertionFailedError;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Random;
public class MockGateKeeperService implements IGateKeeperService {
static class VerifyHandle {
public byte[] password;
public long sid;
public VerifyHandle(byte[] password, long sid) {
this.password = password;
this.sid = sid;
}
public VerifyHandle(byte[] handle) {
ByteBuffer buffer = ByteBuffer.allocate(handle.length);
buffer.put(handle, 0, handle.length);
buffer.flip();
int version = buffer.get();
sid = buffer.getLong();
password = new byte[buffer.remaining()];
buffer.get(password);
}
public byte[] toBytes() {
ByteBuffer buffer = ByteBuffer.allocate(1 + Long.BYTES + password.length);
buffer.put((byte)0);
buffer.putLong(sid);
buffer.put(password);
return buffer.array();
}
}
static class AuthToken {
public long challenge;
public long sid;
public AuthToken(long challenge, long sid) {
this.challenge = challenge;
this.sid = sid;
}
public AuthToken(byte[] handle) {
ByteBuffer buffer = ByteBuffer.allocate(handle.length);
buffer.put(handle, 0, handle.length);
buffer.flip();
int version = buffer.get();
challenge = buffer.getLong();
sid = buffer.getLong();
}
public byte[] toBytes() {
ByteBuffer buffer = ByteBuffer.allocate(1 + Long.BYTES + Long.BYTES);
buffer.put((byte)0);
buffer.putLong(challenge);
buffer.putLong(sid);
return buffer.array();
}
}
private ArrayMap<Integer, Long> sidMap = new ArrayMap<>();
private ArrayMap<Integer, AuthToken> authTokenMap = new ArrayMap<>();
private ArrayMap<Integer, byte[]> handleMap = new ArrayMap<>();
@Override
public GateKeeperResponse enroll(int uid, byte[] currentPasswordHandle, byte[] currentPassword,
byte[] desiredPassword) throws android.os.RemoteException {
if (currentPasswordHandle != null) {
VerifyHandle handle = new VerifyHandle(currentPasswordHandle);
if (Arrays.equals(currentPassword, handle.password)) {
// Trusted enroll
VerifyHandle newHandle = new VerifyHandle(desiredPassword, handle.sid);
refreshSid(uid, handle.sid, false);
handleMap.put(uid, newHandle.toBytes());
return GateKeeperResponse.createOkResponse(newHandle.toBytes(), false);
} else {
return null;
}
} else {
// Untrusted enroll
long newSid = new Random().nextLong();
VerifyHandle newHandle = new VerifyHandle(desiredPassword, newSid);
refreshSid(uid, newSid, true);
handleMap.put(uid, newHandle.toBytes());
return GateKeeperResponse.createOkResponse(newHandle.toBytes(), false);
}
}
@Override
public GateKeeperResponse verify(int uid, byte[] enrolledPasswordHandle,
byte[] providedPassword) throws android.os.RemoteException {
return verifyChallenge(uid, 0, enrolledPasswordHandle, providedPassword);
}
@Override
public GateKeeperResponse verifyChallenge(int uid, long challenge,
byte[] enrolledPasswordHandle, byte[] providedPassword) throws RemoteException {
VerifyHandle handle = new VerifyHandle(enrolledPasswordHandle);
if (Arrays.equals(handle.password, providedPassword)) {
byte[] knownHandle = handleMap.get(uid);
if (knownHandle != null) {
if (!Arrays.equals(knownHandle, enrolledPasswordHandle)) {
throw new AssertionFailedError("Got correct but obsolete handle");
}
}
refreshSid(uid, handle.sid, false);
AuthToken token = new AuthToken(challenge, handle.sid);
refreshAuthToken(uid, token);
return GateKeeperResponse.createOkResponse(token.toBytes(), false);
} else {
return GateKeeperResponse.createGenericResponse(GateKeeperResponse.RESPONSE_ERROR);
}
}
private void refreshAuthToken(int uid, AuthToken token) {
authTokenMap.put(uid, token);
}
public AuthToken getAuthToken(int uid) {
return authTokenMap.get(uid);
}
public void clearAuthToken(int uid) {
authTokenMap.remove(uid);
}
@Override
public IBinder asBinder() {
throw new UnsupportedOperationException();
}
@Override
public void clearSecureUserId(int userId) throws RemoteException {
sidMap.remove(userId);
}
@Override
public long getSecureUserId(int userId) throws RemoteException {
if (sidMap.containsKey(userId)) {
return sidMap.get(userId);
} else {
return 0L;
}
}
private void refreshSid(int uid, long sid, boolean force) {
if (!sidMap.containsKey(uid) || force) {
sidMap.put(uid, sid);
} else{
if (sidMap.get(uid) != sid) {
throw new AssertionFailedError("Inconsistent SID");
}
}
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.server;
import android.app.NotificationManager;
import android.content.Context;
import android.content.ContextWrapper;
import android.os.UserManager;
public class MockLockSettingsContext extends ContextWrapper {
private UserManager mUserManager;
private NotificationManager mNotificationManager;
public MockLockSettingsContext(Context base, UserManager userManager,
NotificationManager notificationManager) {
super(base);
mUserManager = userManager;
mNotificationManager = notificationManager;
}
@Override
public Object getSystemService(String name) {
if (USER_SERVICE.equals(name)) {
return mUserManager;
} else if (NOTIFICATION_SERVICE.equals(name)) {
return mNotificationManager;
} else {
throw new RuntimeException("System service not mocked: " + name);
}
}
@Override
public void enforceCallingOrSelfPermission(String permission, String message) {
// Skip permission checks for unit tests.
}
}

View File

@@ -0,0 +1,475 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.server;
import android.content.pm.IPackageMoveObserver;
import android.os.IBinder;
import android.os.IProgressListener;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.storage.DiskInfo;
import android.os.storage.IObbActionListener;
import android.os.storage.IStorageEventListener;
import android.os.storage.IStorageManager;
import android.os.storage.IStorageShutdownObserver;
import android.os.storage.StorageVolume;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
import android.util.ArrayMap;
import android.util.Pair;
import junit.framework.AssertionFailedError;
import java.util.ArrayList;
import java.util.Arrays;
public class MockStorageManager implements IStorageManager {
private ArrayMap<Integer, ArrayList<Pair<byte[], byte[]>>> mAuth = new ArrayMap<>();
private boolean mIgnoreBadUnlock;
@Override
public void addUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret)
throws RemoteException {
getUserAuth(userId).add(new Pair<>(token, secret));
}
@Override
public void fixateNewestUserKeyAuth(int userId) throws RemoteException {
ArrayList<Pair<byte[], byte[]>> auths = mAuth.get(userId);
Pair<byte[], byte[]> latest = auths.get(auths.size() - 1);
auths.clear();
auths.add(latest);
}
private ArrayList<Pair<byte[], byte[]>> getUserAuth(int userId) {
if (!mAuth.containsKey(userId)) {
ArrayList<Pair<byte[], byte[]>> auths = new ArrayList<Pair<byte[], byte[]>>();
auths.add(new Pair(null, null));
mAuth.put(userId, auths);
}
return mAuth.get(userId);
}
public byte[] getUserUnlockToken(int userId) {
ArrayList<Pair<byte[], byte[]>> auths = getUserAuth(userId);
if (auths.size() != 1) {
throw new AssertionFailedError("More than one secret exists");
}
return auths.get(0).second;
}
public void unlockUser(int userId, byte[] secret, IProgressListener listener)
throws RemoteException {
listener.onStarted(userId, null);
listener.onFinished(userId, null);
ArrayList<Pair<byte[], byte[]>> auths = getUserAuth(userId);
if (secret != null) {
if (auths.size() > 1) {
throw new AssertionFailedError("More than one secret exists");
}
Pair<byte[], byte[]> auth = auths.get(0);
if ((!mIgnoreBadUnlock) && auth.second != null && !Arrays.equals(secret, auth.second)) {
throw new AssertionFailedError("Invalid secret to unlock user");
}
} else {
if (auths != null && auths.size() > 0) {
throw new AssertionFailedError("Cannot unlock encrypted user with empty token");
}
}
}
public void setIgnoreBadUnlock(boolean ignore) {
mIgnoreBadUnlock = ignore;
}
@Override
public IBinder asBinder() {
throw new UnsupportedOperationException();
}
@Override
public void registerListener(IStorageEventListener listener) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void unregisterListener(IStorageEventListener listener) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public boolean isUsbMassStorageConnected() throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void setUsbMassStorageEnabled(boolean enable) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public boolean isUsbMassStorageEnabled() throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public int mountVolume(String mountPoint) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void unmountVolume(String mountPoint, boolean force, boolean removeEncryption)
throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public int formatVolume(String mountPoint) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public int[] getStorageUsers(String path) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public String getVolumeState(String mountPoint) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public int createSecureContainer(String id, int sizeMb, String fstype, String key, int ownerUid,
boolean external) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public int finalizeSecureContainer(String id) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public int destroySecureContainer(String id, boolean force) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly)
throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public int unmountSecureContainer(String id, boolean force) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public boolean isSecureContainerMounted(String id) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public int renameSecureContainer(String oldId, String newId) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public String getSecureContainerPath(String id) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public String[] getSecureContainerList() throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void shutdown(IStorageShutdownObserver observer) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void finishMediaUpdate() throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void mountObb(String rawPath, String canonicalPath, String key, IObbActionListener token,
int nonce) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce)
throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public boolean isObbMounted(String rawPath) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public String getMountedObbPath(String rawPath) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public boolean isExternalStorageEmulated() throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public int decryptStorage(String password) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public int encryptStorage(int type, String password) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public int changeEncryptionPassword(int type, String password) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public StorageVolume[] getVolumeList(int uid, String packageName, int flags)
throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public String getSecureContainerFilesystemPath(String cid) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public int getEncryptionState() throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public int verifyEncryptionPassword(String password) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public int fixPermissionsSecureContainer(String id, int gid, String filename)
throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public int mkdirs(String callingPkg, String path) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public int getPasswordType() throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public String getPassword() throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void clearPassword() throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void setField(String field, String contents) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public String getField(String field) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public int resizeSecureContainer(String id, int sizeMb, String key) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public long lastMaintenance() throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void runMaintenance() throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void waitForAsecScan() throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public DiskInfo[] getDisks() throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public VolumeInfo[] getVolumes(int flags) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public VolumeRecord[] getVolumeRecords(int flags) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void mount(String volId) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void unmount(String volId) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void format(String volId) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void partitionPublic(String diskId) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void partitionPrivate(String diskId) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void partitionMixed(String diskId, int ratio) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void setVolumeNickname(String fsUuid, String nickname) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void setVolumeUserFlags(String fsUuid, int flags, int mask) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void forgetVolume(String fsUuid) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void forgetAllVolumes() throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public String getPrimaryStorageUuid() throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)
throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public long benchmark(String volId) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void setDebugFlags(int flags, int mask) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void createUserKey(int userId, int serialNumber, boolean ephemeral)
throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void destroyUserKey(int userId) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret)
throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void lockUserKey(int userId) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public boolean isUserKeyUnlocked(int userId) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags)
throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void destroyUserStorage(String volumeUuid, int userId, int flags)
throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public boolean isConvertibleToFBE() throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public ParcelFileDescriptor mountAppFuse(String name) throws RemoteException {
throw new UnsupportedOperationException();
}
@Override
public void fstrim(int flags) throws RemoteException {
throw new UnsupportedOperationException();
}
}