TrustAgentWrapper.java revision 76b9b8b0ca537bad6c4da388d77a9e5dee023856
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.trust; 18 19import android.app.AlarmManager; 20import android.app.PendingIntent; 21import android.app.admin.DevicePolicyManager; 22import android.content.BroadcastReceiver; 23import android.content.ComponentName; 24import android.content.Context; 25import android.content.Intent; 26import android.content.IntentFilter; 27import android.content.ServiceConnection; 28import android.net.Uri; 29import android.os.Binder; 30import android.os.Bundle; 31import android.os.Handler; 32import android.os.IBinder; 33import android.os.Message; 34import android.os.PatternMatcher; 35import android.os.RemoteException; 36import android.os.SystemClock; 37import android.os.UserHandle; 38import android.util.Log; 39import android.util.Slog; 40import android.service.trust.ITrustAgentService; 41import android.service.trust.ITrustAgentServiceCallback; 42import android.service.trust.TrustAgentService; 43 44import java.util.ArrayList; 45import java.util.List; 46 47/** 48 * A wrapper around a TrustAgentService interface. Coordinates communication between 49 * TrustManager and the actual TrustAgent. 50 */ 51public class TrustAgentWrapper { 52 private static final String EXTRA_COMPONENT_NAME = "componentName"; 53 private static final String TRUST_EXPIRED_ACTION = "android.server.trust.TRUST_EXPIRED_ACTION"; 54 private static final String PERMISSION = android.Manifest.permission.PROVIDE_TRUST_AGENT; 55 private static final boolean DEBUG = false; 56 private static final String TAG = "TrustAgentWrapper"; 57 58 private static final int MSG_GRANT_TRUST = 1; 59 private static final int MSG_REVOKE_TRUST = 2; 60 private static final int MSG_TRUST_TIMEOUT = 3; 61 private static final int MSG_RESTART_TIMEOUT = 4; 62 private static final int MSG_SET_TRUST_AGENT_FEATURES_COMPLETED = 5; 63 private static final int MSG_MANAGING_TRUST = 6; 64 65 /** 66 * Time in uptime millis that we wait for the service connection, both when starting 67 * and when the service disconnects. 68 */ 69 private static final long RESTART_TIMEOUT_MILLIS = 5 * 60000; 70 71 /** 72 * Long extra for {@link #MSG_GRANT_TRUST} 73 */ 74 private static final String DATA_DURATION = "duration"; 75 76 private final TrustManagerService mTrustManagerService; 77 private final int mUserId; 78 private final Context mContext; 79 private final ComponentName mName; 80 81 private ITrustAgentService mTrustAgentService; 82 private boolean mBound; 83 private long mScheduledRestartUptimeMillis; 84 private long mMaximumTimeToLock; // from DevicePolicyManager 85 86 // Trust state 87 private boolean mTrusted; 88 private CharSequence mMessage; 89 private boolean mTrustDisabledByDpm; 90 private boolean mManagingTrust; 91 private IBinder mSetTrustAgentFeaturesToken; 92 private AlarmManager mAlarmManager; 93 private final Intent mAlarmIntent; 94 private PendingIntent mAlarmPendingIntent; 95 96 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 97 @Override 98 public void onReceive(Context context, Intent intent) { 99 ComponentName component = intent.getParcelableExtra(EXTRA_COMPONENT_NAME); 100 if (TRUST_EXPIRED_ACTION.equals(intent.getAction()) 101 && mName.equals(component)) { 102 mHandler.removeMessages(MSG_TRUST_TIMEOUT); 103 mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT); 104 } 105 } 106 }; 107 108 private final Handler mHandler = new Handler() { 109 @Override 110 public void handleMessage(Message msg) { 111 switch (msg.what) { 112 case MSG_GRANT_TRUST: 113 if (!isConnected()) { 114 Log.w(TAG, "Agent is not connected, cannot grant trust: " 115 + mName.flattenToShortString()); 116 return; 117 } 118 mTrusted = true; 119 mMessage = (CharSequence) msg.obj; 120 boolean initiatedByUser = msg.arg1 != 0; 121 long durationMs = msg.getData().getLong(DATA_DURATION); 122 if (durationMs > 0) { 123 final long duration; 124 if (mMaximumTimeToLock != 0) { 125 // Enforce DevicePolicyManager timeout. This is here as a safeguard to 126 // ensure trust agents are evaluating trust state at least as often as 127 // the policy dictates. Admins that want more guarantees should be using 128 // DevicePolicyManager#KEYGUARD_DISABLE_TRUST_AGENTS. 129 duration = Math.min(durationMs, mMaximumTimeToLock); 130 if (DEBUG) { 131 Log.v(TAG, "DPM lock timeout in effect. Timeout adjusted from " 132 + durationMs + " to " + duration); 133 } 134 } else { 135 duration = durationMs; 136 } 137 long expiration = SystemClock.elapsedRealtime() + duration; 138 mAlarmPendingIntent = PendingIntent.getBroadcast(mContext, 0, mAlarmIntent, 139 PendingIntent.FLAG_CANCEL_CURRENT); 140 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, expiration, 141 mAlarmPendingIntent); 142 } 143 mTrustManagerService.mArchive.logGrantTrust(mUserId, mName, 144 (mMessage != null ? mMessage.toString() : null), 145 durationMs, initiatedByUser); 146 mTrustManagerService.updateTrust(mUserId, initiatedByUser); 147 break; 148 case MSG_TRUST_TIMEOUT: 149 if (DEBUG) Slog.v(TAG, "Trust timed out : " + mName.flattenToShortString()); 150 mTrustManagerService.mArchive.logTrustTimeout(mUserId, mName); 151 onTrustTimeout(); 152 // Fall through. 153 case MSG_REVOKE_TRUST: 154 mTrusted = false; 155 mMessage = null; 156 mHandler.removeMessages(MSG_TRUST_TIMEOUT); 157 if (msg.what == MSG_REVOKE_TRUST) { 158 mTrustManagerService.mArchive.logRevokeTrust(mUserId, mName); 159 } 160 mTrustManagerService.updateTrust(mUserId, false); 161 break; 162 case MSG_RESTART_TIMEOUT: 163 unbind(); 164 mTrustManagerService.resetAgent(mName, mUserId); 165 break; 166 case MSG_SET_TRUST_AGENT_FEATURES_COMPLETED: 167 IBinder token = (IBinder) msg.obj; 168 boolean result = msg.arg1 != 0; 169 if (mSetTrustAgentFeaturesToken == token) { 170 mSetTrustAgentFeaturesToken = null; 171 if (mTrustDisabledByDpm && result) { 172 if (DEBUG) Log.v(TAG, "Re-enabling agent because it acknowledged " 173 + "enabled features: " + mName); 174 mTrustDisabledByDpm = false; 175 mTrustManagerService.updateTrust(mUserId, false); 176 } 177 } else { 178 if (DEBUG) Log.w(TAG, "Ignoring MSG_SET_TRUST_AGENT_FEATURES_COMPLETED " 179 + "with obsolete token: " + mName); 180 } 181 break; 182 case MSG_MANAGING_TRUST: 183 mManagingTrust = msg.arg1 != 0; 184 if (!mManagingTrust) { 185 mTrusted = false; 186 mMessage = null; 187 } 188 mTrustManagerService.mArchive.logManagingTrust(mUserId, mName, mManagingTrust); 189 mTrustManagerService.updateTrust(mUserId, false); 190 break; 191 } 192 } 193 }; 194 195 private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() { 196 197 @Override 198 public void grantTrust(CharSequence userMessage, long durationMs, boolean initiatedByUser) { 199 if (DEBUG) Slog.v(TAG, "enableTrust(" + userMessage + ", durationMs = " + durationMs 200 + ", initiatedByUser = " + initiatedByUser + ")"); 201 202 Message msg = mHandler.obtainMessage( 203 MSG_GRANT_TRUST, initiatedByUser ? 1 : 0, 0, userMessage); 204 msg.getData().putLong(DATA_DURATION, durationMs); 205 msg.sendToTarget(); 206 } 207 208 @Override 209 public void revokeTrust() { 210 if (DEBUG) Slog.v(TAG, "revokeTrust()"); 211 mHandler.sendEmptyMessage(MSG_REVOKE_TRUST); 212 } 213 214 @Override 215 public void setManagingTrust(boolean managingTrust) { 216 if (DEBUG) Slog.v(TAG, "managingTrust()"); 217 mHandler.obtainMessage(MSG_MANAGING_TRUST, managingTrust ? 1 : 0, 0).sendToTarget(); 218 } 219 220 @Override 221 public void onSetTrustAgentFeaturesEnabledCompleted(boolean result, IBinder token) { 222 if (DEBUG) Slog.v(TAG, "onSetTrustAgentFeaturesEnabledCompleted(result=" + result); 223 mHandler.obtainMessage(MSG_SET_TRUST_AGENT_FEATURES_COMPLETED, 224 result ? 1 : 0, 0, token).sendToTarget(); 225 } 226 }; 227 228 private final ServiceConnection mConnection = new ServiceConnection() { 229 @Override 230 public void onServiceConnected(ComponentName name, IBinder service) { 231 if (DEBUG) Log.v(TAG, "TrustAgent started : " + name.flattenToString()); 232 mHandler.removeMessages(MSG_RESTART_TIMEOUT); 233 mTrustAgentService = ITrustAgentService.Stub.asInterface(service); 234 mTrustManagerService.mArchive.logAgentConnected(mUserId, name); 235 setCallback(mCallback); 236 updateDevicePolicyFeatures(); 237 } 238 239 @Override 240 public void onServiceDisconnected(ComponentName name) { 241 if (DEBUG) Log.v(TAG, "TrustAgent disconnected : " + name.flattenToShortString()); 242 mTrustAgentService = null; 243 mManagingTrust = false; 244 mSetTrustAgentFeaturesToken = null; 245 mTrustManagerService.mArchive.logAgentDied(mUserId, name); 246 mHandler.sendEmptyMessage(MSG_REVOKE_TRUST); 247 if (mBound) { 248 scheduleRestart(); 249 } 250 // mTrustDisabledByDpm maintains state 251 } 252 }; 253 254 public TrustAgentWrapper(Context context, TrustManagerService trustManagerService, 255 Intent intent, UserHandle user) { 256 mContext = context; 257 mTrustManagerService = trustManagerService; 258 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 259 mUserId = user.getIdentifier(); 260 mName = intent.getComponent(); 261 262 mAlarmIntent = new Intent(TRUST_EXPIRED_ACTION).putExtra(EXTRA_COMPONENT_NAME, mName); 263 mAlarmIntent.setData(Uri.parse(mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME))); 264 mAlarmIntent.setPackage(context.getPackageName()); 265 266 final IntentFilter alarmFilter = new IntentFilter(TRUST_EXPIRED_ACTION); 267 alarmFilter.addDataScheme(mAlarmIntent.getScheme()); 268 final String pathUri = mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME); 269 alarmFilter.addDataPath(pathUri, PatternMatcher.PATTERN_LITERAL); 270 mContext.registerReceiver(mBroadcastReceiver, alarmFilter, PERMISSION, null); 271 272 // Schedules a restart for when connecting times out. If the connection succeeds, 273 // the restart is canceled in mCallback's onConnected. 274 scheduleRestart(); 275 mBound = context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, user); 276 if (!mBound) { 277 Log.e(TAG, "Can't bind to TrustAgent " + mName.flattenToShortString()); 278 } 279 } 280 281 private void onError(Exception e) { 282 Slog.w(TAG , "Remote Exception", e); 283 } 284 285 private void onTrustTimeout() { 286 try { 287 if (mTrustAgentService != null) mTrustAgentService.onTrustTimeout(); 288 } catch (RemoteException e) { 289 onError(e); 290 } 291 } 292 /** 293 * @see android.service.trust.TrustAgentService#onUnlockAttempt(boolean) 294 */ 295 public void onUnlockAttempt(boolean successful) { 296 try { 297 if (mTrustAgentService != null) mTrustAgentService.onUnlockAttempt(successful); 298 } catch (RemoteException e) { 299 onError(e); 300 } 301 } 302 303 private void setCallback(ITrustAgentServiceCallback callback) { 304 try { 305 if (mTrustAgentService != null) { 306 mTrustAgentService.setCallback(callback); 307 } 308 } catch (RemoteException e) { 309 onError(e); 310 } 311 } 312 313 boolean updateDevicePolicyFeatures() { 314 boolean trustDisabled = false; 315 if (DEBUG) Slog.v(TAG, "updateDevicePolicyFeatures(" + mName + ")"); 316 try { 317 if (mTrustAgentService != null) { 318 DevicePolicyManager dpm = 319 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 320 321 if ((dpm.getKeyguardDisabledFeatures(null) 322 & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0) { 323 List<String> features = dpm.getTrustAgentFeaturesEnabled(null, mName); 324 trustDisabled = true; 325 if (DEBUG) Slog.v(TAG, "Detected trust agents disabled. Features = " 326 + features); 327 if (features != null && features.size() > 0) { 328 Bundle bundle = new Bundle(); 329 bundle.putStringArrayList(TrustAgentService.KEY_FEATURES, 330 (ArrayList<String>)features); 331 if (DEBUG) { 332 Slog.v(TAG, "TrustAgent " + mName.flattenToShortString() 333 + " disabled until it acknowledges "+ features); 334 } 335 mSetTrustAgentFeaturesToken = new Binder(); 336 mTrustAgentService.setTrustAgentFeaturesEnabled(bundle, 337 mSetTrustAgentFeaturesToken); 338 } 339 } 340 final long maxTimeToLock = dpm.getMaximumTimeToLock(null); 341 if (maxTimeToLock != mMaximumTimeToLock) { 342 // If the timeout changes, cancel the alarm and send a timeout event to have 343 // the agent re-evaluate trust. 344 mMaximumTimeToLock = maxTimeToLock; 345 if (mAlarmPendingIntent != null) { 346 mAlarmManager.cancel(mAlarmPendingIntent); 347 mAlarmPendingIntent = null; 348 mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT); 349 } 350 } 351 } 352 } catch (RemoteException e) { 353 onError(e); 354 } 355 if (mTrustDisabledByDpm != trustDisabled) { 356 mTrustDisabledByDpm = trustDisabled; 357 mTrustManagerService.updateTrust(mUserId, false); 358 } 359 return trustDisabled; 360 } 361 362 public boolean isTrusted() { 363 return mTrusted && mManagingTrust && !mTrustDisabledByDpm; 364 } 365 366 public boolean isManagingTrust() { 367 return mManagingTrust && !mTrustDisabledByDpm; 368 } 369 370 public CharSequence getMessage() { 371 return mMessage; 372 } 373 374 public void unbind() { 375 if (!mBound) { 376 return; 377 } 378 if (DEBUG) Log.v(TAG, "TrustAgent unbound : " + mName.flattenToShortString()); 379 mTrustManagerService.mArchive.logAgentStopped(mUserId, mName); 380 mContext.unbindService(mConnection); 381 mBound = false; 382 mTrustAgentService = null; 383 mSetTrustAgentFeaturesToken = null; 384 mHandler.sendEmptyMessage(MSG_REVOKE_TRUST); 385 mHandler.removeMessages(MSG_RESTART_TIMEOUT); 386 } 387 388 public boolean isConnected() { 389 return mTrustAgentService != null; 390 } 391 392 public boolean isBound() { 393 return mBound; 394 } 395 396 /** 397 * If not connected, returns the time at which the agent is restarted. 398 * 399 * @return restart time in uptime millis. 400 */ 401 public long getScheduledRestartUptimeMillis() { 402 return mScheduledRestartUptimeMillis; 403 } 404 405 private void scheduleRestart() { 406 mHandler.removeMessages(MSG_RESTART_TIMEOUT); 407 mScheduledRestartUptimeMillis = SystemClock.uptimeMillis() + RESTART_TIMEOUT_MILLIS; 408 mHandler.sendEmptyMessageAtTime(MSG_RESTART_TIMEOUT, mScheduledRestartUptimeMillis); 409 } 410} 411