blob: 383e25a6d293c50737ef53c2690283149cdc3e5b [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
Jeff Sharkey58482c552016-02-08 17:49:17 -070019import android.annotation.Nullable;
Victoria Lease03cdd3d2013-02-01 15:15:54 -080020import android.content.BroadcastReceiver;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070021import android.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
Victoria Lease03cdd3d2013-02-01 15:15:54 -080024import android.content.IntentFilter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070025import android.content.ServiceConnection;
26import android.content.pm.PackageInfo;
27import android.content.pm.PackageManager;
28import android.content.pm.PackageManager.NameNotFoundException;
29import android.content.pm.ResolveInfo;
30import android.content.pm.Signature;
Zhentao Sunc5fc9982013-04-17 17:47:53 -070031import android.content.res.Resources;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070032import android.os.Handler;
33import android.os.IBinder;
Victoria Leaseb711d572012-10-02 13:14:11 -070034import android.os.UserHandle;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070035import android.util.Log;
Jeff Sharkey58482c552016-02-08 17:49:17 -070036import android.util.Slog;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070037
Jeff Sharkey58482c552016-02-08 17:49:17 -070038import com.android.internal.annotations.GuardedBy;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070039import com.android.internal.content.PackageMonitor;
40
41import java.util.ArrayList;
42import java.util.Arrays;
43import java.util.HashSet;
44import java.util.List;
Jeff Sharkey58482c552016-02-08 17:49:17 -070045import java.util.Objects;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070046
47/**
48 * Find the best Service, and bind to it.
49 * Handles run-time package changes.
50 */
51public class ServiceWatcher implements ServiceConnection {
52 private static final boolean D = false;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050053 public static final String EXTRA_SERVICE_VERSION = "serviceVersion";
Victoria Lease03cdd3d2013-02-01 15:15:54 -080054 public static final String EXTRA_SERVICE_IS_MULTIUSER = "serviceIsMultiuser";
Nick Pelly6fa9ad42012-07-16 12:18:23 -070055
56 private final String mTag;
57 private final Context mContext;
58 private final PackageManager mPm;
59 private final List<HashSet<Signature>> mSignatureSets;
60 private final String mAction;
Zhentao Sunc5fc9982013-04-17 17:47:53 -070061
62 /**
63 * If mServicePackageName is not null, only this package will be searched for the service that
64 * implements mAction. When null, all packages in the system that matches one of the signature
65 * in mSignatureSets are searched.
66 */
67 private final String mServicePackageName;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070068 private final Runnable mNewServiceWork;
69 private final Handler mHandler;
70
Jeff Sharkey58482c552016-02-08 17:49:17 -070071 private final Object mLock = new Object();
Nick Pelly6fa9ad42012-07-16 12:18:23 -070072
Jeff Sharkey58482c552016-02-08 17:49:17 -070073 @GuardedBy("mLock")
74 private int mCurrentUserId = UserHandle.USER_SYSTEM;
75
76 @GuardedBy("mLock")
77 private IBinder mBoundService;
78 @GuardedBy("mLock")
79 private ComponentName mBoundComponent;
80 @GuardedBy("mLock")
81 private String mBoundPackageName;
82 @GuardedBy("mLock")
83 private int mBoundVersion = Integer.MIN_VALUE;
84 @GuardedBy("mLock")
85 private int mBoundUserId = UserHandle.USER_NULL;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070086
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050087 public static ArrayList<HashSet<Signature>> getSignatureSets(Context context,
88 List<String> initialPackageNames) {
89 PackageManager pm = context.getPackageManager();
90 ArrayList<HashSet<Signature>> sigSets = new ArrayList<HashSet<Signature>>();
91 for (int i = 0, size = initialPackageNames.size(); i < size; i++) {
92 String pkg = initialPackageNames.get(i);
93 try {
94 HashSet<Signature> set = new HashSet<Signature>();
Jeff Sharkeyc7bacab2016-02-09 15:56:11 -070095 Signature[] sigs = pm.getPackageInfo(pkg, PackageManager.MATCH_SYSTEM_ONLY
96 | PackageManager.GET_SIGNATURES).signatures;
Jeff Hamiltonfbadb692012-10-05 14:21:58 -050097 set.addAll(Arrays.asList(sigs));
98 sigSets.add(set);
99 } catch (NameNotFoundException e) {
100 Log.w("ServiceWatcher", pkg + " not found");
101 }
102 }
103 return sigSets;
104 }
105
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700106 public ServiceWatcher(Context context, String logTag, String action,
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700107 int overlaySwitchResId, int defaultServicePackageNameResId,
108 int initialPackageNamesResId, Runnable newServiceWork,
109 Handler handler) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700110 mContext = context;
111 mTag = logTag;
112 mAction = action;
113 mPm = mContext.getPackageManager();
114 mNewServiceWork = newServiceWork;
115 mHandler = handler;
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700116 Resources resources = context.getResources();
117
118 // Whether to enable service overlay.
119 boolean enableOverlay = resources.getBoolean(overlaySwitchResId);
Jeff Sharkey58482c552016-02-08 17:49:17 -0700120 ArrayList<String> initialPackageNames = new ArrayList<String>();
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700121 if (enableOverlay) {
122 // A list of package names used to create the signatures.
123 String[] pkgs = resources.getStringArray(initialPackageNamesResId);
124 if (pkgs != null) initialPackageNames.addAll(Arrays.asList(pkgs));
125 mServicePackageName = null;
126 if (D) Log.d(mTag, "Overlay enabled, packages=" + Arrays.toString(pkgs));
127 } else {
128 // The default package name that is searched for service implementation when overlay is
129 // disabled.
130 String servicePackageName = resources.getString(defaultServicePackageNameResId);
131 if (servicePackageName != null) initialPackageNames.add(servicePackageName);
132 mServicePackageName = servicePackageName;
133 if (D) Log.d(mTag, "Overlay disabled, default package=" + servicePackageName);
134 }
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500135 mSignatureSets = getSignatureSets(context, initialPackageNames);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700136 }
137
Jeff Sharkey58482c552016-02-08 17:49:17 -0700138 /**
139 * Start this watcher, including binding to the current best match and
140 * re-binding to any better matches down the road.
141 * <p>
142 * Note that if there are no matching encryption-aware services, we may not
143 * bind to a real service until after the current user is unlocked.
144 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700145 public boolean start() {
Victoria Leaseb711d572012-10-02 13:14:11 -0700146 synchronized (mLock) {
Jeff Sharkey58482c552016-02-08 17:49:17 -0700147 bindBestPackageLocked(mServicePackageName, false);
Victoria Leaseb711d572012-10-02 13:14:11 -0700148 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700149
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800150 // listen for user change
151 IntentFilter intentFilter = new IntentFilter();
152 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Jeff Sharkey58482c552016-02-08 17:49:17 -0700153 intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800154 mContext.registerReceiverAsUser(new BroadcastReceiver() {
155 @Override
156 public void onReceive(Context context, Intent intent) {
Jeff Sharkey58482c552016-02-08 17:49:17 -0700157 final String action = intent.getAction();
158 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
159 UserHandle.USER_NULL);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800160 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
Jeff Sharkey58482c552016-02-08 17:49:17 -0700161 switchUser(userId);
162 } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
163 unlockUser(userId);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800164 }
165 }
166 }, UserHandle.ALL, intentFilter, null, mHandler);
167
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700168 // listen for relevant package changes if service overlay is enabled.
169 if (mServicePackageName == null) {
170 mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
171 }
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800172
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700173 return true;
174 }
175
176 /**
Jeff Sharkey58482c552016-02-08 17:49:17 -0700177 * Searches and binds to the best package, or do nothing if the best package
178 * is already bound, unless force rebinding is requested.
179 *
180 * @param justCheckThisPackage Only consider this package, or consider all
181 * packages if it is {@code null}.
182 * @param forceRebind Force a rebinding to the best package if it's already
183 * bound.
184 * @return {@code true} if a valid package was found to bind to.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700185 */
Jeff Sharkey58482c552016-02-08 17:49:17 -0700186 private boolean bindBestPackageLocked(String justCheckThisPackage, boolean forceRebind) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700187 Intent intent = new Intent(mAction);
188 if (justCheckThisPackage != null) {
189 intent.setPackage(justCheckThisPackage);
190 }
Jeff Sharkey58482c552016-02-08 17:49:17 -0700191 final List<ResolveInfo> rInfos = mPm.queryIntentServicesAsUser(intent,
192 PackageManager.GET_META_DATA | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
193 mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700194 int bestVersion = Integer.MIN_VALUE;
Jeff Sharkey58482c552016-02-08 17:49:17 -0700195 ComponentName bestComponent = null;
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800196 boolean bestIsMultiuser = false;
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700197 if (rInfos != null) {
198 for (ResolveInfo rInfo : rInfos) {
Jeff Sharkey58482c552016-02-08 17:49:17 -0700199 final ComponentName component = rInfo.serviceInfo.getComponentName();
200 final String packageName = component.getPackageName();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700201
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700202 // check signature
203 try {
204 PackageInfo pInfo;
Jeff Sharkey58482c552016-02-08 17:49:17 -0700205 pInfo = mPm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES
206 | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700207 if (!isSignatureMatch(pInfo.signatures)) {
208 Log.w(mTag, packageName + " resolves service " + mAction
209 + ", but has wrong signature, ignoring");
210 continue;
211 }
212 } catch (NameNotFoundException e) {
213 Log.wtf(mTag, e);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700214 continue;
215 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700216
217 // check metadata
218 int version = Integer.MIN_VALUE;
219 boolean isMultiuser = false;
220 if (rInfo.serviceInfo.metaData != null) {
221 version = rInfo.serviceInfo.metaData.getInt(
222 EXTRA_SERVICE_VERSION, Integer.MIN_VALUE);
223 isMultiuser = rInfo.serviceInfo.metaData.getBoolean(EXTRA_SERVICE_IS_MULTIUSER);
224 }
225
Jeff Sharkey58482c552016-02-08 17:49:17 -0700226 if (version > bestVersion) {
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700227 bestVersion = version;
Jeff Sharkey58482c552016-02-08 17:49:17 -0700228 bestComponent = component;
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700229 bestIsMultiuser = isMultiuser;
230 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700231 }
232
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700233 if (D) {
234 Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction,
235 (justCheckThisPackage == null ? ""
236 : "(" + justCheckThisPackage + ") "), rInfos.size(),
Jeff Sharkey58482c552016-02-08 17:49:17 -0700237 (bestComponent == null ? "no new best component"
238 : "new best component: " + bestComponent)));
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700239 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700240 } else {
241 if (D) Log.d(mTag, "Unable to query intent services for action: " + mAction);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700242 }
Jeff Sharkey58482c552016-02-08 17:49:17 -0700243
244 if (bestComponent == null) {
245 Slog.w(mTag, "Odd, no component found for service " + mAction);
246 unbindLocked();
247 return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700248 }
Jeff Sharkey58482c552016-02-08 17:49:17 -0700249
250 final int userId = bestIsMultiuser ? UserHandle.USER_SYSTEM : mCurrentUserId;
251 final boolean alreadyBound = Objects.equals(bestComponent, mBoundComponent)
252 && bestVersion == mBoundVersion && userId == mBoundUserId;
253 if (forceRebind || !alreadyBound) {
254 unbindLocked();
255 bindToPackageLocked(bestComponent, bestVersion, userId);
256 }
257 return true;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700258 }
259
Victoria Leaseb711d572012-10-02 13:14:11 -0700260 private void unbindLocked() {
Jeff Sharkey58482c552016-02-08 17:49:17 -0700261 ComponentName component;
262 component = mBoundComponent;
263 mBoundComponent = null;
264 mBoundPackageName = null;
265 mBoundVersion = Integer.MIN_VALUE;
266 mBoundUserId = UserHandle.USER_NULL;
267 if (component != null) {
268 if (D) Log.d(mTag, "unbinding " + component);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700269 mContext.unbindService(this);
270 }
271 }
272
Jeff Sharkey58482c552016-02-08 17:49:17 -0700273 private void bindToPackageLocked(ComponentName component, int version, int userId) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700274 Intent intent = new Intent(mAction);
Jeff Sharkey58482c552016-02-08 17:49:17 -0700275 intent.setComponent(component);
276 mBoundComponent = component;
277 mBoundPackageName = component.getPackageName();
278 mBoundVersion = version;
279 mBoundUserId = userId;
280 if (D) Log.d(mTag, "binding " + component + " (v" + version + ") (u" + userId + ")");
281 mContext.bindServiceAsUser(intent, this,
282 Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE,
283 new UserHandle(userId));
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700284 }
285
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500286 public static boolean isSignatureMatch(Signature[] signatures,
287 List<HashSet<Signature>> sigSets) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700288 if (signatures == null) return false;
289
290 // build hashset of input to test against
291 HashSet<Signature> inputSet = new HashSet<Signature>();
292 for (Signature s : signatures) {
293 inputSet.add(s);
294 }
295
296 // test input against each of the signature sets
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500297 for (HashSet<Signature> referenceSet : sigSets) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700298 if (referenceSet.equals(inputSet)) {
299 return true;
300 }
301 }
302 return false;
303 }
304
Jeff Hamiltonfbadb692012-10-05 14:21:58 -0500305 private boolean isSignatureMatch(Signature[] signatures) {
306 return isSignatureMatch(signatures, mSignatureSets);
307 }
308
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700309 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
310 /**
311 * Called when package has been reinstalled
312 */
313 @Override
314 public void onPackageUpdateFinished(String packageName, int uid) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700315 synchronized (mLock) {
Jeff Sharkey58482c552016-02-08 17:49:17 -0700316 final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
317 bindBestPackageLocked(null, forceRebind);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700318 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700319 }
320
321 @Override
322 public void onPackageAdded(String packageName, int uid) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700323 synchronized (mLock) {
Jeff Sharkey58482c552016-02-08 17:49:17 -0700324 final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
325 bindBestPackageLocked(null, forceRebind);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700326 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700327 }
328
329 @Override
330 public void onPackageRemoved(String packageName, int uid) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700331 synchronized (mLock) {
Jeff Sharkey58482c552016-02-08 17:49:17 -0700332 final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
333 bindBestPackageLocked(null, forceRebind);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700334 }
335 }
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700336
337 @Override
338 public boolean onPackageChanged(String packageName, int uid, String[] components) {
339 synchronized (mLock) {
Jeff Sharkey58482c552016-02-08 17:49:17 -0700340 final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
341 bindBestPackageLocked(null, forceRebind);
Zhentao Sunc5fc9982013-04-17 17:47:53 -0700342 }
343 return super.onPackageChanged(packageName, uid, components);
344 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700345 };
346
347 @Override
Jeff Sharkey58482c552016-02-08 17:49:17 -0700348 public void onServiceConnected(ComponentName component, IBinder binder) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700349 synchronized (mLock) {
Jeff Sharkey58482c552016-02-08 17:49:17 -0700350 if (component.equals(mBoundComponent)) {
351 if (D) Log.d(mTag, component + " connected");
352 mBoundService = binder;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700353 if (mHandler !=null && mNewServiceWork != null) {
354 mHandler.post(mNewServiceWork);
355 }
356 } else {
Jeff Sharkey58482c552016-02-08 17:49:17 -0700357 Log.w(mTag, "unexpected onServiceConnected: " + component);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700358 }
359 }
360 }
361
362 @Override
Jeff Sharkey58482c552016-02-08 17:49:17 -0700363 public void onServiceDisconnected(ComponentName component) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700364 synchronized (mLock) {
Jeff Sharkey58482c552016-02-08 17:49:17 -0700365 if (D) Log.d(mTag, component + " disconnected");
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700366
Jeff Sharkey58482c552016-02-08 17:49:17 -0700367 if (component.equals(mBoundComponent)) {
368 mBoundService = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700369 }
370 }
371 }
372
Jeff Sharkey58482c552016-02-08 17:49:17 -0700373 public @Nullable String getBestPackageName() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700374 synchronized (mLock) {
Jeff Sharkey58482c552016-02-08 17:49:17 -0700375 return mBoundPackageName;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700376 }
377 }
378
379 public int getBestVersion() {
380 synchronized (mLock) {
Jeff Sharkey58482c552016-02-08 17:49:17 -0700381 return mBoundVersion;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700382 }
383 }
384
Jeff Sharkey58482c552016-02-08 17:49:17 -0700385 public @Nullable IBinder getBinder() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700386 synchronized (mLock) {
Jeff Sharkey58482c552016-02-08 17:49:17 -0700387 return mBoundService;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700388 }
389 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700390
Jeff Sharkey58482c552016-02-08 17:49:17 -0700391 public void switchUser(int userId) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700392 synchronized (mLock) {
Jeff Sharkey58482c552016-02-08 17:49:17 -0700393 mCurrentUserId = userId;
394 bindBestPackageLocked(mServicePackageName, false);
395 }
396 }
397
398 public void unlockUser(int userId) {
399 synchronized (mLock) {
400 if (userId == mCurrentUserId) {
401 bindBestPackageLocked(mServicePackageName, false);
Victoria Lease03cdd3d2013-02-01 15:15:54 -0800402 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700403 }
404 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700405}