Merge "Add unit tests for LockSettingsService"
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user