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 17 package com.android.server.notification; 18 19 import android.app.ActivityManager; 20 import android.app.PendingIntent; 21 import android.content.ComponentName; 22 import android.content.ContentResolver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.ServiceConnection; 26 import android.content.pm.ApplicationInfo; 27 import android.content.pm.PackageManager; 28 import android.content.pm.PackageManager.NameNotFoundException; 29 import android.content.pm.ResolveInfo; 30 import android.content.pm.ServiceInfo; 31 import android.content.pm.UserInfo; 32 import android.database.ContentObserver; 33 import android.net.Uri; 34 import android.os.Build; 35 import android.os.Handler; 36 import android.os.IBinder; 37 import android.os.IInterface; 38 import android.os.RemoteException; 39 import android.os.UserHandle; 40 import android.os.UserManager; 41 import android.provider.Settings; 42 import android.text.TextUtils; 43 import android.util.ArraySet; 44 import android.util.Log; 45 import android.util.Slog; 46 import android.util.SparseArray; 47 48 import com.android.server.notification.NotificationManagerService.DumpFilter; 49 50 import java.io.PrintWriter; 51 import java.util.ArrayList; 52 import java.util.Arrays; 53 import java.util.List; 54 import java.util.Set; 55 56 /** 57 * Manages the lifecycle of application-provided services bound by system server. 58 * 59 * Services managed by this helper must have: 60 * - An associated system settings value with a list of enabled component names. 61 * - A well-known action for services to use in their intent-filter. 62 * - A system permission for services to require in order to ensure system has exclusive binding. 63 * - A settings page for user configuration of enabled services, and associated intent action. 64 * - A remote interface definition (aidl) provided by the service used for communication. 65 */ 66 abstract public class ManagedServices { 67 protected final String TAG = getClass().getSimpleName(); 68 protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 69 70 private static final String ENABLED_SERVICES_SEPARATOR = ":"; 71 72 protected final Context mContext; 73 protected final Object mMutex; 74 private final UserProfiles mUserProfiles; 75 private final SettingsObserver mSettingsObserver; 76 private final Config mConfig; 77 78 // contains connections to all connected services, including app services 79 // and system services 80 protected final ArrayList<ManagedServiceInfo> mServices = new ArrayList<ManagedServiceInfo>(); 81 // things that will be put into mServices as soon as they're ready 82 private final ArrayList<String> mServicesBinding = new ArrayList<String>(); 83 // lists the component names of all enabled (and therefore connected) 84 // app services for current profiles. 85 private ArraySet<ComponentName> mEnabledServicesForCurrentProfiles 86 = new ArraySet<ComponentName>(); 87 // Just the packages from mEnabledServicesForCurrentProfiles 88 private ArraySet<String> mEnabledServicesPackageNames = new ArraySet<String>(); 89 90 // Kept to de-dupe user change events (experienced after boot, when we receive a settings and a 91 // user change). 92 private int[] mLastSeenProfileIds; 93 94 public ManagedServices(Context context, Handler handler, Object mutex, 95 UserProfiles userProfiles) { 96 mContext = context; 97 mMutex = mutex; 98 mUserProfiles = userProfiles; 99 mConfig = getConfig(); 100 mSettingsObserver = new SettingsObserver(handler); 101 } 102 103 abstract protected Config getConfig(); 104 105 private String getCaption() { 106 return mConfig.caption; 107 } 108 109 abstract protected IInterface asInterface(IBinder binder); 110 111 abstract protected void onServiceAdded(ManagedServiceInfo info); 112 113 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { } 114 115 private ManagedServiceInfo newServiceInfo(IInterface service, 116 ComponentName component, int userid, boolean isSystem, ServiceConnection connection, 117 int targetSdkVersion) { 118 return new ManagedServiceInfo(service, component, userid, isSystem, connection, 119 targetSdkVersion); 120 } 121 122 public void onBootPhaseAppsCanStart() { 123 mSettingsObserver.observe(); 124 } 125 126 public void dump(PrintWriter pw, DumpFilter filter) { 127 pw.println(" All " + getCaption() + "s (" + mEnabledServicesForCurrentProfiles.size() 128 + ") enabled for current profiles:"); 129 for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) { 130 if (filter != null && !filter.matches(cmpt)) continue; 131 pw.println(" " + cmpt); 132 } 133 134 pw.println(" Live " + getCaption() + "s (" + mServices.size() + "):"); 135 for (ManagedServiceInfo info : mServices) { 136 if (filter != null && !filter.matches(info.component)) continue; 137 pw.println(" " + info.component 138 + " (user " + info.userid + "): " + info.service 139 + (info.isSystem?" SYSTEM":"")); 140 } 141 } 142 143 public void onPackagesChanged(boolean queryReplace, String[] pkgList) { 144 if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace 145 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList)) 146 + " mEnabledServicesPackageNames=" + mEnabledServicesPackageNames); 147 boolean anyServicesInvolved = false; 148 if (pkgList != null && (pkgList.length > 0)) { 149 for (String pkgName : pkgList) { 150 if (mEnabledServicesPackageNames.contains(pkgName)) { 151 anyServicesInvolved = true; 152 } 153 } 154 } 155 156 if (anyServicesInvolved) { 157 // if we're not replacing a package, clean up orphaned bits 158 if (!queryReplace) { 159 disableNonexistentServices(); 160 } 161 // make sure we're still bound to any of our services who may have just upgraded 162 rebindServices(); 163 } 164 } 165 166 public void onUserSwitched() { 167 if (DEBUG) Slog.d(TAG, "onUserSwitched"); 168 if (Arrays.equals(mLastSeenProfileIds, mUserProfiles.getCurrentProfileIds())) { 169 if (DEBUG) Slog.d(TAG, "Current profile IDs didn't change, skipping rebindServices()."); 170 return; 171 } 172 rebindServices(); 173 } 174 175 public ManagedServiceInfo checkServiceTokenLocked(IInterface service) { 176 checkNotNull(service); 177 final IBinder token = service.asBinder(); 178 final int N = mServices.size(); 179 for (int i=0; i<N; i++) { 180 final ManagedServiceInfo info = mServices.get(i); 181 if (info.service.asBinder() == token) return info; 182 } 183 throw new SecurityException("Disallowed call from unknown " + getCaption() + ": " 184 + service); 185 } 186 187 public void unregisterService(IInterface service, int userid) { 188 checkNotNull(service); 189 // no need to check permissions; if your service binder is in the list, 190 // that's proof that you had permission to add it in the first place 191 unregisterServiceImpl(service, userid); 192 } 193 194 public void registerService(IInterface service, ComponentName component, int userid) { 195 checkNotNull(service); 196 ManagedServiceInfo info = registerServiceImpl(service, component, userid); 197 if (info != null) { 198 onServiceAdded(info); 199 } 200 } 201 202 /** 203 * Remove access for any services that no longer exist. 204 */ 205 private void disableNonexistentServices() { 206 int[] userIds = mUserProfiles.getCurrentProfileIds(); 207 final int N = userIds.length; 208 for (int i = 0 ; i < N; ++i) { 209 disableNonexistentServices(userIds[i]); 210 } 211 } 212 213 private void disableNonexistentServices(int userId) { 214 String flatIn = Settings.Secure.getStringForUser( 215 mContext.getContentResolver(), 216 mConfig.secureSettingName, 217 userId); 218 if (!TextUtils.isEmpty(flatIn)) { 219 if (DEBUG) Slog.v(TAG, "flat before: " + flatIn); 220 PackageManager pm = mContext.getPackageManager(); 221 List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser( 222 new Intent(mConfig.serviceInterface), 223 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, 224 userId); 225 if (DEBUG) Slog.v(TAG, mConfig.serviceInterface + " services: " + installedServices); 226 Set<ComponentName> installed = new ArraySet<ComponentName>(); 227 for (int i = 0, count = installedServices.size(); i < count; i++) { 228 ResolveInfo resolveInfo = installedServices.get(i); 229 ServiceInfo info = resolveInfo.serviceInfo; 230 231 if (!mConfig.bindPermission.equals(info.permission)) { 232 Slog.w(TAG, "Skipping " + getCaption() + " service " 233 + info.packageName + "/" + info.name 234 + ": it does not require the permission " 235 + mConfig.bindPermission); 236 continue; 237 } 238 installed.add(new ComponentName(info.packageName, info.name)); 239 } 240 241 String flatOut = ""; 242 if (!installed.isEmpty()) { 243 String[] enabled = flatIn.split(ENABLED_SERVICES_SEPARATOR); 244 ArrayList<String> remaining = new ArrayList<String>(enabled.length); 245 for (int i = 0; i < enabled.length; i++) { 246 ComponentName enabledComponent = ComponentName.unflattenFromString(enabled[i]); 247 if (installed.contains(enabledComponent)) { 248 remaining.add(enabled[i]); 249 } 250 } 251 flatOut = TextUtils.join(ENABLED_SERVICES_SEPARATOR, remaining); 252 } 253 if (DEBUG) Slog.v(TAG, "flat after: " + flatOut); 254 if (!flatIn.equals(flatOut)) { 255 Settings.Secure.putStringForUser(mContext.getContentResolver(), 256 mConfig.secureSettingName, 257 flatOut, userId); 258 } 259 } 260 } 261 262 /** 263 * Called whenever packages change, the user switches, or the secure setting 264 * is altered. (For example in response to USER_SWITCHED in our broadcast receiver) 265 */ 266 private void rebindServices() { 267 if (DEBUG) Slog.d(TAG, "rebindServices"); 268 final int[] userIds = mUserProfiles.getCurrentProfileIds(); 269 final int nUserIds = userIds.length; 270 271 final SparseArray<String> flat = new SparseArray<String>(); 272 273 for (int i = 0; i < nUserIds; ++i) { 274 flat.put(userIds[i], Settings.Secure.getStringForUser( 275 mContext.getContentResolver(), 276 mConfig.secureSettingName, 277 userIds[i])); 278 } 279 280 ArrayList<ManagedServiceInfo> toRemove = new ArrayList<ManagedServiceInfo>(); 281 final SparseArray<ArrayList<ComponentName>> toAdd 282 = new SparseArray<ArrayList<ComponentName>>(); 283 284 synchronized (mMutex) { 285 // Unbind automatically bound services, retain system services. 286 for (ManagedServiceInfo service : mServices) { 287 if (!service.isSystem) { 288 toRemove.add(service); 289 } 290 } 291 292 final ArraySet<ComponentName> newEnabled = new ArraySet<ComponentName>(); 293 final ArraySet<String> newPackages = new ArraySet<String>(); 294 295 for (int i = 0; i < nUserIds; ++i) { 296 final ArrayList<ComponentName> add = new ArrayList<ComponentName>(); 297 toAdd.put(userIds[i], add); 298 299 // decode the list of components 300 String toDecode = flat.get(userIds[i]); 301 if (toDecode != null) { 302 String[] components = toDecode.split(ENABLED_SERVICES_SEPARATOR); 303 for (int j = 0; j < components.length; j++) { 304 final ComponentName component 305 = ComponentName.unflattenFromString(components[j]); 306 if (component != null) { 307 newEnabled.add(component); 308 add.add(component); 309 newPackages.add(component.getPackageName()); 310 } 311 } 312 313 } 314 } 315 mEnabledServicesForCurrentProfiles = newEnabled; 316 mEnabledServicesPackageNames = newPackages; 317 } 318 319 for (ManagedServiceInfo info : toRemove) { 320 final ComponentName component = info.component; 321 final int oldUser = info.userid; 322 Slog.v(TAG, "disabling " + getCaption() + " for user " 323 + oldUser + ": " + component); 324 unregisterService(component, info.userid); 325 } 326 327 for (int i = 0; i < nUserIds; ++i) { 328 final ArrayList<ComponentName> add = toAdd.get(userIds[i]); 329 final int N = add.size(); 330 for (int j = 0; j < N; j++) { 331 final ComponentName component = add.get(j); 332 Slog.v(TAG, "enabling " + getCaption() + " for user " + userIds[i] + ": " 333 + component); 334 registerService(component, userIds[i]); 335 } 336 } 337 338 mLastSeenProfileIds = mUserProfiles.getCurrentProfileIds(); 339 } 340 341 /** 342 * Version of registerService that takes the name of a service component to bind to. 343 */ 344 private void registerService(final ComponentName name, final int userid) { 345 if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid); 346 347 synchronized (mMutex) { 348 final String servicesBindingTag = name.toString() + "/" + userid; 349 if (mServicesBinding.contains(servicesBindingTag)) { 350 // stop registering this thing already! we're working on it 351 return; 352 } 353 mServicesBinding.add(servicesBindingTag); 354 355 final int N = mServices.size(); 356 for (int i=N-1; i>=0; i--) { 357 final ManagedServiceInfo info = mServices.get(i); 358 if (name.equals(info.component) 359 && info.userid == userid) { 360 // cut old connections 361 if (DEBUG) Slog.v(TAG, " disconnecting old " + getCaption() + ": " 362 + info.service); 363 removeServiceLocked(i); 364 if (info.connection != null) { 365 mContext.unbindService(info.connection); 366 } 367 } 368 } 369 370 Intent intent = new Intent(mConfig.serviceInterface); 371 intent.setComponent(name); 372 373 intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel); 374 375 final PendingIntent pendingIntent = PendingIntent.getActivity( 376 mContext, 0, new Intent(mConfig.settingsAction), 0); 377 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent); 378 379 ApplicationInfo appInfo = null; 380 try { 381 appInfo = mContext.getPackageManager().getApplicationInfo( 382 name.getPackageName(), 0); 383 } catch (NameNotFoundException e) { 384 // Ignore if the package doesn't exist we won't be able to bind to the service. 385 } 386 final int targetSdkVersion = 387 appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE; 388 389 try { 390 if (DEBUG) Slog.v(TAG, "binding: " + intent); 391 if (!mContext.bindServiceAsUser(intent, 392 new ServiceConnection() { 393 IInterface mService; 394 395 @Override 396 public void onServiceConnected(ComponentName name, IBinder binder) { 397 boolean added = false; 398 ManagedServiceInfo info = null; 399 synchronized (mMutex) { 400 mServicesBinding.remove(servicesBindingTag); 401 try { 402 mService = asInterface(binder); 403 info = newServiceInfo(mService, name, 404 userid, false /*isSystem*/, this, targetSdkVersion); 405 binder.linkToDeath(info, 0); 406 added = mServices.add(info); 407 } catch (RemoteException e) { 408 // already dead 409 } 410 } 411 if (added) { 412 onServiceAdded(info); 413 } 414 } 415 416 @Override 417 public void onServiceDisconnected(ComponentName name) { 418 Slog.v(TAG, getCaption() + " connection lost: " + name); 419 } 420 }, 421 Context.BIND_AUTO_CREATE, 422 new UserHandle(userid))) 423 { 424 mServicesBinding.remove(servicesBindingTag); 425 Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent); 426 return; 427 } 428 } catch (SecurityException ex) { 429 Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex); 430 return; 431 } 432 } 433 } 434 435 /** 436 * Remove a service for the given user by ComponentName 437 */ 438 private void unregisterService(ComponentName name, int userid) { 439 synchronized (mMutex) { 440 final int N = mServices.size(); 441 for (int i=N-1; i>=0; i--) { 442 final ManagedServiceInfo info = mServices.get(i); 443 if (name.equals(info.component) 444 && info.userid == userid) { 445 removeServiceLocked(i); 446 if (info.connection != null) { 447 try { 448 mContext.unbindService(info.connection); 449 } catch (IllegalArgumentException ex) { 450 // something happened to the service: we think we have a connection 451 // but it's bogus. 452 Slog.e(TAG, getCaption() + " " + name + " could not be unbound: " + ex); 453 } 454 } 455 } 456 } 457 } 458 } 459 460 /** 461 * Removes a service from the list but does not unbind 462 * 463 * @return the removed service. 464 */ 465 private ManagedServiceInfo removeServiceImpl(IInterface service, final int userid) { 466 if (DEBUG) Slog.d(TAG, "removeServiceImpl service=" + service + " u=" + userid); 467 ManagedServiceInfo serviceInfo = null; 468 synchronized (mMutex) { 469 final int N = mServices.size(); 470 for (int i=N-1; i>=0; i--) { 471 final ManagedServiceInfo info = mServices.get(i); 472 if (info.service.asBinder() == service.asBinder() 473 && info.userid == userid) { 474 if (DEBUG) Slog.d(TAG, "Removing active service " + info.component); 475 serviceInfo = removeServiceLocked(i); 476 } 477 } 478 } 479 return serviceInfo; 480 } 481 482 private ManagedServiceInfo removeServiceLocked(int i) { 483 final ManagedServiceInfo info = mServices.remove(i); 484 onServiceRemovedLocked(info); 485 return info; 486 } 487 488 private void checkNotNull(IInterface service) { 489 if (service == null) { 490 throw new IllegalArgumentException(getCaption() + " must not be null"); 491 } 492 } 493 494 private ManagedServiceInfo registerServiceImpl(final IInterface service, 495 final ComponentName component, final int userid) { 496 synchronized (mMutex) { 497 try { 498 ManagedServiceInfo info = newServiceInfo(service, component, userid, 499 true /*isSystem*/, null, Build.VERSION_CODES.LOLLIPOP); 500 service.asBinder().linkToDeath(info, 0); 501 mServices.add(info); 502 return info; 503 } catch (RemoteException e) { 504 // already dead 505 } 506 } 507 return null; 508 } 509 510 /** 511 * Removes a service from the list and unbinds. 512 */ 513 private void unregisterServiceImpl(IInterface service, int userid) { 514 ManagedServiceInfo info = removeServiceImpl(service, userid); 515 if (info != null && info.connection != null) { 516 mContext.unbindService(info.connection); 517 } 518 } 519 520 private class SettingsObserver extends ContentObserver { 521 private final Uri mSecureSettingsUri = Settings.Secure.getUriFor(mConfig.secureSettingName); 522 523 private SettingsObserver(Handler handler) { 524 super(handler); 525 } 526 527 private void observe() { 528 ContentResolver resolver = mContext.getContentResolver(); 529 resolver.registerContentObserver(mSecureSettingsUri, 530 false, this, UserHandle.USER_ALL); 531 update(null); 532 } 533 534 @Override 535 public void onChange(boolean selfChange, Uri uri) { 536 update(uri); 537 } 538 539 private void update(Uri uri) { 540 if (uri == null || mSecureSettingsUri.equals(uri)) { 541 if (DEBUG) Slog.d(TAG, "Setting changed: mSecureSettingsUri=" + mSecureSettingsUri + 542 " / uri=" + uri); 543 rebindServices(); 544 } 545 } 546 } 547 548 public class ManagedServiceInfo implements IBinder.DeathRecipient { 549 public IInterface service; 550 public ComponentName component; 551 public int userid; 552 public boolean isSystem; 553 public ServiceConnection connection; 554 public int targetSdkVersion; 555 556 public ManagedServiceInfo(IInterface service, ComponentName component, 557 int userid, boolean isSystem, ServiceConnection connection, int targetSdkVersion) { 558 this.service = service; 559 this.component = component; 560 this.userid = userid; 561 this.isSystem = isSystem; 562 this.connection = connection; 563 this.targetSdkVersion = targetSdkVersion; 564 } 565 566 @Override 567 public String toString() { 568 return new StringBuilder("ManagedServiceInfo[") 569 .append("component=").append(component) 570 .append(",userid=").append(userid) 571 .append(",isSystem=").append(isSystem) 572 .append(",targetSdkVersion=").append(targetSdkVersion) 573 .append(",connection=").append(connection == null ? null : "<connection>") 574 .append(",service=").append(service) 575 .append(']').toString(); 576 } 577 578 public boolean enabledAndUserMatches(int nid) { 579 if (!isEnabledForCurrentProfiles()) { 580 return false; 581 } 582 if (this.userid == UserHandle.USER_ALL) return true; 583 if (nid == UserHandle.USER_ALL || nid == this.userid) return true; 584 return supportsProfiles() && mUserProfiles.isCurrentProfile(nid); 585 } 586 587 public boolean supportsProfiles() { 588 return targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP; 589 } 590 591 @Override 592 public void binderDied() { 593 if (DEBUG) Slog.d(TAG, "binderDied"); 594 // Remove the service, but don't unbind from the service. The system will bring the 595 // service back up, and the onServiceConnected handler will readd the service with the 596 // new binding. If this isn't a bound service, and is just a registered 597 // service, just removing it from the list is all we need to do anyway. 598 removeServiceImpl(this.service, this.userid); 599 } 600 601 /** convenience method for looking in mEnabledServicesForCurrentProfiles */ 602 public boolean isEnabledForCurrentProfiles() { 603 if (this.isSystem) return true; 604 if (this.connection == null) return false; 605 return mEnabledServicesForCurrentProfiles.contains(this.component); 606 } 607 } 608 609 public static class UserProfiles { 610 // Profiles of the current user. 611 private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>(); 612 613 public void updateCache(Context context) { 614 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 615 if (userManager != null) { 616 int currentUserId = ActivityManager.getCurrentUser(); 617 List<UserInfo> profiles = userManager.getProfiles(currentUserId); 618 synchronized (mCurrentProfiles) { 619 mCurrentProfiles.clear(); 620 for (UserInfo user : profiles) { 621 mCurrentProfiles.put(user.id, user); 622 } 623 } 624 } 625 } 626 627 public int[] getCurrentProfileIds() { 628 synchronized (mCurrentProfiles) { 629 int[] users = new int[mCurrentProfiles.size()]; 630 final int N = mCurrentProfiles.size(); 631 for (int i = 0; i < N; ++i) { 632 users[i] = mCurrentProfiles.keyAt(i); 633 } 634 return users; 635 } 636 } 637 638 public boolean isCurrentProfile(int userId) { 639 synchronized (mCurrentProfiles) { 640 return mCurrentProfiles.get(userId) != null; 641 } 642 } 643 } 644 645 protected static class Config { 646 String caption; 647 String serviceInterface; 648 String secureSettingName; 649 String bindPermission; 650 String settingsAction; 651 int clientLabel; 652 } 653 } 654