blob: cfb79aa3a210e73ae1364a13c01022ed0bab88ff [file] [log] [blame]
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001/*
2 * Copyright (C) 2012 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;
18
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -080019import static android.content.Context.BIND_AUTO_CREATE;
20import static android.content.Context.BIND_NOT_FOREGROUND;
21import static android.content.Context.BIND_NOT_VISIBLE;
22import static android.content.pm.PackageManager.GET_META_DATA;
23import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO;
24import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
25import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
26import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
27
28import android.annotation.BoolRes;
Jeff Sharkey58482c552016-02-08 17:49:17 -070029import android.annotation.Nullable;
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -080030import android.annotation.StringRes;
31import android.annotation.UserIdInt;
Soonil Nagarkare731ca82018-11-02 13:55:51 -070032import android.app.ActivityManager;
Victoria Lease03cdd3d2013-02-01 15:15:54 -080033import android.content.BroadcastReceiver;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070034import android.content.ComponentName;
35import android.content.Context;
36import android.content.Intent;
Victoria Lease03cdd3d2013-02-01 15:15:54 -080037import android.content.IntentFilter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070038import android.content.ServiceConnection;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070039import android.content.pm.ResolveInfo;
Zhentao Sunc5fc9982013-04-17 17:47:53 -070040import android.content.res.Resources;
Soonil Nagarkare731ca82018-11-02 13:55:51 -070041import android.os.Bundle;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070042import android.os.Handler;
43import android.os.IBinder;
Soonil Nagarkare731ca82018-11-02 13:55:51 -070044import android.os.Looper;
Soonil Nagarkar192710b2019-01-24 17:42:49 -080045import android.os.RemoteException;
Victoria Leaseb711d572012-10-02 13:14:11 -070046import android.os.UserHandle;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070047import android.util.Log;
48
49import com.android.internal.content.PackageMonitor;
Soonil Nagarkare731ca82018-11-02 13:55:51 -070050import com.android.internal.util.Preconditions;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070051
Soonil Nagarkar3b4e8a62020-01-31 22:57:05 -080052import java.io.FileDescriptor;
53import java.io.PrintWriter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070054import java.util.List;
Jeff Sharkey58482c552016-02-08 17:49:17 -070055import java.util.Objects;
Soonil Nagarkar192710b2019-01-24 17:42:49 -080056import java.util.concurrent.Callable;
57import java.util.concurrent.ExecutionException;
58import java.util.concurrent.FutureTask;
Soonil Nagarkar93ff5b82019-10-29 13:34:26 -070059import java.util.concurrent.TimeUnit;
60import java.util.concurrent.TimeoutException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070061
62/**
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -080063 * Maintains a binding to the best service that matches the given intent information. Bind and
64 * unbind callbacks, as well as all binder operations, will all be run on the given handler.
Nick Pelly6fa9ad42012-07-16 12:18:23 -070065 */
66public class ServiceWatcher implements ServiceConnection {
Soonil Nagarkare731ca82018-11-02 13:55:51 -070067
68 private static final String TAG = "ServiceWatcher";
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -080069 private static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
Soonil Nagarkare731ca82018-11-02 13:55:51 -070070
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -080071 private static final String EXTRA_SERVICE_VERSION = "serviceVersion";
72 private static final String EXTRA_SERVICE_IS_MULTIUSER = "serviceIsMultiuser";
Nick Pelly6fa9ad42012-07-16 12:18:23 -070073
Soonil Nagarkar93ff5b82019-10-29 13:34:26 -070074 private static final long BLOCKING_BINDER_TIMEOUT_MS = 30 * 1000;
Soonil Nagarkar192710b2019-01-24 17:42:49 -080075
76 /** Function to run on binder interface. */
Soonil Nagarkare731ca82018-11-02 13:55:51 -070077 public interface BinderRunner {
Soonil Nagarkar192710b2019-01-24 17:42:49 -080078 /** Called to run client code with the binder. */
79 void run(IBinder binder) throws RemoteException;
80 }
81
82 /**
83 * Function to run on binder interface.
84 * @param <T> Type to return.
85 */
86 public interface BlockingBinderRunner<T> {
87 /** Called to run client code with the binder. */
88 T run(IBinder binder) throws RemoteException;
Soonil Nagarkare731ca82018-11-02 13:55:51 -070089 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -070090
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -080091 /**
92 * Information on the service ServiceWatcher has selected as the best option for binding.
93 */
94 public static final class ServiceInfo implements Comparable<ServiceInfo> {
Soonil Nagarkare731ca82018-11-02 13:55:51 -070095
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -080096 public static final ServiceInfo NONE = new ServiceInfo(Integer.MIN_VALUE, null,
97 UserHandle.USER_NULL);
Soonil Nagarkare731ca82018-11-02 13:55:51 -070098
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -080099 public final int version;
100 @Nullable public final ComponentName component;
101 @UserIdInt public final int userId;
102
Soonil Nagarkar705b6af2020-03-10 17:27:50 -0700103 ServiceInfo(ResolveInfo resolveInfo, int currentUserId) {
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800104 Preconditions.checkArgument(resolveInfo.serviceInfo.getComponentName() != null);
105
106 Bundle metadata = resolveInfo.serviceInfo.metaData;
107 boolean isMultiuser;
108 if (metadata != null) {
109 version = metadata.getInt(EXTRA_SERVICE_VERSION, Integer.MIN_VALUE);
110 isMultiuser = metadata.getBoolean(EXTRA_SERVICE_IS_MULTIUSER, false);
111 } else {
112 version = Integer.MIN_VALUE;
113 isMultiuser = false;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500114 }
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800115
116 component = resolveInfo.serviceInfo.getComponentName();
117 userId = isMultiuser ? UserHandle.USER_SYSTEM : currentUserId;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500118 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500119
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800120 private ServiceInfo(int version, @Nullable ComponentName component, int userId) {
121 Preconditions.checkArgument(component != null || version == Integer.MIN_VALUE);
122 this.version = version;
123 this.component = component;
124 this.userId = userId;
125 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700126
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800127 @Override
128 public boolean equals(Object o) {
129 if (this == o) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700130 return true;
131 }
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800132 if (!(o instanceof ServiceInfo)) {
133 return false;
134 }
135 ServiceInfo that = (ServiceInfo) o;
136 return version == that.version && userId == that.userId
137 && Objects.equals(component, that.component);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700138 }
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800139
140 @Override
141 public int hashCode() {
142 return Objects.hash(version, component, userId);
143 }
144
145 @Override
146 public int compareTo(ServiceInfo that) {
147 // ServiceInfos with higher version numbers always win (having a version number >
148 // MIN_VALUE implies having a non-null component). if version numbers are equal, a
149 // non-null component wins over a null component. if the version numbers are equal and
150 // both components exist then we prefer components that work for all users vs components
151 // that only work for a single user at a time. otherwise everything's equal.
152 int ret = Integer.compare(version, that.version);
153 if (ret == 0) {
154 if (component == null && that.component != null) {
155 ret = -1;
156 } else if (component != null && that.component == null) {
157 ret = 1;
158 } else {
159 if (userId != UserHandle.USER_SYSTEM && that.userId == UserHandle.USER_SYSTEM) {
160 ret = -1;
161 } else if (userId == UserHandle.USER_SYSTEM
162 && that.userId != UserHandle.USER_SYSTEM) {
163 ret = 1;
164 }
165 }
166 }
167 return ret;
168 }
169
170 @Override
171 public String toString() {
Soonil Nagarkardd01a322020-01-27 15:28:15 -0800172 return component.toShortString() + "@" + version + "[u" + userId + "]";
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800173 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700174 }
175
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700176 private final Context mContext;
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700177 private final Handler mHandler;
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800178 private final Intent mIntent;
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700179
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800180 @Nullable private final BinderRunner mOnBind;
181 @Nullable private final Runnable mOnUnbind;
182
183 // read/write from handler thread only
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700184 private int mCurrentUserId;
185
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800186 // write from handler thread only, read anywhere
187 private volatile ServiceInfo mServiceInfo;
Soonil Nagarkar3b4e8a62020-01-31 22:57:05 -0800188 private volatile IBinder mBinder;
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700189
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800190 public ServiceWatcher(Context context, Handler handler, String action,
191 @Nullable BinderRunner onBind, @Nullable Runnable onUnbind,
192 @BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId) {
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700193 mContext = context;
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800194 mHandler = FgThread.getHandler();
195 mIntent = new Intent(Objects.requireNonNull(action));
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700196
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800197 Resources resources = context.getResources();
198 boolean enableOverlay = resources.getBoolean(enableOverlayResId);
199 if (!enableOverlay) {
200 mIntent.setPackage(resources.getString(nonOverlayPackageResId));
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700201 }
202
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800203 mOnBind = onBind;
204 mOnUnbind = onUnbind;
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700205
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800206 mCurrentUserId = UserHandle.USER_NULL;
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700207
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800208 mServiceInfo = ServiceInfo.NONE;
209 mBinder = null;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500210 }
211
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700212 /**
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800213 * Register this class, which will start the process of determining the best matching service
214 * and maintaining a binding to it. Will return false and fail if there are no possible matching
215 * services at the time this functions is called.
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700216 */
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800217 public boolean register() {
218 if (mContext.getPackageManager().queryIntentServicesAsUser(mIntent,
219 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE | MATCH_SYSTEM_ONLY,
220 UserHandle.USER_SYSTEM).isEmpty()) {
221 return false;
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700222 }
223
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800224 new PackageMonitor() {
225 @Override
226 public void onPackageUpdateFinished(String packageName, int uid) {
227 ServiceWatcher.this.onPackageChanged(packageName);
228 }
229
230 @Override
231 public void onPackageAdded(String packageName, int uid) {
232 ServiceWatcher.this.onPackageChanged(packageName);
233 }
234
235 @Override
236 public void onPackageRemoved(String packageName, int uid) {
237 ServiceWatcher.this.onPackageChanged(packageName);
238 }
239
240 @Override
241 public boolean onPackageChanged(String packageName, int uid, String[] components) {
242 ServiceWatcher.this.onPackageChanged(packageName);
243 return super.onPackageChanged(packageName, uid, components);
244 }
245 }.register(mContext, UserHandle.ALL, true, mHandler);
246
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700247 IntentFilter intentFilter = new IntentFilter();
248 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
249 intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
250 mContext.registerReceiverAsUser(new BroadcastReceiver() {
251 @Override
252 public void onReceive(Context context, Intent intent) {
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800253 String action = intent.getAction();
254 if (action == null) {
255 return;
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700256 }
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800257 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
258 if (userId == UserHandle.USER_NULL) {
259 return;
260 }
261
262 switch (action) {
263 case Intent.ACTION_USER_SWITCHED:
264 onUserSwitched(userId);
265 break;
266 case Intent.ACTION_USER_UNLOCKED:
267 onUserUnlocked(userId);
268 break;
269 default:
270 break;
271 }
272
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700273 }
274 }, UserHandle.ALL, intentFilter, null, mHandler);
275
276 mCurrentUserId = ActivityManager.getCurrentUser();
277
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800278 mHandler.post(() -> onBestServiceChanged(false));
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700279 return true;
280 }
281
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800282 /**
283 * Returns information on the currently selected service.
284 */
285 public ServiceInfo getBoundService() {
286 return mServiceInfo;
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700287 }
288
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800289 private void onBestServiceChanged(boolean forceRebind) {
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700290 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
291
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800292 List<ResolveInfo> resolveInfos = mContext.getPackageManager().queryIntentServicesAsUser(
293 mIntent,
294 GET_META_DATA | MATCH_DIRECT_BOOT_AUTO | MATCH_SYSTEM_ONLY,
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700295 mCurrentUserId);
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700296
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800297 ServiceInfo bestServiceInfo = ServiceInfo.NONE;
298 for (ResolveInfo resolveInfo : resolveInfos) {
299 ServiceInfo serviceInfo = new ServiceInfo(resolveInfo, mCurrentUserId);
300 if (serviceInfo.compareTo(bestServiceInfo) > 0) {
301 bestServiceInfo = serviceInfo;
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700302 }
303 }
304
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800305 if (forceRebind || !bestServiceInfo.equals(mServiceInfo)) {
306 rebind(bestServiceInfo);
307 }
308 }
309
310 private void rebind(ServiceInfo newServiceInfo) {
311 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
312
313 if (!mServiceInfo.equals(ServiceInfo.NONE)) {
314 if (D) {
315 Log.i(TAG, "[" + mIntent.getAction() + "] unbinding from " + mServiceInfo);
316 }
317
318 mContext.unbindService(this);
Soonil Nagarkar705b6af2020-03-10 17:27:50 -0700319 onServiceDisconnected(mServiceInfo.component);
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800320 mServiceInfo = ServiceInfo.NONE;
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700321 }
322
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800323 mServiceInfo = newServiceInfo;
324 if (mServiceInfo.equals(ServiceInfo.NONE)) {
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700325 return;
326 }
327
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800328 Preconditions.checkState(mServiceInfo.component != null);
329
330 if (D) {
331 Log.i(TAG, getLogPrefix() + " binding to " + mServiceInfo);
332 }
333
334 Intent bindIntent = new Intent(mIntent).setComponent(mServiceInfo.component);
335 mContext.bindServiceAsUser(bindIntent, this,
336 BIND_AUTO_CREATE | BIND_NOT_FOREGROUND | BIND_NOT_VISIBLE,
337 mHandler, UserHandle.of(mServiceInfo.userId));
338 }
339
340 @Override
341 public final void onServiceConnected(ComponentName component, IBinder binder) {
342 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
Soonil Nagarkar705b6af2020-03-10 17:27:50 -0700343 Preconditions.checkState(mBinder == null);
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800344
345 if (D) {
Soonil Nagarkared5a2002020-01-28 10:53:53 -0800346 Log.i(TAG, getLogPrefix() + " connected to " + component.toShortString());
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800347 }
348
349 mBinder = binder;
350 if (mOnBind != null) {
Soonil Nagarkar3b4e8a62020-01-31 22:57:05 -0800351 try {
352 mOnBind.run(binder);
353 } catch (RuntimeException | RemoteException e) {
354 // binders may propagate some specific non-RemoteExceptions from the other side
355 // through the binder as well - we cannot allow those to crash the system server
356 Log.e(TAG, getLogPrefix() + " exception running on " + mServiceInfo, e);
357 }
Soonil Nagarkared5a2002020-01-28 10:53:53 -0800358 }
Soonil Nagarkared5a2002020-01-28 10:53:53 -0800359 }
360
361 @Override
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800362 public final void onServiceDisconnected(ComponentName component) {
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700363 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
364
Soonil Nagarkar705b6af2020-03-10 17:27:50 -0700365 if (mBinder == null) {
366 return;
367 }
368
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800369 if (D) {
Soonil Nagarkared5a2002020-01-28 10:53:53 -0800370 Log.i(TAG, getLogPrefix() + " disconnected from " + component.toShortString());
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700371 }
372
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800373 mBinder = null;
374 if (mOnUnbind != null) {
375 mOnUnbind.run();
376 }
377 }
378
Soonil Nagarkar3b4e8a62020-01-31 22:57:05 -0800379 @Override
380 public void onBindingDied(ComponentName component) {
381 Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
382
383 if (D) {
384 Log.i(TAG, getLogPrefix() + " " + component.toShortString() + " died");
385 }
386
387 onBestServiceChanged(true);
388 }
389
Soonil Nagarkar705b6af2020-03-10 17:27:50 -0700390 void onUserSwitched(@UserIdInt int userId) {
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800391 mCurrentUserId = userId;
392 onBestServiceChanged(false);
393 }
394
Soonil Nagarkar705b6af2020-03-10 17:27:50 -0700395 void onUserUnlocked(@UserIdInt int userId) {
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800396 if (userId == mCurrentUserId) {
397 onBestServiceChanged(false);
398 }
399 }
400
Soonil Nagarkar705b6af2020-03-10 17:27:50 -0700401 void onPackageChanged(String packageName) {
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800402 // force a rebind if the changed package was the currently connected package
403 String currentPackageName =
404 mServiceInfo.component != null ? mServiceInfo.component.getPackageName() : null;
405 onBestServiceChanged(packageName.equals(currentPackageName));
Soonil Nagarkare731ca82018-11-02 13:55:51 -0700406 }
407
Soonil Nagarkar192710b2019-01-24 17:42:49 -0800408 /**
Soonil Nagarkared5a2002020-01-28 10:53:53 -0800409 * Runs the given function asynchronously if and only if currently connected. Suppresses any
410 * RemoteException thrown during execution.
Soonil Nagarkar192710b2019-01-24 17:42:49 -0800411 */
412 public final void runOnBinder(BinderRunner runner) {
Soonil Nagarkar3b4e8a62020-01-31 22:57:05 -0800413 mHandler.post(() -> {
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800414 if (mBinder == null) {
Soonil Nagarkar192710b2019-01-24 17:42:49 -0800415 return;
416 }
417
418 try {
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800419 runner.run(mBinder);
420 } catch (RuntimeException | RemoteException e) {
421 // binders may propagate some specific non-RemoteExceptions from the other side
422 // through the binder as well - we cannot allow those to crash the system server
423 Log.e(TAG, getLogPrefix() + " exception running on " + mServiceInfo, e);
Soonil Nagarkar192710b2019-01-24 17:42:49 -0800424 }
425 });
426 }
427
428 /**
429 * Runs the given function synchronously if currently connected, and returns the default value
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800430 * if not currently connected or if any exception is thrown. Do not obtain any locks within the
431 * BlockingBinderRunner, or risk deadlock. The default value will be returned if there is no
432 * service connection when this is run, if a RemoteException occurs, or if the operation times
433 * out.
Soonil Nagarkarb4707182019-04-02 20:50:02 -0700434 *
435 * @deprecated Using this function is an indication that your AIDL API is broken. Calls from
436 * system server to outside MUST be one-way, and so cannot return any result, and this
437 * method should not be needed or used. Use a separate callback interface to allow outside
438 * components to return results back to the system server.
Soonil Nagarkar192710b2019-01-24 17:42:49 -0800439 */
Soonil Nagarkarb4707182019-04-02 20:50:02 -0700440 @Deprecated
Soonil Nagarkar192710b2019-01-24 17:42:49 -0800441 public final <T> T runOnBinderBlocking(BlockingBinderRunner<T> runner, T defaultValue) {
442 try {
443 return runOnHandlerBlocking(() -> {
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800444 if (mBinder == null) {
Soonil Nagarkar192710b2019-01-24 17:42:49 -0800445 return defaultValue;
446 }
447
448 try {
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800449 return runner.run(mBinder);
450 } catch (RuntimeException | RemoteException e) {
451 // binders may propagate some specific non-RemoteExceptions from the other side
452 // through the binder as well - we cannot allow those to crash the system server
453 Log.e(TAG, getLogPrefix() + " exception running on " + mServiceInfo, e);
Soonil Nagarkar192710b2019-01-24 17:42:49 -0800454 return defaultValue;
455 }
456 });
Soonil Nagarkar93ff5b82019-10-29 13:34:26 -0700457 } catch (InterruptedException | TimeoutException e) {
Soonil Nagarkar192710b2019-01-24 17:42:49 -0800458 return defaultValue;
459 }
460 }
461
Soonil Nagarkar93ff5b82019-10-29 13:34:26 -0700462 private <T> T runOnHandlerBlocking(Callable<T> c)
463 throws InterruptedException, TimeoutException {
Soonil Nagarkar192710b2019-01-24 17:42:49 -0800464 if (Looper.myLooper() == mHandler.getLooper()) {
465 try {
466 return c.call();
467 } catch (Exception e) {
468 // Function cannot throw exception, this should never happen
469 throw new IllegalStateException(e);
470 }
471 } else {
472 FutureTask<T> task = new FutureTask<>(c);
473 mHandler.post(task);
474 try {
Soonil Nagarkar93ff5b82019-10-29 13:34:26 -0700475 // timeout will unblock callers, in particular if the caller is a binder thread to
476 // help reduce binder contention. this will still result in blocking the handler
477 // thread which may result in ANRs, but should make problems slightly more rare.
478 // the underlying solution is simply not to use this API at all, but that would
479 // require large refactors to very legacy code.
480 return task.get(BLOCKING_BINDER_TIMEOUT_MS, TimeUnit.MILLISECONDS);
Soonil Nagarkar192710b2019-01-24 17:42:49 -0800481 } catch (ExecutionException e) {
482 // Function cannot throw exception, this should never happen
483 throw new IllegalStateException(e);
484 }
485 }
486 }
Soonil Nagarkar6d21a4d2020-01-22 16:21:00 -0800487
488 private String getLogPrefix() {
489 return "[" + mIntent.getAction() + "]";
490 }
Soonil Nagarkardd01a322020-01-27 15:28:15 -0800491
492 @Override
493 public String toString() {
494 return mServiceInfo.toString();
495 }
Soonil Nagarkar3b4e8a62020-01-31 22:57:05 -0800496
497 /**
498 * Dump for debugging.
499 */
500 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
501 pw.println("service=" + mServiceInfo);
502 pw.println("connected=" + (mBinder != null));
503 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700504}