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