1 /* 2 * Copyright (C) 2018 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.appbinding; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.AppGlobals; 22 import android.content.BroadcastReceiver; 23 import android.content.ComponentName; 24 import android.content.ContentResolver; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.content.pm.IPackageManager; 29 import android.content.pm.ServiceInfo; 30 import android.database.ContentObserver; 31 import android.net.Uri; 32 import android.os.Binder; 33 import android.os.Handler; 34 import android.os.IBinder; 35 import android.os.IInterface; 36 import android.os.UserHandle; 37 import android.provider.Settings; 38 import android.provider.Settings.Global; 39 import android.text.TextUtils; 40 import android.util.Slog; 41 import android.util.SparseBooleanArray; 42 43 import com.android.internal.annotations.GuardedBy; 44 import com.android.internal.annotations.VisibleForTesting; 45 import com.android.internal.os.BackgroundThread; 46 import com.android.internal.util.DumpUtils; 47 import com.android.server.SystemService; 48 import com.android.server.am.PersistentConnection; 49 import com.android.server.appbinding.finders.AppServiceFinder; 50 import com.android.server.appbinding.finders.CarrierMessagingClientServiceFinder; 51 52 import java.io.FileDescriptor; 53 import java.io.PrintWriter; 54 import java.util.ArrayList; 55 import java.util.function.Consumer; 56 57 /** 58 * System server that keeps a binding to an app to keep it always running. 59 * 60 * <p>As of android Q, we only use it for the default SMS app. 61 * 62 * Relevant tests: 63 * atest CtsAppBindingHostTestCases 64 * 65 * TODO Maybe handle force-stop differently. Right now we just get "binder died" and re-bind 66 * after a timeout. b/116813347 67 */ 68 public class AppBindingService extends Binder { 69 public static final String TAG = "AppBindingService"; 70 71 public static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE 72 73 private final Object mLock = new Object(); 74 75 private final Injector mInjector; 76 private final Context mContext; 77 private final Handler mHandler; 78 private final IPackageManager mIPackageManager; 79 80 @GuardedBy("mLock") 81 private AppBindingConstants mConstants; 82 83 @GuardedBy("mLock") 84 private final SparseBooleanArray mRunningUsers = new SparseBooleanArray(2); 85 86 @GuardedBy("mLock") 87 private final ArrayList<AppServiceFinder> mApps = new ArrayList<>(); 88 89 @GuardedBy("mLock") 90 private final ArrayList<AppServiceConnection> mConnections = new ArrayList<>(); 91 92 static class Injector { 93 public IPackageManager getIPackageManager() { 94 return AppGlobals.getPackageManager(); 95 } 96 97 public String getGlobalSettingString(ContentResolver resolver, String key) { 98 return Settings.Global.getString(resolver, key); 99 } 100 } 101 102 /** 103 * {@link SystemService} for this service. 104 */ 105 public static class Lifecycle extends SystemService { 106 final AppBindingService mService; 107 108 public Lifecycle(Context context) { 109 this(context, new Injector()); 110 } 111 112 Lifecycle(Context context, Injector injector) { 113 super(context); 114 mService = new AppBindingService(injector, context); 115 } 116 117 @Override 118 public void onStart() { 119 publishBinderService(Context.APP_BINDING_SERVICE, mService); 120 } 121 122 @Override 123 public void onBootPhase(int phase) { 124 mService.onBootPhase(phase); 125 } 126 127 @Override 128 public void onStartUser(int userHandle) { 129 mService.onStartUser(userHandle); 130 } 131 132 @Override 133 public void onUnlockUser(int userId) { 134 mService.onUnlockUser(userId); 135 } 136 137 @Override 138 public void onStopUser(int userHandle) { 139 mService.onStopUser(userHandle); 140 } 141 } 142 143 private AppBindingService(Injector injector, Context context) { 144 mInjector = injector; 145 mContext = context; 146 147 mIPackageManager = injector.getIPackageManager(); 148 149 mHandler = BackgroundThread.getHandler(); 150 mApps.add(new CarrierMessagingClientServiceFinder(context, this::onAppChanged, mHandler)); 151 152 // Initialize with the default value to make it non-null. 153 mConstants = AppBindingConstants.initializeFromString(""); 154 } 155 156 private void forAllAppsLocked(Consumer<AppServiceFinder> consumer) { 157 for (int i = 0; i < mApps.size(); i++) { 158 consumer.accept(mApps.get(i)); 159 } 160 } 161 162 private void onBootPhase(int phase) { 163 if (DEBUG) { 164 Slog.d(TAG, "onBootPhase: " + phase); 165 } 166 switch (phase) { 167 case SystemService.PHASE_ACTIVITY_MANAGER_READY: 168 onPhaseActivityManagerReady(); 169 break; 170 case SystemService.PHASE_THIRD_PARTY_APPS_CAN_START: 171 onPhaseThirdPartyAppsCanStart(); 172 break; 173 } 174 } 175 176 /** 177 * Handle boot phase PHASE_ACTIVITY_MANAGER_READY. 178 */ 179 private void onPhaseActivityManagerReady() { 180 // RoleManager doesn't tell us about upgrade, so we still need to listen for app upgrades. 181 // (app uninstall/disable will be notified by RoleManager.) 182 final IntentFilter packageFilter = new IntentFilter(); 183 packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 184 packageFilter.addDataScheme("package"); 185 186 mContext.registerReceiverAsUser(mPackageUserMonitor, UserHandle.ALL, 187 packageFilter, null, mHandler); 188 189 final IntentFilter userFilter = new IntentFilter(); 190 userFilter.addAction(Intent.ACTION_USER_REMOVED); 191 mContext.registerReceiverAsUser(mPackageUserMonitor, UserHandle.ALL, 192 userFilter, null, mHandler); 193 194 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor( 195 Settings.Global.APP_BINDING_CONSTANTS), false, mSettingsObserver); 196 197 refreshConstants(); 198 } 199 200 private final ContentObserver mSettingsObserver = new ContentObserver(null) { 201 @Override 202 public void onChange(boolean selfChange) { 203 refreshConstants(); 204 } 205 }; 206 207 private void refreshConstants() { 208 final String newSetting = mInjector.getGlobalSettingString( 209 mContext.getContentResolver(), Global.APP_BINDING_CONSTANTS); 210 211 synchronized (mLock) { 212 if (TextUtils.equals(mConstants.sourceSettings, newSetting)) { 213 return; 214 } 215 Slog.i(TAG, "Updating constants with: " + newSetting); 216 mConstants = AppBindingConstants.initializeFromString(newSetting); 217 218 rebindAllLocked("settings update"); 219 } 220 } 221 222 @VisibleForTesting 223 final BroadcastReceiver mPackageUserMonitor = new BroadcastReceiver() { 224 @Override 225 public void onReceive(Context context, Intent intent) { 226 if (DEBUG) { 227 Slog.d(TAG, "Broadcast received: " + intent); 228 } 229 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); 230 if (userId == UserHandle.USER_NULL) { 231 Slog.w(TAG, "Intent broadcast does not contain user handle: " + intent); 232 return; 233 } 234 235 final String action = intent.getAction(); 236 237 if (Intent.ACTION_USER_REMOVED.equals(action)) { 238 onUserRemoved(userId); 239 return; 240 } 241 242 final Uri intentUri = intent.getData(); 243 final String packageName = (intentUri != null) ? intentUri.getSchemeSpecificPart() 244 : null; 245 if (packageName == null) { 246 Slog.w(TAG, "Intent broadcast does not contain package name: " + intent); 247 return; 248 } 249 250 final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); 251 252 switch (action) { 253 case Intent.ACTION_PACKAGE_ADDED: 254 if (replacing) { 255 handlePackageAddedReplacing(packageName, userId); 256 } 257 break; 258 } 259 } 260 }; 261 262 /** 263 * Handle boot phase PHASE_THIRD_PARTY_APPS_CAN_START. 264 */ 265 private void onPhaseThirdPartyAppsCanStart() { 266 synchronized (mLock) { 267 forAllAppsLocked(AppServiceFinder::startMonitoring); 268 } 269 } 270 271 /** User lifecycle callback. */ 272 private void onStartUser(int userId) { 273 if (DEBUG) { 274 Slog.d(TAG, "onStartUser: u" + userId); 275 } 276 synchronized (mLock) { 277 mRunningUsers.append(userId, true); 278 bindServicesLocked(userId, null, "user start"); 279 } 280 } 281 282 /** User lifecycle callback. */ 283 private void onUnlockUser(int userId) { 284 if (DEBUG) { 285 Slog.d(TAG, "onUnlockUser: u" + userId); 286 } 287 synchronized (mLock) { 288 bindServicesLocked(userId, null, "user unlock"); 289 } 290 } 291 292 /** User lifecycle callback. */ 293 private void onStopUser(int userId) { 294 if (DEBUG) { 295 Slog.d(TAG, "onStopUser: u" + userId); 296 } 297 synchronized (mLock) { 298 unbindServicesLocked(userId, null, "user stop"); 299 300 mRunningUsers.delete(userId); 301 } 302 } 303 304 private void onUserRemoved(int userId) { 305 if (DEBUG) { 306 Slog.d(TAG, "onUserRemoved: u" + userId); 307 } 308 synchronized (mLock) { 309 forAllAppsLocked((app) -> app.onUserRemoved(userId)); 310 311 mRunningUsers.delete(userId); 312 } 313 } 314 315 /** 316 * Called when a target package changes; e.g. when the user changes the default SMS app. 317 */ 318 private void onAppChanged(AppServiceFinder finder, int userId) { 319 if (DEBUG) { 320 Slog.d(TAG, "onAppChanged: u" + userId + " " + finder.getAppDescription()); 321 } 322 synchronized (mLock) { 323 final String reason = finder.getAppDescription() + " changed"; 324 unbindServicesLocked(userId, finder, reason); 325 bindServicesLocked(userId, finder, reason); 326 } 327 } 328 329 @Nullable 330 private AppServiceFinder findFinderLocked(int userId, @NonNull String packageName) { 331 for (int i = 0; i < mApps.size(); i++) { 332 final AppServiceFinder app = mApps.get(i); 333 if (packageName.equals(app.getTargetPackage(userId))) { 334 return app; 335 } 336 } 337 return null; 338 } 339 340 @Nullable 341 private AppServiceConnection findConnectionLock( 342 int userId, @NonNull AppServiceFinder target) { 343 for (int i = 0; i < mConnections.size(); i++) { 344 final AppServiceConnection conn = mConnections.get(i); 345 if ((conn.getUserId() == userId) && (conn.getFinder() == target)) { 346 return conn; 347 } 348 } 349 return null; 350 } 351 352 private void handlePackageAddedReplacing(String packageName, int userId) { 353 if (DEBUG) { 354 Slog.d(TAG, "handlePackageAddedReplacing: u" + userId + " " + packageName); 355 } 356 synchronized (mLock) { 357 final AppServiceFinder finder = findFinderLocked(userId, packageName); 358 if (finder != null) { 359 unbindServicesLocked(userId, finder, "package update"); 360 bindServicesLocked(userId, finder, "package update"); 361 } 362 } 363 } 364 365 private void rebindAllLocked(String reason) { 366 for (int i = 0; i < mRunningUsers.size(); i++) { 367 if (!mRunningUsers.valueAt(i)) { 368 continue; 369 } 370 final int userId = mRunningUsers.keyAt(i); 371 372 unbindServicesLocked(userId, null, reason); 373 bindServicesLocked(userId, null, reason); 374 } 375 } 376 377 private void bindServicesLocked(int userId, @Nullable AppServiceFinder target, 378 @NonNull String reasonForLog) { 379 for (int i = 0; i < mApps.size(); i++) { 380 final AppServiceFinder app = mApps.get(i); 381 if (target != null && target != app) { 382 continue; 383 } 384 385 // Disconnect from existing binding. 386 final AppServiceConnection existingConn = findConnectionLock(userId, app); 387 if (existingConn != null) { 388 unbindServicesLocked(userId, target, reasonForLog); 389 } 390 391 final ServiceInfo service = app.findService(userId, mIPackageManager, mConstants); 392 if (service == null) { 393 continue; 394 } 395 if (DEBUG) { 396 Slog.d(TAG, "bindServicesLocked: u" + userId + " " + app.getAppDescription() 397 + " binding " + service.getComponentName() + " for " + reasonForLog); 398 } 399 final AppServiceConnection conn = 400 new AppServiceConnection(mContext, userId, mConstants, mHandler, 401 app, service.getComponentName()); 402 mConnections.add(conn); 403 conn.bind(); 404 } 405 } 406 407 private void unbindServicesLocked(int userId, @Nullable AppServiceFinder target, 408 @NonNull String reasonForLog) { 409 for (int i = mConnections.size() - 1; i >= 0; i--) { 410 final AppServiceConnection conn = mConnections.get(i); 411 if ((conn.getUserId() != userId) 412 || (target != null && conn.getFinder() != target)) { 413 continue; 414 } 415 if (DEBUG) { 416 Slog.d(TAG, "unbindServicesLocked: u" + userId 417 + " " + conn.getFinder().getAppDescription() 418 + " unbinding " + conn.getComponentName() + " for " + reasonForLog); 419 } 420 mConnections.remove(i); 421 conn.unbind(); 422 } 423 } 424 425 private static class AppServiceConnection extends PersistentConnection<IInterface> { 426 private final AppBindingConstants mConstants; 427 private final AppServiceFinder mFinder; 428 429 AppServiceConnection(Context context, int userId, AppBindingConstants constants, 430 Handler handler, AppServiceFinder finder, 431 @NonNull ComponentName componentName) { 432 super(TAG, context, handler, userId, componentName, 433 constants.SERVICE_RECONNECT_BACKOFF_SEC, 434 constants.SERVICE_RECONNECT_BACKOFF_INCREASE, 435 constants.SERVICE_RECONNECT_MAX_BACKOFF_SEC, 436 constants.SERVICE_STABLE_CONNECTION_THRESHOLD_SEC); 437 mFinder = finder; 438 mConstants = constants; 439 } 440 441 @Override 442 protected int getBindFlags() { 443 return mFinder.getBindFlags(mConstants); 444 } 445 446 @Override 447 protected IInterface asInterface(IBinder obj) { 448 return mFinder.asInterface(obj); 449 } 450 451 public AppServiceFinder getFinder() { 452 return mFinder; 453 } 454 } 455 456 @Override 457 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 458 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 459 460 if (args.length > 0 && "-s".equals(args[0])) { 461 dumpSimple(pw); 462 return; 463 } 464 465 synchronized (mLock) { 466 mConstants.dump(" ", pw); 467 468 pw.println(); 469 pw.print(" Running users:"); 470 for (int i = 0; i < mRunningUsers.size(); i++) { 471 if (mRunningUsers.valueAt(i)) { 472 pw.print(" "); 473 pw.print(mRunningUsers.keyAt(i)); 474 } 475 } 476 477 pw.println(); 478 pw.println(" Connections:"); 479 for (int i = 0; i < mConnections.size(); i++) { 480 final AppServiceConnection conn = mConnections.get(i); 481 pw.print(" App type: "); 482 pw.print(conn.getFinder().getAppDescription()); 483 pw.println(); 484 485 conn.dump(" ", pw); 486 } 487 if (mConnections.size() == 0) { 488 pw.println(" None:"); 489 } 490 491 pw.println(); 492 pw.println(" Finders:"); 493 forAllAppsLocked((app) -> app.dump(" ", pw)); 494 } 495 } 496 497 /** 498 * Print simple output for CTS. 499 */ 500 private void dumpSimple(PrintWriter pw) { 501 synchronized (mLock) { 502 for (int i = 0; i < mConnections.size(); i++) { 503 final AppServiceConnection conn = mConnections.get(i); 504 505 pw.print("conn,"); 506 pw.print(conn.getFinder().getAppDescription()); 507 pw.print(","); 508 pw.print(conn.getUserId()); 509 pw.print(","); 510 pw.print(conn.getComponentName().getPackageName()); 511 pw.print(","); 512 pw.print(conn.getComponentName().getClassName()); 513 pw.print(","); 514 pw.print(conn.isBound() ? "bound" : "not-bound"); 515 pw.print(","); 516 pw.print(conn.isConnected() ? "connected" : "not-connected"); 517 pw.print(",#con="); 518 pw.print(conn.getNumConnected()); 519 pw.print(",#dis="); 520 pw.print(conn.getNumDisconnected()); 521 pw.print(",#died="); 522 pw.print(conn.getNumBindingDied()); 523 pw.print(",backoff="); 524 pw.print(conn.getNextBackoffMs()); 525 pw.println(); 526 } 527 forAllAppsLocked((app) -> app.dumpSimple(pw)); 528 } 529 } 530 531 AppBindingConstants getConstantsForTest() { 532 return mConstants; 533 } 534 } 535