TrustManagerService.java revision a4ba56ba879b83e2866c31b4eb395d38302a1769
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.admin.DevicePolicyManager; 28import android.app.trust.ITrustListener; 29import android.app.trust.ITrustManager; 30import android.content.BroadcastReceiver; 31import android.content.ComponentName; 32import android.content.Context; 33import android.content.Intent; 34import android.content.IntentFilter; 35import android.content.pm.PackageManager; 36import android.content.pm.ResolveInfo; 37import android.content.pm.UserInfo; 38import android.content.res.Resources; 39import android.content.res.TypedArray; 40import android.content.res.XmlResourceParser; 41import android.graphics.drawable.Drawable; 42import android.os.DeadObjectException; 43import android.os.Handler; 44import android.os.IBinder; 45import android.os.Message; 46import android.os.RemoteException; 47import android.os.UserHandle; 48import android.os.UserManager; 49import android.service.trust.TrustAgentService; 50import android.util.ArraySet; 51import android.util.AttributeSet; 52import android.util.Slog; 53import android.util.SparseBooleanArray; 54import android.util.Xml; 55 56import java.io.IOException; 57import java.util.ArrayList; 58import java.util.List; 59 60/** 61 * Manages trust agents and trust listeners. 62 * 63 * It is responsible for binding to the enabled {@link android.service.trust.TrustAgentService}s 64 * of each user and notifies them about events that are relevant to them. 65 * It start and stops them based on the value of 66 * {@link com.android.internal.widget.LockPatternUtils#getEnabledTrustAgents(int)}. 67 * 68 * It also keeps a set of {@link android.app.trust.ITrustListener}s that are notified whenever the 69 * trust state changes for any user. 70 * 71 * Trust state and the setting of enabled agents is kept per user and each user has its own 72 * instance of a {@link android.service.trust.TrustAgentService}. 73 */ 74public class TrustManagerService extends SystemService { 75 76 private static final boolean DEBUG = false; 77 private static final String TAG = "TrustManagerService"; 78 79 private static final Intent TRUST_AGENT_INTENT = 80 new Intent(TrustAgentService.SERVICE_INTERFACE); 81 82 private static final int MSG_REGISTER_LISTENER = 1; 83 private static final int MSG_UNREGISTER_LISTENER = 2; 84 private static final int MSG_DISPATCH_UNLOCK_ATTEMPT = 3; 85 private static final int MSG_ENABLED_AGENTS_CHANGED = 4; 86 87 private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<AgentInfo>(); 88 private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<ITrustListener>(); 89 private final DevicePolicyReceiver mDevicePolicyReceiver = new DevicePolicyReceiver(); 90 private final SparseBooleanArray mUserHasAuthenticatedSinceBoot = new SparseBooleanArray(); 91 private final Context mContext; 92 93 private UserManager mUserManager; 94 95 /** 96 * Cache for {@link #refreshAgentList()} 97 */ 98 private final ArraySet<AgentInfo> mObsoleteAgents = new ArraySet<AgentInfo>(); 99 100 101 public TrustManagerService(Context context) { 102 super(context); 103 mContext = context; 104 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 105 } 106 107 @Override 108 public void onStart() { 109 publishBinderService(Context.TRUST_SERVICE, mService); 110 } 111 112 @Override 113 public void onBootPhase(int phase) { 114 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY && !isSafeMode()) { 115 mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true); 116 mDevicePolicyReceiver.register(mContext); 117 refreshAgentList(); 118 } 119 } 120 121 // Agent management 122 123 private static final class AgentInfo { 124 CharSequence label; 125 Drawable icon; 126 ComponentName component; // service that implements ITrustAgent 127 ComponentName settings; // setting to launch to modify agent. 128 TrustAgentWrapper agent; 129 int userId; 130 131 @Override 132 public boolean equals(Object other) { 133 if (!(other instanceof AgentInfo)) { 134 return false; 135 } 136 AgentInfo o = (AgentInfo) other; 137 return component.equals(o.component) && userId == o.userId; 138 } 139 140 @Override 141 public int hashCode() { 142 return component.hashCode() * 31 + userId; 143 } 144 } 145 146 private void updateTrustAll() { 147 List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */); 148 for (UserInfo userInfo : userInfos) { 149 updateTrust(userInfo.id); 150 } 151 } 152 153 public void updateTrust(int userId) { 154 dispatchOnTrustChanged(aggregateIsTrusted(userId), userId); 155 } 156 157 protected void refreshAgentList() { 158 if (DEBUG) Slog.d(TAG, "refreshAgentList()"); 159 PackageManager pm = mContext.getPackageManager(); 160 161 List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */); 162 LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext); 163 164 mObsoleteAgents.clear(); 165 mObsoleteAgents.addAll(mActiveAgents); 166 167 for (UserInfo userInfo : userInfos) { 168 int disabledFeatures = lockPatternUtils.getDevicePolicyManager() 169 .getKeyguardDisabledFeatures(null, userInfo.id); 170 boolean disableTrustAgents = 171 (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0; 172 173 List<ComponentName> enabledAgents = lockPatternUtils.getEnabledTrustAgents(userInfo.id); 174 if (disableTrustAgents || enabledAgents == null) { 175 continue; 176 } 177 List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(TRUST_AGENT_INTENT, 178 PackageManager.GET_META_DATA, userInfo.id); 179 for (ResolveInfo resolveInfo : resolveInfos) { 180 if (resolveInfo.serviceInfo == null) continue; 181 ComponentName name = getComponentName(resolveInfo); 182 if (!enabledAgents.contains(name)) continue; 183 184 AgentInfo agentInfo = new AgentInfo(); 185 agentInfo.component = name; 186 agentInfo.userId = userInfo.id; 187 if (!mActiveAgents.contains(agentInfo)) { 188 agentInfo.label = resolveInfo.loadLabel(pm); 189 agentInfo.icon = resolveInfo.loadIcon(pm); 190 agentInfo.settings = getSettingsComponentName(pm, resolveInfo); 191 agentInfo.agent = new TrustAgentWrapper(mContext, this, 192 new Intent().setComponent(name), userInfo.getUserHandle()); 193 mActiveAgents.add(agentInfo); 194 } else { 195 mObsoleteAgents.remove(agentInfo); 196 } 197 } 198 } 199 200 boolean trustMayHaveChanged = false; 201 for (int i = 0; i < mObsoleteAgents.size(); i++) { 202 AgentInfo info = mObsoleteAgents.valueAt(i); 203 if (info.agent.isTrusted()) { 204 trustMayHaveChanged = true; 205 } 206 info.agent.unbind(); 207 mActiveAgents.remove(info); 208 } 209 210 if (trustMayHaveChanged) { 211 updateTrustAll(); 212 } 213 } 214 215 private ComponentName getSettingsComponentName(PackageManager pm, ResolveInfo resolveInfo) { 216 if (resolveInfo == null || resolveInfo.serviceInfo == null 217 || resolveInfo.serviceInfo.metaData == null) return null; 218 String cn = null; 219 XmlResourceParser parser = null; 220 Exception caughtException = null; 221 try { 222 parser = resolveInfo.serviceInfo.loadXmlMetaData(pm, 223 TrustAgentService.TRUST_AGENT_META_DATA); 224 if (parser == null) { 225 Slog.w(TAG, "Can't find " + TrustAgentService.TRUST_AGENT_META_DATA + " meta-data"); 226 return null; 227 } 228 Resources res = pm.getResourcesForApplication(resolveInfo.serviceInfo.applicationInfo); 229 AttributeSet attrs = Xml.asAttributeSet(parser); 230 int type; 231 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 232 && type != XmlPullParser.START_TAG) { 233 // Drain preamble. 234 } 235 String nodeName = parser.getName(); 236 if (!"trust-agent".equals(nodeName)) { 237 Slog.w(TAG, "Meta-data does not start with trust-agent tag"); 238 return null; 239 } 240 TypedArray sa = res 241 .obtainAttributes(attrs, com.android.internal.R.styleable.TrustAgent); 242 cn = sa.getString(com.android.internal.R.styleable.TrustAgent_settingsActivity); 243 sa.recycle(); 244 } catch (PackageManager.NameNotFoundException e) { 245 caughtException = e; 246 } catch (IOException e) { 247 caughtException = e; 248 } catch (XmlPullParserException e) { 249 caughtException = e; 250 } finally { 251 if (parser != null) parser.close(); 252 } 253 if (caughtException != null) { 254 Slog.w(TAG, "Error parsing : " + resolveInfo.serviceInfo.packageName, caughtException); 255 return null; 256 } 257 if (cn == null) { 258 return null; 259 } 260 if (cn.indexOf('/') < 0) { 261 cn = resolveInfo.serviceInfo.packageName + "/" + cn; 262 } 263 return ComponentName.unflattenFromString(cn); 264 } 265 266 private ComponentName getComponentName(ResolveInfo resolveInfo) { 267 if (resolveInfo == null || resolveInfo.serviceInfo == null) return null; 268 return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name); 269 } 270 271 // Agent dispatch and aggregation 272 273 private boolean aggregateIsTrusted(int userId) { 274 if (!mUserHasAuthenticatedSinceBoot.get(userId)) { 275 return false; 276 } 277 for (int i = 0; i < mActiveAgents.size(); i++) { 278 AgentInfo info = mActiveAgents.valueAt(i); 279 if (info.userId == userId) { 280 if (info.agent.isTrusted()) { 281 return true; 282 } 283 } 284 } 285 return false; 286 } 287 288 private void dispatchUnlockAttempt(boolean successful, int userId) { 289 for (int i = 0; i < mActiveAgents.size(); i++) { 290 AgentInfo info = mActiveAgents.valueAt(i); 291 if (info.userId == userId) { 292 info.agent.onUnlockAttempt(successful); 293 } 294 } 295 296 if (successful && !mUserHasAuthenticatedSinceBoot.get(userId)) { 297 mUserHasAuthenticatedSinceBoot.put(userId, true); 298 updateTrust(userId); 299 } 300 } 301 302 // Listeners 303 304 private void addListener(ITrustListener listener) { 305 for (int i = 0; i < mTrustListeners.size(); i++) { 306 if (mTrustListeners.get(i).asBinder() == listener.asBinder()) { 307 return; 308 } 309 } 310 mTrustListeners.add(listener); 311 } 312 313 private void removeListener(ITrustListener listener) { 314 for (int i = 0; i < mTrustListeners.size(); i++) { 315 if (mTrustListeners.get(i).asBinder() == listener.asBinder()) { 316 mTrustListeners.get(i); 317 return; 318 } 319 } 320 } 321 322 private void dispatchOnTrustChanged(boolean enabled, int userId) { 323 for (int i = 0; i < mTrustListeners.size(); i++) { 324 try { 325 mTrustListeners.get(i).onTrustChanged(enabled, userId); 326 } catch (DeadObjectException e) { 327 if (DEBUG) Slog.d(TAG, "Removing dead TrustListener."); 328 mTrustListeners.remove(i); 329 i--; 330 } catch (RemoteException e) { 331 Slog.e(TAG, "Exception while notifying TrustListener.", e); 332 } 333 } 334 } 335 336 // Plumbing 337 338 private final IBinder mService = new ITrustManager.Stub() { 339 @Override 340 public void reportUnlockAttempt(boolean authenticated, int userId) throws RemoteException { 341 enforceReportPermission(); 342 mHandler.obtainMessage(MSG_DISPATCH_UNLOCK_ATTEMPT, authenticated ? 1 : 0, userId) 343 .sendToTarget(); 344 } 345 346 @Override 347 public void reportEnabledTrustAgentsChanged(int userId) throws RemoteException { 348 enforceReportPermission(); 349 // coalesce refresh messages. 350 mHandler.removeMessages(MSG_ENABLED_AGENTS_CHANGED); 351 mHandler.sendEmptyMessage(MSG_ENABLED_AGENTS_CHANGED); 352 } 353 354 @Override 355 public void registerTrustListener(ITrustListener trustListener) throws RemoteException { 356 enforceListenerPermission(); 357 mHandler.obtainMessage(MSG_REGISTER_LISTENER, trustListener).sendToTarget(); 358 } 359 360 @Override 361 public void unregisterTrustListener(ITrustListener trustListener) throws RemoteException { 362 enforceListenerPermission(); 363 mHandler.obtainMessage(MSG_UNREGISTER_LISTENER, trustListener).sendToTarget(); 364 } 365 366 private void enforceReportPermission() { 367 mContext.enforceCallingPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, 368 "reporting trust events"); 369 } 370 371 private void enforceListenerPermission() { 372 mContext.enforceCallingPermission(Manifest.permission.TRUST_LISTENER, 373 "register trust listener"); 374 } 375 }; 376 377 private final Handler mHandler = new Handler() { 378 @Override 379 public void handleMessage(Message msg) { 380 switch (msg.what) { 381 case MSG_REGISTER_LISTENER: 382 addListener((ITrustListener) msg.obj); 383 break; 384 case MSG_UNREGISTER_LISTENER: 385 removeListener((ITrustListener) msg.obj); 386 break; 387 case MSG_DISPATCH_UNLOCK_ATTEMPT: 388 dispatchUnlockAttempt(msg.arg1 != 0, msg.arg2); 389 break; 390 case MSG_ENABLED_AGENTS_CHANGED: 391 refreshAgentList(); 392 break; 393 } 394 } 395 }; 396 397 private final PackageMonitor mPackageMonitor = new PackageMonitor() { 398 @Override 399 public void onSomePackagesChanged() { 400 refreshAgentList(); 401 } 402 403 @Override 404 public boolean onPackageChanged(String packageName, int uid, String[] components) { 405 // We're interested in all changes, even if just some components get enabled / disabled. 406 return true; 407 } 408 }; 409 410 private class DevicePolicyReceiver extends BroadcastReceiver { 411 412 @Override 413 public void onReceive(Context context, Intent intent) { 414 if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals( 415 intent.getAction())) { 416 refreshAgentList(); 417 } 418 } 419 420 public void register(Context context) { 421 context.registerReceiverAsUser(this, 422 UserHandle.ALL, 423 new IntentFilter( 424 DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), 425 null /* permission */, 426 null /* scheduler */); 427 } 428 } 429} 430