Define trust agent framework components
Adds the TrustManager system service that allows registering for changes to the trust status and reporting events that are important to trust agents. Bug: 13723878 Change-Id: I7d0d2ea86fd755702d31aa5d49cac038a6cd4301
This commit is contained in:
@@ -85,6 +85,8 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/app/IWallpaperManager.aidl \
|
||||
core/java/android/app/IWallpaperManagerCallback.aidl \
|
||||
core/java/android/app/admin/IDevicePolicyManager.aidl \
|
||||
core/java/android/app/trust/ITrustManager.aidl \
|
||||
core/java/android/app/trust/ITrustListener.aidl \
|
||||
core/java/android/app/backup/IBackupManager.aidl \
|
||||
core/java/android/app/backup/IFullBackupRestoreObserver.aidl \
|
||||
core/java/android/app/backup/IRestoreObserver.aidl \
|
||||
|
||||
@@ -119,6 +119,7 @@ import android.view.textservice.TextServicesManager;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.IAccountManager;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.trust.TrustManager;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.app.IAppOpsService;
|
||||
@@ -621,6 +622,12 @@ class ContextImpl extends Context {
|
||||
return new MediaSessionManager(ctx);
|
||||
}
|
||||
});
|
||||
registerService(TRUST_SERVICE, new ServiceFetcher() {
|
||||
public Object createService(ContextImpl ctx) {
|
||||
IBinder b = ServiceManager.getService(TRUST_SERVICE);
|
||||
return new TrustManager(b);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static ContextImpl getImpl(Context context) {
|
||||
|
||||
26
core/java/android/app/trust/ITrustListener.aidl
Normal file
26
core/java/android/app/trust/ITrustListener.aidl
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
**
|
||||
** Copyright 2014, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
package android.app.trust;
|
||||
|
||||
/**
|
||||
* Private API to be notified about trust changes.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
oneway interface ITrustListener {
|
||||
void onTrustChanged(boolean enabled, int userId);
|
||||
}
|
||||
31
core/java/android/app/trust/ITrustManager.aidl
Normal file
31
core/java/android/app/trust/ITrustManager.aidl
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
**
|
||||
** Copyright 2014, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
package android.app.trust;
|
||||
|
||||
import android.app.trust.ITrustListener;
|
||||
|
||||
/**
|
||||
* System private API to comunicate with trust service.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
interface ITrustManager {
|
||||
void reportUnlockAttempt(boolean successful, int userId);
|
||||
void reportEnabledTrustAgentsChanged(int userId);
|
||||
void registerTrustListener(in ITrustListener trustListener);
|
||||
void unregisterTrustListener(in ITrustListener trustListener);
|
||||
}
|
||||
134
core/java/android/app/trust/TrustManager.java
Normal file
134
core/java/android/app/trust/TrustManager.java
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package android.app.trust;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* See {@link com.android.server.trust.TrustManagerService}
|
||||
* @hide
|
||||
*/
|
||||
public class TrustManager {
|
||||
|
||||
private static final int MSG_TRUST_CHANGED = 1;
|
||||
|
||||
private static final String TAG = "TrustManager";
|
||||
|
||||
private final ITrustManager mService;
|
||||
private final ArrayMap<TrustListener, ITrustListener> mTrustListeners;
|
||||
|
||||
public TrustManager(IBinder b) {
|
||||
mService = ITrustManager.Stub.asInterface(b);
|
||||
mTrustListeners = new ArrayMap<TrustListener, ITrustListener>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that user {@param userId} has tried to unlock the device.
|
||||
*
|
||||
* @param successful if true, the unlock attempt was successful.
|
||||
*
|
||||
* Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
|
||||
*/
|
||||
public void reportUnlockAttempt(boolean successful, int userId) {
|
||||
try {
|
||||
mService.reportUnlockAttempt(successful, userId);
|
||||
} catch (RemoteException e) {
|
||||
onError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that the list of enabled trust agents changed for user {@param userId}.
|
||||
*
|
||||
* Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
|
||||
*/
|
||||
public void reportEnabledTrustAgentsChanged(int userId) {
|
||||
try {
|
||||
mService.reportEnabledTrustAgentsChanged(userId);
|
||||
} catch (RemoteException e) {
|
||||
onError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a listener for trust events.
|
||||
*
|
||||
* Requires the {@link android.Manifest.permission#TRUST_LISTENER} permission.
|
||||
*/
|
||||
public void registerTrustListener(final TrustListener trustListener) {
|
||||
try {
|
||||
ITrustListener.Stub iTrustListener = new ITrustListener.Stub() {
|
||||
@Override
|
||||
public void onTrustChanged(boolean enabled, int userId) throws RemoteException {
|
||||
mHandler.obtainMessage(MSG_TRUST_CHANGED, (enabled ? 1 : 0), userId,
|
||||
trustListener).sendToTarget();
|
||||
}
|
||||
};
|
||||
mService.registerTrustListener(iTrustListener);
|
||||
mTrustListeners.put(trustListener, iTrustListener);
|
||||
} catch (RemoteException e) {
|
||||
onError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a listener for trust events.
|
||||
*
|
||||
* Requires the {@link android.Manifest.permission#TRUST_LISTENER} permission.
|
||||
*/
|
||||
public void unregisterTrustListener(final TrustListener trustListener) {
|
||||
ITrustListener iTrustListener = mTrustListeners.remove(trustListener);
|
||||
if (iTrustListener != null) {
|
||||
try {
|
||||
mService.unregisterTrustListener(iTrustListener);
|
||||
} catch (RemoteException e) {
|
||||
onError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onError(Exception e) {
|
||||
Log.e(TAG, "Error while calling TrustManagerService", e);
|
||||
}
|
||||
|
||||
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch(msg.what) {
|
||||
case MSG_TRUST_CHANGED:
|
||||
((TrustListener)msg.obj).onTrustChanged(msg.arg1 != 0, msg.arg2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public interface TrustListener {
|
||||
|
||||
/**
|
||||
* Reports that the trust state has changed.
|
||||
* @param enabled if true, the system believes the environment to be trusted.
|
||||
* @param userId the user, for which the trust changed.
|
||||
*/
|
||||
void onTrustChanged(boolean enabled, int userId);
|
||||
}
|
||||
}
|
||||
@@ -2594,6 +2594,14 @@ public abstract class Context {
|
||||
*/
|
||||
public static final String CONSUMER_IR_SERVICE = "consumer_ir";
|
||||
|
||||
/**
|
||||
* {@link android.app.trust.TrustManager} for managing trust agents.
|
||||
* @see #getSystemService
|
||||
* @see android.app.trust.TrustManager
|
||||
* @hide
|
||||
*/
|
||||
public static final String TRUST_SERVICE = "trust";
|
||||
|
||||
/**
|
||||
* Determine whether the given permission is allowed for a particular
|
||||
* process and user ID running in the system.
|
||||
|
||||
@@ -19,11 +19,14 @@ package com.android.internal.widget;
|
||||
import android.Manifest;
|
||||
import android.app.ActivityManagerNative;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.trust.TrustManager;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
@@ -46,6 +49,8 @@ import com.google.android.collect.Lists;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -145,6 +150,8 @@ public class LockPatternUtils {
|
||||
private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
|
||||
Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
|
||||
|
||||
private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
|
||||
|
||||
private final Context mContext;
|
||||
private final ContentResolver mContentResolver;
|
||||
private DevicePolicyManager mDevicePolicyManager;
|
||||
@@ -167,6 +174,15 @@ public class LockPatternUtils {
|
||||
return mDevicePolicyManager;
|
||||
}
|
||||
|
||||
private TrustManager getTrustManager() {
|
||||
TrustManager trust = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
|
||||
if (trust == null) {
|
||||
Log.e(TAG, "Can't get TrustManagerService: is it running?",
|
||||
new IllegalStateException("Stack trace:"));
|
||||
}
|
||||
return trust;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param contentResolver Used to look up and save settings.
|
||||
*/
|
||||
@@ -242,10 +258,14 @@ public class LockPatternUtils {
|
||||
*/
|
||||
public void reportFailedPasswordAttempt() {
|
||||
getDevicePolicyManager().reportFailedPasswordAttempt(getCurrentOrCallingUserId());
|
||||
getTrustManager().reportUnlockAttempt(false /* authenticated */,
|
||||
getCurrentOrCallingUserId());
|
||||
}
|
||||
|
||||
public void reportSuccessfulPasswordAttempt() {
|
||||
getDevicePolicyManager().reportSuccessfulPasswordAttempt(getCurrentOrCallingUserId());
|
||||
getTrustManager().reportUnlockAttempt(true /* authenticated */,
|
||||
getCurrentOrCallingUserId());
|
||||
}
|
||||
|
||||
public void setCurrentUser(int userId) {
|
||||
@@ -496,11 +516,12 @@ public class LockPatternUtils {
|
||||
*/
|
||||
public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback) {
|
||||
try {
|
||||
getLockSettings().setLockPattern(patternToString(pattern), getCurrentOrCallingUserId());
|
||||
int userId = getCurrentOrCallingUserId();
|
||||
getLockSettings().setLockPattern(patternToString(pattern), userId);
|
||||
DevicePolicyManager dpm = getDevicePolicyManager();
|
||||
if (pattern != null) {
|
||||
|
||||
int userHandle = getCurrentOrCallingUserId();
|
||||
int userHandle = userId;
|
||||
if (userHandle == UserHandle.USER_OWNER) {
|
||||
String stringPattern = patternToString(pattern);
|
||||
updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
|
||||
@@ -511,18 +532,18 @@ public class LockPatternUtils {
|
||||
deleteGallery();
|
||||
setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
|
||||
dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
|
||||
pattern.size(), 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
|
||||
pattern.size(), 0, 0, 0, 0, 0, 0, userId);
|
||||
} else {
|
||||
setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
|
||||
setLong(PASSWORD_TYPE_ALTERNATE_KEY,
|
||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
|
||||
finishBiometricWeak();
|
||||
dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
|
||||
0, 0, 0, 0, 0, 0, 0, getCurrentOrCallingUserId());
|
||||
0, 0, 0, 0, 0, 0, 0, userId);
|
||||
}
|
||||
} else {
|
||||
dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0,
|
||||
0, 0, 0, 0, 0, getCurrentOrCallingUserId());
|
||||
0, 0, 0, 0, 0, userId);
|
||||
}
|
||||
} catch (RemoteException re) {
|
||||
Log.e(TAG, "Couldn't save lock pattern " + re);
|
||||
@@ -1374,4 +1395,38 @@ public class LockPatternUtils {
|
||||
setBoolean(LOCKSCREEN_WIDGETS_ENABLED, enabled, userId);
|
||||
}
|
||||
|
||||
public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents) {
|
||||
setEnabledTrustAgents(activeTrustAgents, getCurrentOrCallingUserId());
|
||||
}
|
||||
|
||||
public List<ComponentName> getEnabledTrustAgents() {
|
||||
return getEnabledTrustAgents(getCurrentOrCallingUserId());
|
||||
}
|
||||
|
||||
public void setEnabledTrustAgents(Collection<ComponentName> activeTrustAgents, int userId) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (ComponentName cn : activeTrustAgents) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(cn.flattenToShortString());
|
||||
}
|
||||
setString(ENABLED_TRUST_AGENTS, sb.toString(), userId);
|
||||
getTrustManager().reportEnabledTrustAgentsChanged(getCurrentOrCallingUserId());
|
||||
}
|
||||
|
||||
public List<ComponentName> getEnabledTrustAgents(int userId) {
|
||||
String serialized = getString(ENABLED_TRUST_AGENTS, userId);
|
||||
if (TextUtils.isEmpty(serialized)) {
|
||||
return null;
|
||||
}
|
||||
String[] split = serialized.split(",");
|
||||
ArrayList<ComponentName> activeTrustAgents = new ArrayList<ComponentName>(split.length);
|
||||
for (String s : split) {
|
||||
if (!TextUtils.isEmpty(s)) {
|
||||
activeTrustAgents.add(ComponentName.unflattenFromString(s));
|
||||
}
|
||||
}
|
||||
return activeTrustAgents;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2547,6 +2547,13 @@
|
||||
android:label="@string/permlab_control_keyguard"
|
||||
android:description="@string/permdesc_control_keyguard" />
|
||||
|
||||
<!-- Allows an application to listen to trust changes. Only allowed for system processes.
|
||||
@hide -->
|
||||
<permission android:name="android.permission.TRUST_LISTENER"
|
||||
android:protectionLevel="signature"
|
||||
android:label="@string/permlab_trust_listener"
|
||||
android:description="@string/permdesc_trust_listener" />
|
||||
|
||||
<!-- Must be required by an {@link
|
||||
android.service.trust.TrustAgentService},
|
||||
to ensure that only the system can bind to it. -->
|
||||
|
||||
@@ -3651,6 +3651,11 @@
|
||||
<!-- Description of an application permission that lets it control keyguard. -->
|
||||
<string name="permdesc_control_keyguard">Allows an application to control keguard.</string>
|
||||
|
||||
<!-- Title of an application permission that lets it listen to trust state changes. -->
|
||||
<string name="permlab_trust_listener">Listen to trust state changes.</string>
|
||||
<!-- Description of an application permission that lets it listen to trust state changes. -->
|
||||
<string name="permdesc_trust_listener">Allows an application to listen for changes in trust state.</string>
|
||||
|
||||
<!-- Title of an application permission that lets it bind to a trust agent service. -->
|
||||
<string name="permlab_bind_trust_agent_service">Bind to a trust agent service</string>
|
||||
<!-- Description of an application permission that lets it bind to a trust agent service. -->
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.trust;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.service.trust.ITrustAgentService;
|
||||
import android.service.trust.ITrustAgentServiceCallback;
|
||||
|
||||
/**
|
||||
* A wrapper around a TrustAgentService interface. Coordinates communication between
|
||||
* TrustManager and the actual TrustAgent.
|
||||
*/
|
||||
public class TrustAgentWrapper {
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String TAG = "TrustAgentWrapper";
|
||||
|
||||
private static final int MSG_ENABLE_TRUST = 1;
|
||||
private static final int MSG_REVOKE_TRUST = 2;
|
||||
private static final int MSG_TRUST_TIMEOUT = 3;
|
||||
|
||||
private final TrustManagerService mTrustManagerService;
|
||||
private final int mUserId;
|
||||
private final Context mContext;
|
||||
private final ComponentName mName;
|
||||
|
||||
private ITrustAgentService mTrustAgentService;
|
||||
|
||||
// Trust state
|
||||
private boolean mTrusted;
|
||||
private String mMessage;
|
||||
|
||||
private final Handler mHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_ENABLE_TRUST:
|
||||
mTrusted = true;
|
||||
mMessage = (String) msg.obj;
|
||||
boolean initiatedByUser = msg.arg1 != 0;
|
||||
// TODO: Handle handle user initiated trust changes.
|
||||
mTrustManagerService.updateTrust(mUserId);
|
||||
break;
|
||||
case MSG_TRUST_TIMEOUT:
|
||||
if (DEBUG) Slog.v(TAG, "Trust timed out : " + mName.flattenToShortString());
|
||||
// Fall through.
|
||||
case MSG_REVOKE_TRUST:
|
||||
mTrusted = false;
|
||||
mMessage = null;
|
||||
mTrustManagerService.updateTrust(mUserId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() {
|
||||
|
||||
public void enableTrust(String userMessage, long durationMs, boolean initiatedByUser) {
|
||||
if (DEBUG) Slog.v(TAG, "enableTrust(" + userMessage + ", durationMs = " + durationMs
|
||||
+ ", initiatedByUser = " + initiatedByUser + ")");
|
||||
|
||||
mHandler.obtainMessage(MSG_ENABLE_TRUST, initiatedByUser ? 1 : 0, 0, userMessage)
|
||||
.sendToTarget();
|
||||
if (durationMs > 0) {
|
||||
mHandler.removeMessages(MSG_TRUST_TIMEOUT);
|
||||
mHandler.sendEmptyMessageDelayed(MSG_TRUST_TIMEOUT, durationMs);
|
||||
}
|
||||
}
|
||||
|
||||
public void revokeTrust() {
|
||||
if (DEBUG) Slog.v(TAG, "revokeTrust()");
|
||||
mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
|
||||
}
|
||||
};
|
||||
|
||||
private final ServiceConnection mConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
if (DEBUG) Log.v(TAG, "TrustAgent started : " + name.flattenToString());
|
||||
mTrustAgentService = ITrustAgentService.Stub.asInterface(service);
|
||||
setCallback(mCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
if (DEBUG) Log.v(TAG, "TrustAgent disconnected : " + name.flattenToShortString());
|
||||
mTrustAgentService = null;
|
||||
mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public TrustAgentWrapper(Context context, TrustManagerService trustManagerService,
|
||||
Intent intent, UserHandle user) {
|
||||
mContext = context;
|
||||
mTrustManagerService = trustManagerService;
|
||||
mUserId = user.getIdentifier();
|
||||
mName = intent.getComponent();
|
||||
if (!context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, user)) {
|
||||
if (DEBUG) Log.v(TAG, "can't bind to TrustAgent " + mName.flattenToShortString());
|
||||
// TODO: retry somehow?
|
||||
}
|
||||
}
|
||||
|
||||
private void onError(Exception e) {
|
||||
Slog.w(TAG , "Remote Exception", e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see android.service.trust.TrustAgentService#onUnlockAttempt(boolean)
|
||||
*/
|
||||
public void onUnlockAttempt(boolean successful) {
|
||||
try {
|
||||
if (mTrustAgentService != null) mTrustAgentService.onUnlockAttempt(successful);
|
||||
} catch (RemoteException e) {
|
||||
onError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void setCallback(ITrustAgentServiceCallback callback) {
|
||||
try {
|
||||
if (mTrustAgentService != null) {
|
||||
mTrustAgentService.setCallback(callback);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
onError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isTrusted() {
|
||||
return mTrusted;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return mMessage;
|
||||
}
|
||||
|
||||
public void unbind() {
|
||||
if (DEBUG) Log.v(TAG, "TrustAgent unbound : " + mName.flattenToShortString());
|
||||
mContext.unbindService(mConnection);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,387 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.server.trust;
|
||||
|
||||
import com.android.internal.content.PackageMonitor;
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.server.SystemService;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.trust.ITrustListener;
|
||||
import android.app.trust.ITrustManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.service.trust.TrustAgentService;
|
||||
import android.util.ArraySet;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Slog;
|
||||
import android.util.Xml;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Manages trust agents and trust listeners.
|
||||
*
|
||||
* It is responsible for binding to the enabled {@link android.service.trust.TrustAgentService}s
|
||||
* of each user and notifies them about events that are relevant to them.
|
||||
* It start and stops them based on the value of
|
||||
* {@link com.android.internal.widget.LockPatternUtils#getEnabledTrustAgents(int)}.
|
||||
*
|
||||
* It also keeps a set of {@link android.app.trust.ITrustListener}s that are notified whenever the
|
||||
* trust state changes for any user.
|
||||
*
|
||||
* Trust state and the setting of enabled agents is kept per user and each user has its own
|
||||
* instance of a {@link android.service.trust.TrustAgentService}.
|
||||
*/
|
||||
public class TrustManagerService extends SystemService {
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String TAG = "TrustManagerService";
|
||||
|
||||
private static final Intent TRUST_AGENT_INTENT =
|
||||
new Intent(TrustAgentService.SERVICE_INTERFACE);
|
||||
|
||||
private static final int MSG_REGISTER_LISTENER = 1;
|
||||
private static final int MSG_UNREGISTER_LISTENER = 2;
|
||||
private static final int MSG_DISPATCH_UNLOCK_ATTEMPT = 3;
|
||||
private static final int MSG_ENABLED_AGENTS_CHANGED = 4;
|
||||
|
||||
private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<AgentInfo>();
|
||||
private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<ITrustListener>();
|
||||
private final Context mContext;
|
||||
|
||||
private UserManager mUserManager;
|
||||
|
||||
/**
|
||||
* Cache for {@link #refreshAgentList()}
|
||||
*/
|
||||
private final ArraySet<AgentInfo> mObsoleteAgents = new ArraySet<AgentInfo>();
|
||||
|
||||
|
||||
public TrustManagerService(Context context) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
publishBinderService(Context.TRUST_SERVICE, mService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBootPhase(int phase) {
|
||||
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY && !isSafeMode()) {
|
||||
// Listen for package changes
|
||||
mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
|
||||
refreshAgentList();
|
||||
}
|
||||
}
|
||||
|
||||
// Agent management
|
||||
|
||||
private static final class AgentInfo {
|
||||
CharSequence label;
|
||||
Drawable icon;
|
||||
ComponentName component; // service that implements ITrustAgent
|
||||
ComponentName settings; // setting to launch to modify agent.
|
||||
TrustAgentWrapper agent;
|
||||
int userId;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof AgentInfo)) {
|
||||
return false;
|
||||
}
|
||||
AgentInfo o = (AgentInfo) other;
|
||||
return component.equals(o.component) && userId == o.userId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return component.hashCode() * 31 + userId;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTrustAll() {
|
||||
List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
|
||||
for (UserInfo userInfo : userInfos) {
|
||||
updateTrust(userInfo.id);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateTrust(int userId) {
|
||||
dispatchOnTrustChanged(aggregateIsTrusted(userId), userId);
|
||||
}
|
||||
|
||||
protected void refreshAgentList() {
|
||||
if (DEBUG) Slog.d(TAG, "refreshAgentList()");
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
|
||||
List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
|
||||
LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
|
||||
|
||||
mObsoleteAgents.clear();
|
||||
mObsoleteAgents.addAll(mActiveAgents);
|
||||
|
||||
for (UserInfo userInfo : userInfos) {
|
||||
List<ComponentName> enabledAgents = lockPatternUtils.getEnabledTrustAgents(userInfo.id);
|
||||
if (enabledAgents == null) {
|
||||
continue;
|
||||
}
|
||||
List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(TRUST_AGENT_INTENT,
|
||||
PackageManager.GET_META_DATA, userInfo.id);
|
||||
for (ResolveInfo resolveInfo : resolveInfos) {
|
||||
if (resolveInfo.serviceInfo == null) continue;
|
||||
ComponentName name = getComponentName(resolveInfo);
|
||||
if (!enabledAgents.contains(name)) continue;
|
||||
|
||||
AgentInfo agentInfo = new AgentInfo();
|
||||
agentInfo.component = name;
|
||||
agentInfo.userId = userInfo.id;
|
||||
if (!mActiveAgents.contains(agentInfo)) {
|
||||
agentInfo.label = resolveInfo.loadLabel(pm);
|
||||
agentInfo.icon = resolveInfo.loadIcon(pm);
|
||||
agentInfo.settings = getSettingsComponentName(pm, resolveInfo);
|
||||
agentInfo.agent = new TrustAgentWrapper(mContext, this,
|
||||
new Intent().setComponent(name), userInfo.getUserHandle());
|
||||
mActiveAgents.add(agentInfo);
|
||||
} else {
|
||||
mObsoleteAgents.remove(agentInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean trustMayHaveChanged = false;
|
||||
for (int i = 0; i < mObsoleteAgents.size(); i++) {
|
||||
AgentInfo info = mActiveAgents.valueAt(i);
|
||||
if (info.agent.isTrusted()) {
|
||||
trustMayHaveChanged = true;
|
||||
}
|
||||
info.agent.unbind();
|
||||
mActiveAgents.remove(info);
|
||||
}
|
||||
|
||||
if (trustMayHaveChanged) {
|
||||
updateTrustAll();
|
||||
}
|
||||
}
|
||||
|
||||
private ComponentName getSettingsComponentName(PackageManager pm, ResolveInfo resolveInfo) {
|
||||
if (resolveInfo == null || resolveInfo.serviceInfo == null
|
||||
|| resolveInfo.serviceInfo.metaData == null) return null;
|
||||
String cn = null;
|
||||
XmlResourceParser parser = null;
|
||||
Exception caughtException = null;
|
||||
try {
|
||||
parser = resolveInfo.serviceInfo.loadXmlMetaData(pm,
|
||||
TrustAgentService.TRUST_AGENT_META_DATA);
|
||||
if (parser == null) {
|
||||
Slog.w(TAG, "Can't find " + TrustAgentService.TRUST_AGENT_META_DATA + " meta-data");
|
||||
return null;
|
||||
}
|
||||
Resources res = pm.getResourcesForApplication(resolveInfo.serviceInfo.applicationInfo);
|
||||
AttributeSet attrs = Xml.asAttributeSet(parser);
|
||||
int type;
|
||||
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
|
||||
&& type != XmlPullParser.START_TAG) {
|
||||
// Drain preamble.
|
||||
}
|
||||
String nodeName = parser.getName();
|
||||
if (!"trust_agent".equals(nodeName)) {
|
||||
Slog.w(TAG, "Meta-data does not start with trust_agent tag");
|
||||
return null;
|
||||
}
|
||||
TypedArray sa = res
|
||||
.obtainAttributes(attrs, com.android.internal.R.styleable.TrustAgent);
|
||||
cn = sa.getString(com.android.internal.R.styleable.TrustAgent_settingsActivity);
|
||||
sa.recycle();
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
caughtException = e;
|
||||
} catch (IOException e) {
|
||||
caughtException = e;
|
||||
} catch (XmlPullParserException e) {
|
||||
caughtException = e;
|
||||
} finally {
|
||||
if (parser != null) parser.close();
|
||||
}
|
||||
if (caughtException != null) {
|
||||
Slog.w(TAG, "Error parsing : " + resolveInfo.serviceInfo.packageName, caughtException);
|
||||
return null;
|
||||
}
|
||||
if (cn == null) {
|
||||
return null;
|
||||
}
|
||||
if (cn.indexOf('/') < 0) {
|
||||
cn = resolveInfo.serviceInfo.packageName + "/" + cn;
|
||||
}
|
||||
return ComponentName.unflattenFromString(cn);
|
||||
}
|
||||
|
||||
private ComponentName getComponentName(ResolveInfo resolveInfo) {
|
||||
if (resolveInfo == null || resolveInfo.serviceInfo == null) return null;
|
||||
return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
|
||||
}
|
||||
|
||||
// Agent dispatch and aggregation
|
||||
|
||||
private boolean aggregateIsTrusted(int userId) {
|
||||
for (int i = 0; i < mActiveAgents.size(); i++) {
|
||||
AgentInfo info = mActiveAgents.valueAt(i);
|
||||
if (info.userId == userId) {
|
||||
if (info.agent.isTrusted()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void dispatchUnlockAttempt(boolean successful, int userId) {
|
||||
for (int i = 0; i < mActiveAgents.size(); i++) {
|
||||
AgentInfo info = mActiveAgents.valueAt(i);
|
||||
if (info.userId == userId) {
|
||||
info.agent.onUnlockAttempt(successful);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Listeners
|
||||
|
||||
private void addListener(ITrustListener listener) {
|
||||
for (int i = 0; i < mTrustListeners.size(); i++) {
|
||||
if (mTrustListeners.get(i).asBinder() == listener.asBinder()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
mTrustListeners.add(listener);
|
||||
}
|
||||
|
||||
private void removeListener(ITrustListener listener) {
|
||||
for (int i = 0; i < mTrustListeners.size(); i++) {
|
||||
if (mTrustListeners.get(i).asBinder() == listener.asBinder()) {
|
||||
mTrustListeners.get(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchOnTrustChanged(boolean enabled, int userId) {
|
||||
for (int i = 0; i < mTrustListeners.size(); i++) {
|
||||
try {
|
||||
mTrustListeners.get(i).onTrustChanged(enabled, userId);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Exception while notifying TrustListener. Removing listener.", e);
|
||||
mTrustListeners.get(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Plumbing
|
||||
|
||||
private final IBinder mService = new ITrustManager.Stub() {
|
||||
@Override
|
||||
public void reportUnlockAttempt(boolean authenticated, int userId) throws RemoteException {
|
||||
enforceReportPermission();
|
||||
mHandler.obtainMessage(MSG_DISPATCH_UNLOCK_ATTEMPT, authenticated ? 1 : 0, userId)
|
||||
.sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportEnabledTrustAgentsChanged(int userId) throws RemoteException {
|
||||
enforceReportPermission();
|
||||
// coalesce refresh messages.
|
||||
mHandler.removeMessages(MSG_ENABLED_AGENTS_CHANGED);
|
||||
mHandler.sendEmptyMessage(MSG_ENABLED_AGENTS_CHANGED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerTrustListener(ITrustListener trustListener) throws RemoteException {
|
||||
enforceListenerPermission();
|
||||
mHandler.obtainMessage(MSG_REGISTER_LISTENER, trustListener).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterTrustListener(ITrustListener trustListener) throws RemoteException {
|
||||
enforceListenerPermission();
|
||||
mHandler.obtainMessage(MSG_UNREGISTER_LISTENER, trustListener).sendToTarget();
|
||||
}
|
||||
|
||||
private void enforceReportPermission() {
|
||||
mContext.enforceCallingPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE,
|
||||
"reporting trust events");
|
||||
}
|
||||
|
||||
private void enforceListenerPermission() {
|
||||
mContext.enforceCallingPermission(Manifest.permission.TRUST_LISTENER,
|
||||
"register trust listener");
|
||||
}
|
||||
};
|
||||
|
||||
private final Handler mHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_REGISTER_LISTENER:
|
||||
addListener((ITrustListener) msg.obj);
|
||||
break;
|
||||
case MSG_UNREGISTER_LISTENER:
|
||||
removeListener((ITrustListener) msg.obj);
|
||||
break;
|
||||
case MSG_DISPATCH_UNLOCK_ATTEMPT:
|
||||
dispatchUnlockAttempt(msg.arg1 != 0, msg.arg2);
|
||||
break;
|
||||
case MSG_ENABLED_AGENTS_CHANGED:
|
||||
refreshAgentList();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
|
||||
@Override
|
||||
public void onSomePackagesChanged() {
|
||||
refreshAgentList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPackageChanged(String packageName, int uid, String[] components) {
|
||||
// We're interested in all changes, even if just some components get enabled / disabled.
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -76,6 +76,7 @@ import com.android.server.power.ShutdownThread;
|
||||
import com.android.server.search.SearchManagerService;
|
||||
import com.android.server.statusbar.StatusBarManagerService;
|
||||
import com.android.server.storage.DeviceStorageMonitorService;
|
||||
import com.android.server.trust.TrustManagerService;
|
||||
import com.android.server.twilight.TwilightService;
|
||||
import com.android.server.usb.UsbService;
|
||||
import com.android.server.wallpaper.WallpaperManagerService;
|
||||
@@ -913,6 +914,13 @@ public final class SystemServer {
|
||||
} catch (Throwable e) {
|
||||
reportWtf("starting MediaRouterService", e);
|
||||
}
|
||||
|
||||
try {
|
||||
Slog.i(TAG, "Trust Manager");
|
||||
mSystemServiceManager.startService(TrustManagerService.class);
|
||||
} catch (Throwable e) {
|
||||
Slog.e(TAG, "Failure starting TrustManagerService", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user