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