TrustAgentWrapper.java revision d4efaac5d54cdb3735b032bb76a5639949f33216
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.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 85 // Trust state 86 private boolean mTrusted; 87 private CharSequence mMessage; 88 private boolean mTrustDisabledByDpm; 89 private boolean mManagingTrust; 90 private IBinder mSetTrustAgentFeaturesToken; 91 private AlarmManager mAlarmManager; 92 private final Intent mAlarmIntent; 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 long expiration = SystemClock.elapsedRealtime() + durationMs; 122 PendingIntent op = PendingIntent.getBroadcast(mContext, 0, mAlarmIntent, 123 PendingIntent.FLAG_CANCEL_CURRENT); 124 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, expiration, op); 125 } 126 mTrustManagerService.mArchive.logGrantTrust(mUserId, mName, 127 (mMessage != null ? mMessage.toString() : null), 128 durationMs, initiatedByUser); 129 mTrustManagerService.updateTrust(mUserId, initiatedByUser); 130 break; 131 case MSG_TRUST_TIMEOUT: 132 if (DEBUG) Slog.v(TAG, "Trust timed out : " + mName.flattenToShortString()); 133 mTrustManagerService.mArchive.logTrustTimeout(mUserId, mName); 134 onTrustTimeout(); 135 // Fall through. 136 case MSG_REVOKE_TRUST: 137 mTrusted = false; 138 mMessage = null; 139 mHandler.removeMessages(MSG_TRUST_TIMEOUT); 140 if (msg.what == MSG_REVOKE_TRUST) { 141 mTrustManagerService.mArchive.logRevokeTrust(mUserId, mName); 142 } 143 mTrustManagerService.updateTrust(mUserId, false); 144 break; 145 case MSG_RESTART_TIMEOUT: 146 unbind(); 147 mTrustManagerService.resetAgent(mName, mUserId); 148 break; 149 case MSG_SET_TRUST_AGENT_FEATURES_COMPLETED: 150 IBinder token = (IBinder) msg.obj; 151 boolean result = msg.arg1 != 0; 152 if (mSetTrustAgentFeaturesToken == token) { 153 mSetTrustAgentFeaturesToken = null; 154 if (mTrustDisabledByDpm && result) { 155 if (DEBUG) Log.v(TAG, "Re-enabling agent because it acknowledged " 156 + "enabled features: " + mName); 157 mTrustDisabledByDpm = false; 158 mTrustManagerService.updateTrust(mUserId, false); 159 } 160 } else { 161 if (DEBUG) Log.w(TAG, "Ignoring MSG_SET_TRUST_AGENT_FEATURES_COMPLETED " 162 + "with obsolete token: " + mName); 163 } 164 break; 165 case MSG_MANAGING_TRUST: 166 mManagingTrust = msg.arg1 != 0; 167 if (!mManagingTrust) { 168 mTrusted = false; 169 mMessage = null; 170 } 171 mTrustManagerService.mArchive.logManagingTrust(mUserId, mName, mManagingTrust); 172 mTrustManagerService.updateTrust(mUserId, false); 173 break; 174 } 175 } 176 }; 177 178 private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() { 179 180 @Override 181 public void grantTrust(CharSequence userMessage, long durationMs, boolean initiatedByUser) { 182 if (DEBUG) Slog.v(TAG, "enableTrust(" + userMessage + ", durationMs = " + durationMs 183 + ", initiatedByUser = " + initiatedByUser + ")"); 184 185 Message msg = mHandler.obtainMessage( 186 MSG_GRANT_TRUST, initiatedByUser ? 1 : 0, 0, userMessage); 187 msg.getData().putLong(DATA_DURATION, durationMs); 188 msg.sendToTarget(); 189 } 190 191 @Override 192 public void revokeTrust() { 193 if (DEBUG) Slog.v(TAG, "revokeTrust()"); 194 mHandler.sendEmptyMessage(MSG_REVOKE_TRUST); 195 } 196 197 @Override 198 public void setManagingTrust(boolean managingTrust) { 199 if (DEBUG) Slog.v(TAG, "managingTrust()"); 200 mHandler.obtainMessage(MSG_MANAGING_TRUST, managingTrust ? 1 : 0, 0).sendToTarget(); 201 } 202 203 @Override 204 public void onSetTrustAgentFeaturesEnabledCompleted(boolean result, IBinder token) { 205 if (DEBUG) Slog.v(TAG, "onSetTrustAgentFeaturesEnabledCompleted(result=" + result); 206 mHandler.obtainMessage(MSG_SET_TRUST_AGENT_FEATURES_COMPLETED, 207 result ? 1 : 0, 0, token).sendToTarget(); 208 } 209 }; 210 211 private final ServiceConnection mConnection = new ServiceConnection() { 212 @Override 213 public void onServiceConnected(ComponentName name, IBinder service) { 214 if (DEBUG) Log.v(TAG, "TrustAgent started : " + name.flattenToString()); 215 mHandler.removeMessages(MSG_RESTART_TIMEOUT); 216 mTrustAgentService = ITrustAgentService.Stub.asInterface(service); 217 mTrustManagerService.mArchive.logAgentConnected(mUserId, name); 218 setCallback(mCallback); 219 updateDevicePolicyFeatures(); 220 } 221 222 @Override 223 public void onServiceDisconnected(ComponentName name) { 224 if (DEBUG) Log.v(TAG, "TrustAgent disconnected : " + name.flattenToShortString()); 225 mTrustAgentService = null; 226 mManagingTrust = false; 227 mSetTrustAgentFeaturesToken = null; 228 mTrustManagerService.mArchive.logAgentDied(mUserId, name); 229 mHandler.sendEmptyMessage(MSG_REVOKE_TRUST); 230 if (mBound) { 231 scheduleRestart(); 232 } 233 // mTrustDisabledByDpm maintains state 234 } 235 }; 236 237 public TrustAgentWrapper(Context context, TrustManagerService trustManagerService, 238 Intent intent, UserHandle user) { 239 mContext = context; 240 mTrustManagerService = trustManagerService; 241 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 242 mUserId = user.getIdentifier(); 243 mName = intent.getComponent(); 244 245 mAlarmIntent = new Intent(TRUST_EXPIRED_ACTION).putExtra(EXTRA_COMPONENT_NAME, mName); 246 mAlarmIntent.setData(Uri.parse(mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME))); 247 248 final IntentFilter alarmFilter = new IntentFilter(TRUST_EXPIRED_ACTION); 249 alarmFilter.addDataScheme(mAlarmIntent.getScheme()); 250 final String pathUri = mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME); 251 alarmFilter.addDataPath(pathUri, PatternMatcher.PATTERN_LITERAL); 252 mContext.registerReceiver(mBroadcastReceiver, alarmFilter); 253 254 // Schedules a restart for when connecting times out. If the connection succeeds, 255 // the restart is canceled in mCallback's onConnected. 256 scheduleRestart(); 257 mBound = context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, user); 258 if (!mBound) { 259 Log.e(TAG, "Can't bind to TrustAgent " + mName.flattenToShortString()); 260 } 261 } 262 263 private void onError(Exception e) { 264 Slog.w(TAG , "Remote Exception", e); 265 } 266 267 private void onTrustTimeout() { 268 try { 269 if (mTrustAgentService != null) mTrustAgentService.onTrustTimeout(); 270 } catch (RemoteException e) { 271 onError(e); 272 } 273 } 274 /** 275 * @see android.service.trust.TrustAgentService#onUnlockAttempt(boolean) 276 */ 277 public void onUnlockAttempt(boolean successful) { 278 try { 279 if (mTrustAgentService != null) mTrustAgentService.onUnlockAttempt(successful); 280 } catch (RemoteException e) { 281 onError(e); 282 } 283 } 284 285 private void setCallback(ITrustAgentServiceCallback callback) { 286 try { 287 if (mTrustAgentService != null) { 288 mTrustAgentService.setCallback(callback); 289 } 290 } catch (RemoteException e) { 291 onError(e); 292 } 293 } 294 295 boolean updateDevicePolicyFeatures() { 296 boolean trustDisabled = false; 297 if (DEBUG) Slog.v(TAG, "updateDevicePolicyFeatures(" + mName + ")"); 298 try { 299 if (mTrustAgentService != null) { 300 DevicePolicyManager dpm = 301 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 302 303 if ((dpm.getKeyguardDisabledFeatures(null) 304 & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0) { 305 List<String> features = dpm.getTrustAgentFeaturesEnabled(null, mName); 306 trustDisabled = true; 307 if (DEBUG) Slog.v(TAG, "Detected trust agents disabled. Features = " 308 + features); 309 if (features != null && features.size() > 0) { 310 Bundle bundle = new Bundle(); 311 bundle.putStringArrayList(TrustAgentService.KEY_FEATURES, 312 (ArrayList<String>)features); 313 if (DEBUG) { 314 Slog.v(TAG, "TrustAgent " + mName.flattenToShortString() 315 + " disabled until it acknowledges "+ features); 316 } 317 mSetTrustAgentFeaturesToken = new Binder(); 318 mTrustAgentService.setTrustAgentFeaturesEnabled(bundle, 319 mSetTrustAgentFeaturesToken); 320 } 321 } 322 } 323 } catch (RemoteException e) { 324 onError(e); 325 } 326 if (mTrustDisabledByDpm != trustDisabled) { 327 mTrustDisabledByDpm = trustDisabled; 328 mTrustManagerService.updateTrust(mUserId, false); 329 } 330 return trustDisabled; 331 } 332 333 public boolean isTrusted() { 334 return mTrusted && mManagingTrust && !mTrustDisabledByDpm; 335 } 336 337 public boolean isManagingTrust() { 338 return mManagingTrust && !mTrustDisabledByDpm; 339 } 340 341 public CharSequence getMessage() { 342 return mMessage; 343 } 344 345 public void unbind() { 346 if (!mBound) { 347 return; 348 } 349 if (DEBUG) Log.v(TAG, "TrustAgent unbound : " + mName.flattenToShortString()); 350 mTrustManagerService.mArchive.logAgentStopped(mUserId, mName); 351 mContext.unbindService(mConnection); 352 mBound = false; 353 mTrustAgentService = null; 354 mSetTrustAgentFeaturesToken = null; 355 mHandler.sendEmptyMessage(MSG_REVOKE_TRUST); 356 mHandler.removeMessages(MSG_RESTART_TIMEOUT); 357 } 358 359 public boolean isConnected() { 360 return mTrustAgentService != null; 361 } 362 363 public boolean isBound() { 364 return mBound; 365 } 366 367 /** 368 * If not connected, returns the time at which the agent is restarted. 369 * 370 * @return restart time in uptime millis. 371 */ 372 public long getScheduledRestartUptimeMillis() { 373 return mScheduledRestartUptimeMillis; 374 } 375 376 private void scheduleRestart() { 377 mHandler.removeMessages(MSG_RESTART_TIMEOUT); 378 mScheduledRestartUptimeMillis = SystemClock.uptimeMillis() + RESTART_TIMEOUT_MILLIS; 379 mHandler.sendEmptyMessageAtTime(MSG_RESTART_TIMEOUT, mScheduledRestartUptimeMillis); 380 } 381} 382