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