TrustAgentWrapper.java revision 8f21158fe64eb93ff005dc1b831b282b95531023
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.admin.DevicePolicyManager; 20import android.content.ComponentName; 21import android.content.Context; 22import android.content.Intent; 23import android.content.ServiceConnection; 24import android.os.Binder; 25import android.os.Bundle; 26import android.os.Handler; 27import android.os.IBinder; 28import android.os.Message; 29import android.os.RemoteException; 30import android.os.SystemClock; 31import android.os.UserHandle; 32import android.util.Log; 33import android.util.Slog; 34import android.service.trust.ITrustAgentService; 35import android.service.trust.ITrustAgentServiceCallback; 36import android.service.trust.TrustAgentService; 37 38import java.util.ArrayList; 39import java.util.List; 40 41/** 42 * A wrapper around a TrustAgentService interface. Coordinates communication between 43 * TrustManager and the actual TrustAgent. 44 */ 45public class TrustAgentWrapper { 46 private static final boolean DEBUG = false; 47 private static final String TAG = "TrustAgentWrapper"; 48 49 private static final int MSG_GRANT_TRUST = 1; 50 private static final int MSG_REVOKE_TRUST = 2; 51 private static final int MSG_TRUST_TIMEOUT = 3; 52 private static final int MSG_RESTART_TIMEOUT = 4; 53 private static final int MSG_SET_TRUST_AGENT_FEATURES_COMPLETED = 5; 54 private static final int MSG_MANAGING_TRUST = 6; 55 56 /** 57 * Time in uptime millis that we wait for the service connection, both when starting 58 * and when the service disconnects. 59 */ 60 private static final long RESTART_TIMEOUT_MILLIS = 5 * 60000; 61 62 /** 63 * Long extra for {@link #MSG_GRANT_TRUST} 64 */ 65 private static final String DATA_DURATION = "duration"; 66 67 private final TrustManagerService mTrustManagerService; 68 private final int mUserId; 69 private final Context mContext; 70 private final ComponentName mName; 71 72 private ITrustAgentService mTrustAgentService; 73 private boolean mBound; 74 private long mScheduledRestartUptimeMillis; 75 76 // Trust state 77 private boolean mTrusted; 78 private CharSequence mMessage; 79 private boolean mTrustDisabledByDpm; 80 private boolean mManagingTrust; 81 private IBinder mSetTrustAgentFeaturesToken; 82 83 private final Handler mHandler = new Handler() { 84 @Override 85 public void handleMessage(Message msg) { 86 switch (msg.what) { 87 case MSG_GRANT_TRUST: 88 if (!isConnected()) { 89 Log.w(TAG, "Agent is not connected, cannot grant trust: " 90 + mName.flattenToShortString()); 91 return; 92 } 93 mTrusted = true; 94 mMessage = (CharSequence) msg.obj; 95 boolean initiatedByUser = msg.arg1 != 0; 96 // TODO: Handle initiatedByUser. 97 long durationMs = msg.getData().getLong(DATA_DURATION); 98 if (durationMs > 0) { 99 mHandler.removeMessages(MSG_TRUST_TIMEOUT); 100 mHandler.sendEmptyMessageDelayed(MSG_TRUST_TIMEOUT, durationMs); 101 } 102 mTrustManagerService.mArchive.logGrantTrust(mUserId, mName, 103 (mMessage != null ? mMessage.toString() : null), 104 durationMs, initiatedByUser); 105 mTrustManagerService.updateTrust(mUserId); 106 break; 107 case MSG_TRUST_TIMEOUT: 108 if (DEBUG) Slog.v(TAG, "Trust timed out : " + mName.flattenToShortString()); 109 mTrustManagerService.mArchive.logTrustTimeout(mUserId, mName); 110 // Fall through. 111 case MSG_REVOKE_TRUST: 112 mTrusted = false; 113 mMessage = null; 114 mHandler.removeMessages(MSG_TRUST_TIMEOUT); 115 if (msg.what == MSG_REVOKE_TRUST) { 116 mTrustManagerService.mArchive.logRevokeTrust(mUserId, mName); 117 } 118 mTrustManagerService.updateTrust(mUserId); 119 break; 120 case MSG_RESTART_TIMEOUT: 121 unbind(); 122 mTrustManagerService.resetAgent(mName, mUserId); 123 break; 124 case MSG_SET_TRUST_AGENT_FEATURES_COMPLETED: 125 IBinder token = (IBinder) msg.obj; 126 boolean result = msg.arg1 != 0; 127 if (mSetTrustAgentFeaturesToken == token) { 128 mSetTrustAgentFeaturesToken = null; 129 if (mTrustDisabledByDpm && result) { 130 if (DEBUG) Log.v(TAG, "Re-enabling agent because it acknowledged " 131 + "enabled features: " + mName); 132 mTrustDisabledByDpm = false; 133 mTrustManagerService.updateTrust(mUserId); 134 } 135 } else { 136 if (DEBUG) Log.w(TAG, "Ignoring MSG_SET_TRUST_AGENT_FEATURES_COMPLETED " 137 + "with obsolete token: " + mName); 138 } 139 break; 140 case MSG_MANAGING_TRUST: 141 mManagingTrust = msg.arg1 != 0; 142 if (!mManagingTrust) { 143 mTrusted = false; 144 mMessage = null; 145 } 146 mTrustManagerService.mArchive.logManagingTrust(mUserId, mName, mManagingTrust); 147 mTrustManagerService.updateTrust(mUserId); 148 break; 149 } 150 } 151 }; 152 153 private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() { 154 155 @Override 156 public void grantTrust(CharSequence userMessage, long durationMs, boolean initiatedByUser) { 157 if (DEBUG) Slog.v(TAG, "enableTrust(" + userMessage + ", durationMs = " + durationMs 158 + ", initiatedByUser = " + initiatedByUser + ")"); 159 160 Message msg = mHandler.obtainMessage( 161 MSG_GRANT_TRUST, initiatedByUser ? 1 : 0, 0, userMessage); 162 msg.getData().putLong(DATA_DURATION, durationMs); 163 msg.sendToTarget(); 164 } 165 166 @Override 167 public void revokeTrust() { 168 if (DEBUG) Slog.v(TAG, "revokeTrust()"); 169 mHandler.sendEmptyMessage(MSG_REVOKE_TRUST); 170 } 171 172 @Override 173 public void setManagingTrust(boolean managingTrust) { 174 if (DEBUG) Slog.v(TAG, "managingTrust()"); 175 mHandler.obtainMessage(MSG_MANAGING_TRUST, managingTrust ? 1 : 0, 0).sendToTarget(); 176 } 177 178 @Override 179 public void onSetTrustAgentFeaturesEnabledCompleted(boolean result, IBinder token) { 180 if (DEBUG) Slog.v(TAG, "onSetTrustAgentFeaturesEnabledCompleted(result=" + result); 181 mHandler.obtainMessage(MSG_SET_TRUST_AGENT_FEATURES_COMPLETED, 182 result ? 1 : 0, 0, token).sendToTarget(); 183 } 184 }; 185 186 private final ServiceConnection mConnection = new ServiceConnection() { 187 @Override 188 public void onServiceConnected(ComponentName name, IBinder service) { 189 if (DEBUG) Log.v(TAG, "TrustAgent started : " + name.flattenToString()); 190 mHandler.removeMessages(MSG_RESTART_TIMEOUT); 191 mTrustAgentService = ITrustAgentService.Stub.asInterface(service); 192 mTrustManagerService.mArchive.logAgentConnected(mUserId, name); 193 setCallback(mCallback); 194 updateDevicePolicyFeatures(); 195 } 196 197 @Override 198 public void onServiceDisconnected(ComponentName name) { 199 if (DEBUG) Log.v(TAG, "TrustAgent disconnected : " + name.flattenToShortString()); 200 mTrustAgentService = null; 201 mManagingTrust = false; 202 mSetTrustAgentFeaturesToken = null; 203 mTrustManagerService.mArchive.logAgentDied(mUserId, name); 204 mHandler.sendEmptyMessage(MSG_REVOKE_TRUST); 205 if (mBound) { 206 scheduleRestart(); 207 } 208 // mTrustDisabledByDpm maintains state 209 } 210 }; 211 212 public TrustAgentWrapper(Context context, TrustManagerService trustManagerService, 213 Intent intent, UserHandle user) { 214 mContext = context; 215 mTrustManagerService = trustManagerService; 216 mUserId = user.getIdentifier(); 217 mName = intent.getComponent(); 218 // Schedules a restart for when connecting times out. If the connection succeeds, 219 // the restart is canceled in mCallback's onConnected. 220 scheduleRestart(); 221 mBound = context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, user); 222 if (!mBound) { 223 Log.e(TAG, "Can't bind to TrustAgent " + mName.flattenToShortString()); 224 } 225 } 226 227 private void onError(Exception e) { 228 Slog.w(TAG , "Remote Exception", e); 229 } 230 231 /** 232 * @see android.service.trust.TrustAgentService#onUnlockAttempt(boolean) 233 */ 234 public void onUnlockAttempt(boolean successful) { 235 try { 236 if (mTrustAgentService != null) mTrustAgentService.onUnlockAttempt(successful); 237 } catch (RemoteException e) { 238 onError(e); 239 } 240 } 241 242 private void setCallback(ITrustAgentServiceCallback callback) { 243 try { 244 if (mTrustAgentService != null) { 245 mTrustAgentService.setCallback(callback); 246 } 247 } catch (RemoteException e) { 248 onError(e); 249 } 250 } 251 252 boolean updateDevicePolicyFeatures() { 253 boolean trustDisabled = false; 254 if (DEBUG) Slog.v(TAG, "updateDevicePolicyFeatures(" + mName + ")"); 255 try { 256 if (mTrustAgentService != null) { 257 DevicePolicyManager dpm = 258 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 259 260 if ((dpm.getKeyguardDisabledFeatures(null) 261 & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0) { 262 List<String> features = dpm.getTrustAgentFeaturesEnabled(null, mName); 263 trustDisabled = true; 264 if (DEBUG) Slog.v(TAG, "Detected trust agents disabled. Features = " 265 + features); 266 if (features != null && features.size() > 0) { 267 Bundle bundle = new Bundle(); 268 bundle.putStringArrayList(TrustAgentService.KEY_FEATURES, 269 (ArrayList<String>)features); 270 if (DEBUG) { 271 Slog.v(TAG, "TrustAgent " + mName.flattenToShortString() 272 + " disabled until it acknowledges "+ features); 273 } 274 mSetTrustAgentFeaturesToken = new Binder(); 275 mTrustAgentService.setTrustAgentFeaturesEnabled(bundle, 276 mSetTrustAgentFeaturesToken); 277 } 278 } 279 } 280 } catch (RemoteException e) { 281 onError(e); 282 } 283 if (mTrustDisabledByDpm != trustDisabled) { 284 mTrustDisabledByDpm = trustDisabled; 285 mTrustManagerService.updateTrust(mUserId); 286 } 287 return trustDisabled; 288 } 289 290 public boolean isTrusted() { 291 return mTrusted && mManagingTrust && !mTrustDisabledByDpm; 292 } 293 294 public boolean isManagingTrust() { 295 return mManagingTrust && !mTrustDisabledByDpm; 296 } 297 298 public CharSequence getMessage() { 299 return mMessage; 300 } 301 302 public void unbind() { 303 if (!mBound) { 304 return; 305 } 306 if (DEBUG) Log.v(TAG, "TrustAgent unbound : " + mName.flattenToShortString()); 307 mTrustManagerService.mArchive.logAgentStopped(mUserId, mName); 308 mContext.unbindService(mConnection); 309 mBound = false; 310 mTrustAgentService = null; 311 mSetTrustAgentFeaturesToken = null; 312 mHandler.sendEmptyMessage(MSG_REVOKE_TRUST); 313 mHandler.removeMessages(MSG_RESTART_TIMEOUT); 314 } 315 316 public boolean isConnected() { 317 return mTrustAgentService != null; 318 } 319 320 public boolean isBound() { 321 return mBound; 322 } 323 324 /** 325 * If not connected, returns the time at which the agent is restarted. 326 * 327 * @return restart time in uptime millis. 328 */ 329 public long getScheduledRestartUptimeMillis() { 330 return mScheduledRestartUptimeMillis; 331 } 332 333 private void scheduleRestart() { 334 mHandler.removeMessages(MSG_RESTART_TIMEOUT); 335 mScheduledRestartUptimeMillis = SystemClock.uptimeMillis() + RESTART_TIMEOUT_MILLIS; 336 mHandler.sendEmptyMessageAtTime(MSG_RESTART_TIMEOUT, mScheduledRestartUptimeMillis); 337 } 338} 339