blob: 3131255a61cd39dba3eb355b932c4246b326cb05 [file] [log] [blame]
Makoto Onukidf7e4812018-09-24 14:31:25 -07001/*
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
17package com.android.server.appbinding;
18
Makoto Onuki87d260a2018-09-26 16:58:32 -070019import android.annotation.NonNull;
20import android.annotation.Nullable;
Makoto Onukidf7e4812018-09-24 14:31:25 -070021import android.app.AppGlobals;
Makoto Onuki87d260a2018-09-26 16:58:32 -070022import android.content.BroadcastReceiver;
23import android.content.ComponentName;
Makoto Onuki8c7c5cc2018-10-02 09:29:58 -070024import android.content.ContentResolver;
Makoto Onukidf7e4812018-09-24 14:31:25 -070025import android.content.Context;
Makoto Onuki87d260a2018-09-26 16:58:32 -070026import android.content.Intent;
27import android.content.IntentFilter;
Makoto Onukidf7e4812018-09-24 14:31:25 -070028import android.content.pm.IPackageManager;
Makoto Onuki87d260a2018-09-26 16:58:32 -070029import android.content.pm.ServiceInfo;
30import android.database.ContentObserver;
31import android.net.Uri;
Makoto Onukidf7e4812018-09-24 14:31:25 -070032import android.os.Binder;
33import android.os.Handler;
Makoto Onuki87d260a2018-09-26 16:58:32 -070034import android.os.IBinder;
35import android.os.IInterface;
36import android.os.UserHandle;
37import android.provider.Settings;
38import android.provider.Settings.Global;
39import android.text.TextUtils;
40import android.util.Slog;
41import android.util.SparseBooleanArray;
Makoto Onukidf7e4812018-09-24 14:31:25 -070042
Makoto Onuki87d260a2018-09-26 16:58:32 -070043import com.android.internal.annotations.GuardedBy;
44import com.android.internal.annotations.VisibleForTesting;
Makoto Onukidf7e4812018-09-24 14:31:25 -070045import com.android.internal.os.BackgroundThread;
46import com.android.internal.util.DumpUtils;
47import com.android.server.SystemService;
Makoto Onuki87d260a2018-09-26 16:58:32 -070048import com.android.server.am.PersistentConnection;
49import com.android.server.appbinding.finders.AppServiceFinder;
50import com.android.server.appbinding.finders.SmsAppServiceFinder;
Makoto Onukidf7e4812018-09-24 14:31:25 -070051
52import java.io.FileDescriptor;
53import java.io.PrintWriter;
Makoto Onuki87d260a2018-09-26 16:58:32 -070054import java.util.ArrayList;
55import java.util.function.Consumer;
Makoto Onukidf7e4812018-09-24 14:31:25 -070056
57/**
58 * System server that keeps a binding to an app to keep it always running.
Makoto Onuki87d260a2018-09-26 16:58:32 -070059 *
60 * <p>As of android Q, we only use it for the default SMS app.
61 *
Makoto Onuki8c7c5cc2018-10-02 09:29:58 -070062 * 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
Makoto Onukidf7e4812018-09-24 14:31:25 -070067 */
68public class AppBindingService extends Binder {
69 public static final String TAG = "AppBindingService";
70
Makoto Onuki87d260a2018-09-26 16:58:32 -070071 public static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE
Makoto Onukidf7e4812018-09-24 14:31:25 -070072
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
Makoto Onuki87d260a2018-09-26 16:58:32 -070080 @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
Makoto Onukidf7e4812018-09-24 14:31:25 -070092 static class Injector {
93 public IPackageManager getIPackageManager() {
94 return AppGlobals.getPackageManager();
95 }
Makoto Onuki8c7c5cc2018-10-02 09:29:58 -070096
97 public String getGlobalSettingString(ContentResolver resolver, String key) {
98 return Settings.Global.getString(resolver, key);
99 }
Makoto Onukidf7e4812018-09-24 14:31:25 -0700100 }
101
102 /**
Makoto Onuki87d260a2018-09-26 16:58:32 -0700103 * {@link SystemService} for this service.
Makoto Onukidf7e4812018-09-24 14:31:25 -0700104 */
Makoto Onuki8c7c5cc2018-10-02 09:29:58 -0700105 public static class Lifecycle extends SystemService {
Makoto Onukidf7e4812018-09-24 14:31:25 -0700106 final AppBindingService mService;
107
108 public Lifecycle(Context context) {
Makoto Onuki8c7c5cc2018-10-02 09:29:58 -0700109 this(context, new Injector());
110 }
111
112 Lifecycle(Context context, Injector injector) {
Makoto Onukidf7e4812018-09-24 14:31:25 -0700113 super(context);
Makoto Onuki8c7c5cc2018-10-02 09:29:58 -0700114 mService = new AppBindingService(injector, context);
Makoto Onukidf7e4812018-09-24 14:31:25 -0700115 }
116
117 @Override
118 public void onStart() {
119 publishBinderService(Context.APP_BINDING_SERVICE, mService);
120 }
Makoto Onuki87d260a2018-09-26 16:58:32 -0700121
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 }
Makoto Onukidf7e4812018-09-24 14:31:25 -0700141 }
142
143 private AppBindingService(Injector injector, Context context) {
144 mInjector = injector;
145 mContext = context;
Makoto Onuki87d260a2018-09-26 16:58:32 -0700146
Makoto Onukidf7e4812018-09-24 14:31:25 -0700147 mIPackageManager = injector.getIPackageManager();
Makoto Onuki87d260a2018-09-26 16:58:32 -0700148
Makoto Onukidf7e4812018-09-24 14:31:25 -0700149 mHandler = BackgroundThread.getHandler();
Makoto Onuki87d260a2018-09-26 16:58:32 -0700150 mApps.add(new SmsAppServiceFinder(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 final IntentFilter packageFilter = new IntentFilter();
181 packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
182 packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
183 packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Makoto Onuki87d260a2018-09-26 16:58:32 -0700184 packageFilter.addDataScheme("package");
185
186 packageFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
187 mContext.registerReceiverAsUser(mPackageUserMonitor, UserHandle.ALL,
188 packageFilter, null, mHandler);
189
190 final IntentFilter userFilter = new IntentFilter();
191 userFilter.addAction(Intent.ACTION_USER_REMOVED);
192 mContext.registerReceiverAsUser(mPackageUserMonitor, UserHandle.ALL,
193 userFilter, null, mHandler);
194
195 mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
196 Settings.Global.APP_BINDING_CONSTANTS), false, mSettingsObserver);
197
198 refreshConstants();
199 }
200
201 private final ContentObserver mSettingsObserver = new ContentObserver(null) {
202 @Override
203 public void onChange(boolean selfChange) {
204 refreshConstants();
205 }
206 };
207
208 private void refreshConstants() {
Makoto Onuki8c7c5cc2018-10-02 09:29:58 -0700209 final String newSetting = mInjector.getGlobalSettingString(
Makoto Onuki87d260a2018-09-26 16:58:32 -0700210 mContext.getContentResolver(), Global.APP_BINDING_CONSTANTS);
211
212 synchronized (mLock) {
213 if (TextUtils.equals(mConstants.sourceSettings, newSetting)) {
214 return;
215 }
216 Slog.i(TAG, "Updating constants with: " + newSetting);
217 mConstants = AppBindingConstants.initializeFromString(newSetting);
218
219 rebindAllLocked("settings update");
220 }
221 }
222
223 @VisibleForTesting
224 final BroadcastReceiver mPackageUserMonitor = new BroadcastReceiver() {
225 @Override
226 public void onReceive(Context context, Intent intent) {
Makoto Onuki8c7c5cc2018-10-02 09:29:58 -0700227 if (DEBUG) {
228 Slog.d(TAG, "Broadcast received: " + intent);
229 }
Makoto Onuki87d260a2018-09-26 16:58:32 -0700230 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
231 if (userId == UserHandle.USER_NULL) {
232 Slog.w(TAG, "Intent broadcast does not contain user handle: " + intent);
233 return;
234 }
235
236 final String action = intent.getAction();
237
238 if (Intent.ACTION_USER_REMOVED.equals(action)) {
239 onUserRemoved(userId);
240 return;
241 }
242
243 final Uri intentUri = intent.getData();
244 final String packageName = (intentUri != null) ? intentUri.getSchemeSpecificPart()
245 : null;
246 if (packageName == null) {
247 Slog.w(TAG, "Intent broadcast does not contain package name: " + intent);
248 return;
249 }
250
251 final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
252
253 switch (action) {
254 case Intent.ACTION_PACKAGE_ADDED:
255 if (replacing) {
256 handlePackageAddedReplacing(packageName, userId);
257 }
258 break;
259 case Intent.ACTION_PACKAGE_REMOVED:
260 if (!replacing) {
261 handlePackageRemoved(packageName, userId);
262 }
263 break;
264 case Intent.ACTION_PACKAGE_CHANGED:
265 handlePackageChanged(packageName, userId);
266 break;
267 }
268 }
269 };
270
271 /**
272 * Handle boot phase PHASE_THIRD_PARTY_APPS_CAN_START.
273 */
274 private void onPhaseThirdPartyAppsCanStart() {
275 synchronized (mLock) {
276 forAllAppsLocked(AppServiceFinder::startMonitoring);
277 }
278 }
279
280 /** User lifecycle callback. */
281 private void onStartUser(int userId) {
282 if (DEBUG) {
283 Slog.d(TAG, "onStartUser: u" + userId);
284 }
285 synchronized (mLock) {
286 mRunningUsers.append(userId, true);
287 bindServicesLocked(userId, null, "user start");
288 }
289 }
290
291 /** User lifecycle callback. */
292 private void onUnlockUser(int userId) {
293 if (DEBUG) {
294 Slog.d(TAG, "onUnlockUser: u" + userId);
295 }
296 synchronized (mLock) {
297 bindServicesLocked(userId, null, "user unlock");
298 }
299 }
300
301 /** User lifecycle callback. */
302 private void onStopUser(int userId) {
303 if (DEBUG) {
304 Slog.d(TAG, "onStopUser: u" + userId);
305 }
306 synchronized (mLock) {
307 unbindServicesLocked(userId, null, "user stop");
308
309 mRunningUsers.delete(userId);
310 }
311 }
312
313 private void onUserRemoved(int userId) {
314 if (DEBUG) {
315 Slog.d(TAG, "onUserRemoved: u" + userId);
316 }
317 synchronized (mLock) {
318 forAllAppsLocked((app) -> app.onUserRemoved(userId));
319
320 mRunningUsers.delete(userId);
321 }
322 }
323
324 /**
325 * Called when a target package changes; e.g. when the user changes the default SMS app.
326 */
327 private void onAppChanged(AppServiceFinder finder, int userId) {
328 if (DEBUG) {
329 Slog.d(TAG, "onAppChanged: u" + userId + " " + finder.getAppDescription());
330 }
331 synchronized (mLock) {
332 final String reason = finder.getAppDescription() + " changed";
333 unbindServicesLocked(userId, finder, reason);
334 bindServicesLocked(userId, finder, reason);
335 }
336 }
337
338 @Nullable
339 private AppServiceFinder findFinderLocked(int userId, @NonNull String packageName) {
340 for (int i = 0; i < mApps.size(); i++) {
341 final AppServiceFinder app = mApps.get(i);
342 if (packageName.equals(app.getTargetPackage(userId))) {
343 return app;
344 }
345 }
346 return null;
347 }
348
349 @Nullable
350 private AppServiceConnection findConnectionLock(
351 int userId, @NonNull AppServiceFinder target) {
352 for (int i = 0; i < mConnections.size(); i++) {
353 final AppServiceConnection conn = mConnections.get(i);
354 if ((conn.getUserId() == userId) && (conn.getFinder() == target)) {
355 return conn;
356 }
357 }
358 return null;
359 }
360
361 private void handlePackageAddedReplacing(String packageName, int userId) {
362 if (DEBUG) {
363 Slog.d(TAG, "handlePackageAddedReplacing: u" + userId + " " + packageName);
364 }
365 synchronized (mLock) {
366 final AppServiceFinder finder = findFinderLocked(userId, packageName);
367 if (finder != null) {
368 unbindServicesLocked(userId, finder, "package update");
369 bindServicesLocked(userId, finder, "package update");
370 }
371 }
372 }
373
374 private void handlePackageRemoved(String packageName, int userId) {
375 if (DEBUG) {
376 Slog.d(TAG, "handlePackageRemoved: u" + userId + " " + packageName);
377 }
378 synchronized (mLock) {
379 final AppServiceFinder finder = findFinderLocked(userId, packageName);
380 if (finder != null) {
381 unbindServicesLocked(userId, finder, "package uninstall");
382 }
383 }
384 }
385
386 private void handlePackageChanged(String packageName, int userId) {
387 if (DEBUG) {
388 Slog.d(TAG, "handlePackageChanged: u" + userId + " " + packageName);
389 }
390 synchronized (mLock) {
391 final AppServiceFinder finder = findFinderLocked(userId, packageName);
392 if (finder != null) {
393 unbindServicesLocked(userId, finder, "package changed");
394 bindServicesLocked(userId, finder, "package changed");
395 }
396 }
397 }
398
399 private void rebindAllLocked(String reason) {
400 for (int i = 0; i < mRunningUsers.size(); i++) {
401 if (!mRunningUsers.valueAt(i)) {
402 continue;
403 }
404 final int userId = mRunningUsers.keyAt(i);
405
406 unbindServicesLocked(userId, null, reason);
407 bindServicesLocked(userId, null, reason);
408 }
409 }
410
411 private void bindServicesLocked(int userId, @Nullable AppServiceFinder target,
412 @NonNull String reasonForLog) {
413 for (int i = 0; i < mApps.size(); i++) {
414 final AppServiceFinder app = mApps.get(i);
415 if (target != null && target != app) {
416 continue;
417 }
418
419 // Disconnect from existing binding.
420 final AppServiceConnection existingConn = findConnectionLock(userId, app);
421 if (existingConn != null) {
422 unbindServicesLocked(userId, target, reasonForLog);
423 }
424
Makoto Onuki7a2d35e2018-10-03 11:15:52 -0700425 final ServiceInfo service = app.findService(userId, mIPackageManager, mConstants);
Makoto Onuki87d260a2018-09-26 16:58:32 -0700426 if (service == null) {
427 continue;
428 }
429 if (DEBUG) {
430 Slog.d(TAG, "bindServicesLocked: u" + userId + " " + app.getAppDescription()
431 + " binding " + service.getComponentName() + " for " + reasonForLog);
432 }
433 final AppServiceConnection conn =
434 new AppServiceConnection(mContext, userId, mConstants, mHandler,
435 app, service.getComponentName());
436 mConnections.add(conn);
437 conn.bind();
438 }
439 }
440
441 private void unbindServicesLocked(int userId, @Nullable AppServiceFinder target,
442 @NonNull String reasonForLog) {
443 for (int i = mConnections.size() - 1; i >= 0; i--) {
444 final AppServiceConnection conn = mConnections.get(i);
445 if ((conn.getUserId() != userId)
446 || (target != null && conn.getFinder() != target)) {
447 continue;
448 }
449 if (DEBUG) {
450 Slog.d(TAG, "unbindServicesLocked: u" + userId
451 + " " + conn.getFinder().getAppDescription()
452 + " unbinding " + conn.getComponentName() + " for " + reasonForLog);
453 }
454 mConnections.remove(i);
455 conn.unbind();
456 }
457 }
458
459 private static class AppServiceConnection extends PersistentConnection<IInterface> {
460 private final AppBindingConstants mConstants;
461 private final AppServiceFinder mFinder;
462
463 AppServiceConnection(Context context, int userId, AppBindingConstants constants,
464 Handler handler, AppServiceFinder finder,
465 @NonNull ComponentName componentName) {
466 super(TAG, context, handler, userId, componentName,
467 constants.SERVICE_RECONNECT_BACKOFF_SEC,
468 constants.SERVICE_RECONNECT_BACKOFF_INCREASE,
Makoto Onuki8c7c5cc2018-10-02 09:29:58 -0700469 constants.SERVICE_RECONNECT_MAX_BACKOFF_SEC,
470 constants.SERVICE_STABLE_CONNECTION_THRESHOLD_SEC);
Makoto Onuki87d260a2018-09-26 16:58:32 -0700471 mFinder = finder;
472 mConstants = constants;
473 }
474
475 @Override
476 protected int getBindFlags() {
Makoto Onuki8c7c5cc2018-10-02 09:29:58 -0700477 return mFinder.getBindFlags(mConstants);
Makoto Onuki87d260a2018-09-26 16:58:32 -0700478 }
479
480 @Override
481 protected IInterface asInterface(IBinder obj) {
482 return mFinder.asInterface(obj);
483 }
484
485 public AppServiceFinder getFinder() {
486 return mFinder;
487 }
Makoto Onukidf7e4812018-09-24 14:31:25 -0700488 }
489
490 @Override
491 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
492 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Makoto Onuki87d260a2018-09-26 16:58:32 -0700493
494 if (args.length > 0 && "-s".equals(args[0])) {
495 dumpSimple(pw);
496 return;
497 }
498
499 synchronized (mLock) {
500 mConstants.dump(" ", pw);
501
502 pw.println();
503 pw.print(" Running users:");
504 for (int i = 0; i < mRunningUsers.size(); i++) {
505 if (mRunningUsers.valueAt(i)) {
506 pw.print(" ");
507 pw.print(mRunningUsers.keyAt(i));
508 }
509 }
510
511 pw.println();
512 pw.println(" Connections:");
513 for (int i = 0; i < mConnections.size(); i++) {
514 final AppServiceConnection conn = mConnections.get(i);
515 pw.print(" App type: ");
516 pw.print(conn.getFinder().getAppDescription());
517 pw.println();
518
519 conn.dump(" ", pw);
520 }
521 if (mConnections.size() == 0) {
522 pw.println(" None:");
523 }
524
525 pw.println();
526 pw.println(" Finders:");
527 forAllAppsLocked((app) -> app.dump(" ", pw));
528 }
529 }
530
531 /**
532 * Print simple output for CTS.
533 */
534 private void dumpSimple(PrintWriter pw) {
535 synchronized (mLock) {
536 for (int i = 0; i < mConnections.size(); i++) {
537 final AppServiceConnection conn = mConnections.get(i);
538
539 pw.print("conn,");
540 pw.print(conn.getFinder().getAppDescription());
541 pw.print(",");
542 pw.print(conn.getUserId());
543 pw.print(",");
544 pw.print(conn.getComponentName().getPackageName());
545 pw.print(",");
546 pw.print(conn.getComponentName().getClassName());
547 pw.print(",");
548 pw.print(conn.isBound() ? "bound" : "not-bound");
549 pw.print(",");
550 pw.print(conn.isConnected() ? "connected" : "not-connected");
Makoto Onuki8c7c5cc2018-10-02 09:29:58 -0700551 pw.print(",#con=");
552 pw.print(conn.getNumConnected());
553 pw.print(",#dis=");
554 pw.print(conn.getNumDisconnected());
555 pw.print(",#died=");
556 pw.print(conn.getNumBindingDied());
557 pw.print(",backoff=");
558 pw.print(conn.getNextBackoffMs());
Makoto Onuki87d260a2018-09-26 16:58:32 -0700559 pw.println();
560 }
561 forAllAppsLocked((app) -> app.dumpSimple(pw));
562 }
Makoto Onukidf7e4812018-09-24 14:31:25 -0700563 }
Makoto Onuki8c7c5cc2018-10-02 09:29:58 -0700564
565 AppBindingConstants getConstantsForTest() {
566 return mConstants;
567 }
Makoto Onukidf7e4812018-09-24 14:31:25 -0700568}