TrustManagerService.java revision c5f95cea2639b698594a85acbde6a5519941d7b1
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 com.android.internal.content.PackageMonitor; 20import com.android.internal.widget.LockPatternUtils; 21import com.android.server.SystemService; 22 23import org.xmlpull.v1.XmlPullParser; 24import org.xmlpull.v1.XmlPullParserException; 25 26import android.Manifest; 27import android.app.ActivityManagerNative; 28import android.app.admin.DevicePolicyManager; 29import android.app.trust.ITrustListener; 30import android.app.trust.ITrustManager; 31import android.content.BroadcastReceiver; 32import android.content.ComponentName; 33import android.content.Context; 34import android.content.Intent; 35import android.content.IntentFilter; 36import android.content.pm.PackageManager; 37import android.content.pm.ResolveInfo; 38import android.content.pm.UserInfo; 39import android.content.res.Resources; 40import android.content.res.TypedArray; 41import android.content.res.XmlResourceParser; 42import android.graphics.drawable.Drawable; 43import android.os.DeadObjectException; 44import android.os.Handler; 45import android.os.IBinder; 46import android.os.Message; 47import android.os.RemoteException; 48import android.os.SystemClock; 49import android.os.UserHandle; 50import android.os.UserManager; 51import android.service.trust.TrustAgentService; 52import android.util.ArraySet; 53import android.util.AttributeSet; 54import android.util.Log; 55import android.util.Slog; 56import android.util.SparseBooleanArray; 57import android.util.Xml; 58 59import java.io.FileDescriptor; 60import java.io.IOException; 61import java.io.PrintWriter; 62import java.util.ArrayList; 63import java.util.List; 64 65/** 66 * Manages trust agents and trust listeners. 67 * 68 * It is responsible for binding to the enabled {@link android.service.trust.TrustAgentService}s 69 * of each user and notifies them about events that are relevant to them. 70 * It start and stops them based on the value of 71 * {@link com.android.internal.widget.LockPatternUtils#getEnabledTrustAgents(int)}. 72 * 73 * It also keeps a set of {@link android.app.trust.ITrustListener}s that are notified whenever the 74 * trust state changes for any user. 75 * 76 * Trust state and the setting of enabled agents is kept per user and each user has its own 77 * instance of a {@link android.service.trust.TrustAgentService}. 78 */ 79public class TrustManagerService extends SystemService { 80 81 private static final boolean DEBUG = false; 82 private static final String TAG = "TrustManagerService"; 83 84 private static final Intent TRUST_AGENT_INTENT = 85 new Intent(TrustAgentService.SERVICE_INTERFACE); 86 private static final String PERMISSION_PROVIDE_AGENT = Manifest.permission.PROVIDE_TRUST_AGENT; 87 88 private static final int MSG_REGISTER_LISTENER = 1; 89 private static final int MSG_UNREGISTER_LISTENER = 2; 90 private static final int MSG_DISPATCH_UNLOCK_ATTEMPT = 3; 91 private static final int MSG_ENABLED_AGENTS_CHANGED = 4; 92 private static final int MSG_REQUIRE_CREDENTIAL_ENTRY = 5; 93 94 private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<AgentInfo>(); 95 private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<ITrustListener>(); 96 private final DevicePolicyReceiver mDevicePolicyReceiver = new DevicePolicyReceiver(); 97 private final SparseBooleanArray mUserHasAuthenticatedSinceBoot = new SparseBooleanArray(); 98 /* package */ final TrustArchive mArchive = new TrustArchive(); 99 private final Context mContext; 100 101 private UserManager mUserManager; 102 103 public TrustManagerService(Context context) { 104 super(context); 105 mContext = context; 106 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 107 } 108 109 @Override 110 public void onStart() { 111 publishBinderService(Context.TRUST_SERVICE, mService); 112 } 113 114 @Override 115 public void onBootPhase(int phase) { 116 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY && !isSafeMode()) { 117 mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true); 118 mDevicePolicyReceiver.register(mContext); 119 refreshAgentList(); 120 } 121 } 122 123 // Agent management 124 125 private static final class AgentInfo { 126 CharSequence label; 127 Drawable icon; 128 ComponentName component; // service that implements ITrustAgent 129 ComponentName settings; // setting to launch to modify agent. 130 TrustAgentWrapper agent; 131 int userId; 132 133 @Override 134 public boolean equals(Object other) { 135 if (!(other instanceof AgentInfo)) { 136 return false; 137 } 138 AgentInfo o = (AgentInfo) other; 139 return component.equals(o.component) && userId == o.userId; 140 } 141 142 @Override 143 public int hashCode() { 144 return component.hashCode() * 31 + userId; 145 } 146 } 147 148 private void updateTrustAll() { 149 List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */); 150 for (UserInfo userInfo : userInfos) { 151 updateTrust(userInfo.id); 152 } 153 } 154 155 public void updateTrust(int userId) { 156 dispatchOnTrustChanged(aggregateIsTrusted(userId), userId); 157 } 158 159 protected void refreshAgentList() { 160 if (DEBUG) Slog.d(TAG, "refreshAgentList()"); 161 PackageManager pm = mContext.getPackageManager(); 162 163 List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */); 164 LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext); 165 166 ArraySet<AgentInfo> obsoleteAgents = new ArraySet<>(); 167 obsoleteAgents.addAll(mActiveAgents); 168 169 for (UserInfo userInfo : userInfos) { 170 int disabledFeatures = lockPatternUtils.getDevicePolicyManager() 171 .getKeyguardDisabledFeatures(null, userInfo.id); 172 boolean disableTrustAgents = 173 (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0; 174 175 List<ComponentName> enabledAgents = lockPatternUtils.getEnabledTrustAgents(userInfo.id); 176 if (disableTrustAgents || enabledAgents == null) { 177 continue; 178 } 179 List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(TRUST_AGENT_INTENT, 180 PackageManager.GET_META_DATA, userInfo.id); 181 for (ResolveInfo resolveInfo : resolveInfos) { 182 if (resolveInfo.serviceInfo == null) continue; 183 184 String packageName = resolveInfo.serviceInfo.packageName; 185 if (pm.checkPermission(PERMISSION_PROVIDE_AGENT, packageName) 186 != PackageManager.PERMISSION_GRANTED) { 187 Log.w(TAG, "Skipping agent because package " + packageName 188 + " does not have permission " + PERMISSION_PROVIDE_AGENT + "."); 189 continue; 190 } 191 192 ComponentName name = getComponentName(resolveInfo); 193 if (!enabledAgents.contains(name)) continue; 194 195 AgentInfo agentInfo = new AgentInfo(); 196 agentInfo.component = name; 197 agentInfo.userId = userInfo.id; 198 if (!mActiveAgents.contains(agentInfo)) { 199 agentInfo.label = resolveInfo.loadLabel(pm); 200 agentInfo.icon = resolveInfo.loadIcon(pm); 201 agentInfo.settings = getSettingsComponentName(pm, resolveInfo); 202 agentInfo.agent = new TrustAgentWrapper(mContext, this, 203 new Intent().setComponent(name), userInfo.getUserHandle()); 204 mActiveAgents.add(agentInfo); 205 } else { 206 obsoleteAgents.remove(agentInfo); 207 } 208 } 209 } 210 211 boolean trustMayHaveChanged = false; 212 for (int i = 0; i < obsoleteAgents.size(); i++) { 213 AgentInfo info = obsoleteAgents.valueAt(i); 214 if (info.agent.isTrusted()) { 215 trustMayHaveChanged = true; 216 } 217 info.agent.unbind(); 218 mActiveAgents.remove(info); 219 } 220 221 if (trustMayHaveChanged) { 222 updateTrustAll(); 223 } 224 } 225 226 private void removeAgentsOfPackage(String packageName) { 227 boolean trustMayHaveChanged = false; 228 for (int i = mActiveAgents.size() - 1; i >= 0; i--) { 229 AgentInfo info = mActiveAgents.valueAt(i); 230 if (packageName.equals(info.component.getPackageName())) { 231 Log.i(TAG, "Resetting agent " + info.component.flattenToShortString()); 232 if (info.agent.isTrusted()) { 233 trustMayHaveChanged = true; 234 } 235 info.agent.unbind(); 236 mActiveAgents.removeAt(i); 237 } 238 } 239 if (trustMayHaveChanged) { 240 updateTrustAll(); 241 } 242 } 243 244 public void resetAgent(ComponentName name, int userId) { 245 boolean trustMayHaveChanged = false; 246 for (int i = mActiveAgents.size() - 1; i >= 0; i--) { 247 AgentInfo info = mActiveAgents.valueAt(i); 248 if (name.equals(info.component) && userId == info.userId) { 249 Log.i(TAG, "Resetting agent " + info.component.flattenToShortString()); 250 if (info.agent.isTrusted()) { 251 trustMayHaveChanged = true; 252 } 253 info.agent.unbind(); 254 mActiveAgents.removeAt(i); 255 } 256 } 257 if (trustMayHaveChanged) { 258 updateTrust(userId); 259 } 260 refreshAgentList(); 261 } 262 263 private ComponentName getSettingsComponentName(PackageManager pm, ResolveInfo resolveInfo) { 264 if (resolveInfo == null || resolveInfo.serviceInfo == null 265 || resolveInfo.serviceInfo.metaData == null) return null; 266 String cn = null; 267 XmlResourceParser parser = null; 268 Exception caughtException = null; 269 try { 270 parser = resolveInfo.serviceInfo.loadXmlMetaData(pm, 271 TrustAgentService.TRUST_AGENT_META_DATA); 272 if (parser == null) { 273 Slog.w(TAG, "Can't find " + TrustAgentService.TRUST_AGENT_META_DATA + " meta-data"); 274 return null; 275 } 276 Resources res = pm.getResourcesForApplication(resolveInfo.serviceInfo.applicationInfo); 277 AttributeSet attrs = Xml.asAttributeSet(parser); 278 int type; 279 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 280 && type != XmlPullParser.START_TAG) { 281 // Drain preamble. 282 } 283 String nodeName = parser.getName(); 284 if (!"trust-agent".equals(nodeName)) { 285 Slog.w(TAG, "Meta-data does not start with trust-agent tag"); 286 return null; 287 } 288 TypedArray sa = res 289 .obtainAttributes(attrs, com.android.internal.R.styleable.TrustAgent); 290 cn = sa.getString(com.android.internal.R.styleable.TrustAgent_settingsActivity); 291 sa.recycle(); 292 } catch (PackageManager.NameNotFoundException e) { 293 caughtException = e; 294 } catch (IOException e) { 295 caughtException = e; 296 } catch (XmlPullParserException e) { 297 caughtException = e; 298 } finally { 299 if (parser != null) parser.close(); 300 } 301 if (caughtException != null) { 302 Slog.w(TAG, "Error parsing : " + resolveInfo.serviceInfo.packageName, caughtException); 303 return null; 304 } 305 if (cn == null) { 306 return null; 307 } 308 if (cn.indexOf('/') < 0) { 309 cn = resolveInfo.serviceInfo.packageName + "/" + cn; 310 } 311 return ComponentName.unflattenFromString(cn); 312 } 313 314 private ComponentName getComponentName(ResolveInfo resolveInfo) { 315 if (resolveInfo == null || resolveInfo.serviceInfo == null) return null; 316 return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name); 317 } 318 319 // Agent dispatch and aggregation 320 321 private boolean aggregateIsTrusted(int userId) { 322 if (!mUserHasAuthenticatedSinceBoot.get(userId)) { 323 return false; 324 } 325 for (int i = 0; i < mActiveAgents.size(); i++) { 326 AgentInfo info = mActiveAgents.valueAt(i); 327 if (info.userId == userId) { 328 if (info.agent.isTrusted()) { 329 return true; 330 } 331 } 332 } 333 return false; 334 } 335 336 private void dispatchUnlockAttempt(boolean successful, int userId) { 337 for (int i = 0; i < mActiveAgents.size(); i++) { 338 AgentInfo info = mActiveAgents.valueAt(i); 339 if (info.userId == userId) { 340 info.agent.onUnlockAttempt(successful); 341 } 342 } 343 344 if (successful && !mUserHasAuthenticatedSinceBoot.get(userId)) { 345 mUserHasAuthenticatedSinceBoot.put(userId, true); 346 updateTrust(userId); 347 } 348 } 349 350 351 private void requireCredentialEntry(int userId) { 352 if (userId == UserHandle.USER_ALL) { 353 mUserHasAuthenticatedSinceBoot.clear(); 354 updateTrustAll(); 355 } else { 356 mUserHasAuthenticatedSinceBoot.put(userId, false); 357 updateTrust(userId); 358 } 359 } 360 361 // Listeners 362 363 private void addListener(ITrustListener listener) { 364 for (int i = 0; i < mTrustListeners.size(); i++) { 365 if (mTrustListeners.get(i).asBinder() == listener.asBinder()) { 366 return; 367 } 368 } 369 mTrustListeners.add(listener); 370 } 371 372 private void removeListener(ITrustListener listener) { 373 for (int i = 0; i < mTrustListeners.size(); i++) { 374 if (mTrustListeners.get(i).asBinder() == listener.asBinder()) { 375 mTrustListeners.get(i); 376 return; 377 } 378 } 379 } 380 381 private void dispatchOnTrustChanged(boolean enabled, int userId) { 382 for (int i = 0; i < mTrustListeners.size(); i++) { 383 try { 384 mTrustListeners.get(i).onTrustChanged(enabled, userId); 385 } catch (DeadObjectException e) { 386 if (DEBUG) Slog.d(TAG, "Removing dead TrustListener."); 387 mTrustListeners.remove(i); 388 i--; 389 } catch (RemoteException e) { 390 Slog.e(TAG, "Exception while notifying TrustListener.", e); 391 } 392 } 393 } 394 395 // Plumbing 396 397 private final IBinder mService = new ITrustManager.Stub() { 398 @Override 399 public void reportUnlockAttempt(boolean authenticated, int userId) throws RemoteException { 400 enforceReportPermission(); 401 mHandler.obtainMessage(MSG_DISPATCH_UNLOCK_ATTEMPT, authenticated ? 1 : 0, userId) 402 .sendToTarget(); 403 } 404 405 @Override 406 public void reportEnabledTrustAgentsChanged(int userId) throws RemoteException { 407 enforceReportPermission(); 408 // coalesce refresh messages. 409 mHandler.removeMessages(MSG_ENABLED_AGENTS_CHANGED); 410 mHandler.sendEmptyMessage(MSG_ENABLED_AGENTS_CHANGED); 411 } 412 413 @Override 414 public void reportRequireCredentialEntry(int userId) throws RemoteException { 415 enforceReportPermission(); 416 if (userId == UserHandle.USER_ALL || userId >= UserHandle.USER_OWNER) { 417 mHandler.obtainMessage(MSG_REQUIRE_CREDENTIAL_ENTRY, userId, 0).sendToTarget(); 418 } else { 419 throw new IllegalArgumentException( 420 "userId must be an explicit user id or USER_ALL"); 421 } 422 } 423 424 @Override 425 public void registerTrustListener(ITrustListener trustListener) throws RemoteException { 426 enforceListenerPermission(); 427 mHandler.obtainMessage(MSG_REGISTER_LISTENER, trustListener).sendToTarget(); 428 } 429 430 @Override 431 public void unregisterTrustListener(ITrustListener trustListener) throws RemoteException { 432 enforceListenerPermission(); 433 mHandler.obtainMessage(MSG_UNREGISTER_LISTENER, trustListener).sendToTarget(); 434 } 435 436 private void enforceReportPermission() { 437 mContext.enforceCallingOrSelfPermission( 438 Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, "reporting trust events"); 439 } 440 441 private void enforceListenerPermission() { 442 mContext.enforceCallingPermission(Manifest.permission.TRUST_LISTENER, 443 "register trust listener"); 444 } 445 446 @Override 447 protected void dump(FileDescriptor fd, final PrintWriter fout, String[] args) { 448 mContext.enforceCallingPermission(Manifest.permission.DUMP, 449 "dumping TrustManagerService"); 450 final UserInfo currentUser; 451 final List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */); 452 try { 453 currentUser = ActivityManagerNative.getDefault().getCurrentUser(); 454 } catch (RemoteException e) { 455 throw new RuntimeException(e); 456 } 457 mHandler.runWithScissors(new Runnable() { 458 @Override 459 public void run() { 460 fout.println("Trust manager state:"); 461 for (UserInfo user : userInfos) { 462 dumpUser(fout, user, user.id == currentUser.id); 463 } 464 } 465 }, 1500); 466 } 467 468 private void dumpUser(PrintWriter fout, UserInfo user, boolean isCurrent) { 469 fout.printf(" User \"%s\" (id=%d, flags=%#x)", 470 user.name, user.id, user.flags); 471 if (isCurrent) { 472 fout.print(" (current)"); 473 } 474 fout.print(": trusted=" + dumpBool(aggregateIsTrusted(user.id))); 475 fout.println(); 476 fout.println(" Enabled agents:"); 477 boolean duplicateSimpleNames = false; 478 ArraySet<String> simpleNames = new ArraySet<String>(); 479 for (AgentInfo info : mActiveAgents) { 480 if (info.userId != user.id) { continue; } 481 boolean trusted = info.agent.isTrusted(); 482 fout.print(" "); fout.println(info.component.flattenToShortString()); 483 fout.print(" bound=" + dumpBool(info.agent.isBound())); 484 fout.print(", connected=" + dumpBool(info.agent.isConnected())); 485 fout.println(", trusted=" + dumpBool(trusted)); 486 if (trusted) { 487 fout.println(" message=\"" + info.agent.getMessage() + "\""); 488 } 489 if (!info.agent.isConnected()) { 490 String restartTime = TrustArchive.formatDuration( 491 info.agent.getScheduledRestartUptimeMillis() 492 - SystemClock.uptimeMillis()); 493 fout.println(" restartScheduledAt=" + restartTime); 494 } 495 if (!simpleNames.add(TrustArchive.getSimpleName(info.component))) { 496 duplicateSimpleNames = true; 497 } 498 } 499 fout.println(" Events:"); 500 mArchive.dump(fout, 50, user.id, " " /* linePrefix */, duplicateSimpleNames); 501 fout.println(); 502 } 503 504 private String dumpBool(boolean b) { 505 return b ? "1" : "0"; 506 } 507 }; 508 509 private final Handler mHandler = new Handler() { 510 @Override 511 public void handleMessage(Message msg) { 512 switch (msg.what) { 513 case MSG_REGISTER_LISTENER: 514 addListener((ITrustListener) msg.obj); 515 break; 516 case MSG_UNREGISTER_LISTENER: 517 removeListener((ITrustListener) msg.obj); 518 break; 519 case MSG_DISPATCH_UNLOCK_ATTEMPT: 520 dispatchUnlockAttempt(msg.arg1 != 0, msg.arg2); 521 break; 522 case MSG_ENABLED_AGENTS_CHANGED: 523 refreshAgentList(); 524 break; 525 case MSG_REQUIRE_CREDENTIAL_ENTRY: 526 requireCredentialEntry(msg.arg1); 527 break; 528 } 529 } 530 }; 531 532 private final PackageMonitor mPackageMonitor = new PackageMonitor() { 533 @Override 534 public void onSomePackagesChanged() { 535 refreshAgentList(); 536 } 537 538 @Override 539 public boolean onPackageChanged(String packageName, int uid, String[] components) { 540 // We're interested in all changes, even if just some components get enabled / disabled. 541 return true; 542 } 543 544 @Override 545 public void onPackageDisappeared(String packageName, int reason) { 546 removeAgentsOfPackage(packageName); 547 } 548 }; 549 550 private class DevicePolicyReceiver extends BroadcastReceiver { 551 552 @Override 553 public void onReceive(Context context, Intent intent) { 554 if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals( 555 intent.getAction())) { 556 refreshAgentList(); 557 } 558 } 559 560 public void register(Context context) { 561 context.registerReceiverAsUser(this, 562 UserHandle.ALL, 563 new IntentFilter( 564 DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), 565 null /* permission */, 566 null /* scheduler */); 567 } 568 } 569} 570