blob: a8c3b889421beba281a8d1bd1ae6774018689b4f [file] [log] [blame]
Fred Quintana718d8a22009-04-29 17:53:20 -07001/*
2 * Copyright (C) 2009 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 android.content.pm;
18
Hongming Jin8e2bfc12018-05-30 11:01:06 -070019import android.Manifest;
Mathew Inwood1c77a112018-08-14 14:06:26 +010020import android.annotation.UnsupportedAppUsage;
Fred Quintana718d8a22009-04-29 17:53:20 -070021import android.content.BroadcastReceiver;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070022import android.content.ComponentName;
23import android.content.Context;
Fred Quintana718d8a22009-04-29 17:53:20 -070024import android.content.Intent;
25import android.content.IntentFilter;
Dianne Hackborn20cb56e2010-03-04 00:58:29 -080026import android.content.pm.PackageManager.NameNotFoundException;
27import android.content.res.Resources;
Fred Quintana718d8a22009-04-29 17:53:20 -070028import android.content.res.XmlResourceParser;
Fred Quintana5ebbb4a2009-11-09 15:42:20 -080029import android.os.Environment;
30import android.os.Handler;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070031import android.os.UserHandle;
Fyodor Kupolov259e7612015-02-11 14:13:34 -080032import android.os.UserManager;
Dianne Hackborn39606a02012-07-31 17:54:35 -070033import android.util.AtomicFile;
Fred Quintana718d8a22009-04-29 17:53:20 -070034import android.util.AttributeSet;
Fyodor Kupolov81446482016-08-24 11:27:49 -070035import android.util.IntArray;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070036import android.util.Log;
37import android.util.Slog;
38import android.util.SparseArray;
Fred Quintana718d8a22009-04-29 17:53:20 -070039import android.util.Xml;
40
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -080041import com.android.internal.annotations.GuardedBy;
Fyodor Kupolov9e0d81e2015-02-10 10:45:55 -080042import com.android.internal.annotations.VisibleForTesting;
Amith Yamasani460a7b42015-02-06 14:41:40 -080043import com.android.internal.util.ArrayUtils;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080044import com.android.internal.util.FastXmlSerializer;
Hongming Jin8e2bfc12018-05-30 11:01:06 -070045
Fred Quintana5ebbb4a2009-11-09 15:42:20 -080046import com.google.android.collect.Lists;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070047import com.google.android.collect.Maps;
Fred Quintana5ebbb4a2009-11-09 15:42:20 -080048
Hongming Jin8e2bfc12018-05-30 11:01:06 -070049import libcore.io.IoUtils;
50
Fred Quintana718d8a22009-04-29 17:53:20 -070051import org.xmlpull.v1.XmlPullParser;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070052import org.xmlpull.v1.XmlPullParserException;
Fred Quintana5ebbb4a2009-11-09 15:42:20 -080053import org.xmlpull.v1.XmlSerializer;
Fred Quintana718d8a22009-04-29 17:53:20 -070054
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070055import java.io.File;
56import java.io.FileDescriptor;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070057import java.io.FileOutputStream;
58import java.io.IOException;
Fyodor Kupolov259e7612015-02-11 14:13:34 -080059import java.io.InputStream;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070060import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +010061import java.nio.charset.StandardCharsets;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070062import java.util.ArrayList;
Fyodor Kupolov81446482016-08-24 11:27:49 -070063import java.util.Arrays;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070064import java.util.Collection;
65import java.util.Collections;
66import java.util.List;
67import java.util.Map;
68
Fred Quintana718d8a22009-04-29 17:53:20 -070069/**
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070070 * Cache of registered services. This cache is lazily built by interrogating
71 * {@link PackageManager} on a per-user basis. It's updated as packages are
72 * added, removed and changed. Users are responsible for calling
73 * {@link #invalidateCache(int)} when a user is started, since
74 * {@link PackageManager} broadcasts aren't sent for stopped users.
75 * <p>
76 * The services are referred to by type V and are made available via the
77 * {@link #getServiceInfo} method.
Hongming Jin8e2bfc12018-05-30 11:01:06 -070078 *
Fred Quintana718d8a22009-04-29 17:53:20 -070079 * @hide
80 */
81public abstract class RegisteredServicesCache<V> {
82 private static final String TAG = "PackageManager";
Dianne Hackborn40e9f292012-11-27 19:12:23 -080083 private static final boolean DEBUG = false;
Fyodor Kupolov259e7612015-02-11 14:13:34 -080084 protected static final String REGISTERED_SERVICES_DIR = "registered_services";
Fred Quintana718d8a22009-04-29 17:53:20 -070085
86 public final Context mContext;
87 private final String mInterfaceName;
88 private final String mMetaDataName;
89 private final String mAttributesName;
Fred Quintana5ebbb4a2009-11-09 15:42:20 -080090 private final XmlSerializerAndParser<V> mSerializerAndParser;
Fred Quintana718d8a22009-04-29 17:53:20 -070091
Amith Yamasani37a40c22015-06-17 13:25:42 -070092 protected final Object mServicesLock = new Object();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070093
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -080094 @GuardedBy("mServicesLock")
Dianne Hackbornf4bf0ae2013-05-20 18:42:16 -070095 private final SparseArray<UserServices<V>> mUserServices = new SparseArray<UserServices<V>>(2);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -070096
97 private static class UserServices<V> {
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -080098 @GuardedBy("mServicesLock")
Fyodor Kupolov259e7612015-02-11 14:13:34 -080099 final Map<V, Integer> persistentServices = Maps.newHashMap();
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -0800100 @GuardedBy("mServicesLock")
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800101 Map<V, ServiceInfo<V>> services = null;
102 @GuardedBy("mServicesLock")
103 boolean mPersistentServicesFileDidNotExist = true;
Hongming Jin8e2bfc12018-05-30 11:01:06 -0700104 @GuardedBy("mServicesLock")
105 boolean mBindInstantServiceAllowed = false;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700106 }
107
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800108 @GuardedBy("mServicesLock")
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700109 private UserServices<V> findOrCreateUserLocked(int userId) {
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800110 return findOrCreateUserLocked(userId, true);
111 }
112
113 @GuardedBy("mServicesLock")
114 private UserServices<V> findOrCreateUserLocked(int userId, boolean loadFromFileIfNew) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700115 UserServices<V> services = mUserServices.get(userId);
116 if (services == null) {
117 services = new UserServices<V>();
118 mUserServices.put(userId, services);
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800119 if (loadFromFileIfNew && mSerializerAndParser != null) {
120 // Check if user exists and try loading data from file
121 // clear existing data if there was an error during migration
122 UserInfo user = getUser(userId);
123 if (user != null) {
124 AtomicFile file = createFileForUser(user.id);
125 if (file.getBaseFile().exists()) {
126 if (DEBUG) {
127 Slog.i(TAG, String.format("Loading u%s data from %s", user.id, file));
128 }
129 InputStream is = null;
130 try {
131 is = file.openRead();
132 readPersistentServicesLocked(is);
133 } catch (Exception e) {
134 Log.w(TAG, "Error reading persistent services for user " + user.id, e);
135 } finally {
136 IoUtils.closeQuietly(is);
137 }
138 }
139 }
140 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700141 }
142 return services;
143 }
Fred Quintana3ecd5f42009-09-17 12:42:35 -0700144
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800145 // the listener and handler are synchronized on "this" and must be updated together
146 private RegisteredServicesCacheListener<V> mListener;
147 private Handler mHandler;
Fred Quintana718d8a22009-04-29 17:53:20 -0700148
Mathew Inwood1c77a112018-08-14 14:06:26 +0100149 @UnsupportedAppUsage
Fred Quintana718d8a22009-04-29 17:53:20 -0700150 public RegisteredServicesCache(Context context, String interfaceName, String metaDataName,
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800151 String attributeName, XmlSerializerAndParser<V> serializerAndParser) {
Fred Quintana718d8a22009-04-29 17:53:20 -0700152 mContext = context;
153 mInterfaceName = interfaceName;
154 mMetaDataName = metaDataName;
155 mAttributesName = attributeName;
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800156 mSerializerAndParser = serializerAndParser;
157
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800158 migrateIfNecessaryLocked();
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800159
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800160 IntentFilter intentFilter = new IntentFilter();
161 intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
162 intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
163 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
164 intentFilter.addDataScheme("package");
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700165 mContext.registerReceiverAsUser(mPackageReceiver, UserHandle.ALL, intentFilter, null, null);
166
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800167 // Register for events related to sdcard installation.
168 IntentFilter sdFilter = new IntentFilter();
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800169 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
170 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700171 mContext.registerReceiver(mExternalReceiver, sdFilter);
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800172
173 // Register for user-related events
174 IntentFilter userFilter = new IntentFilter();
175 sdFilter.addAction(Intent.ACTION_USER_REMOVED);
176 mContext.registerReceiver(mUserRemovedReceiver, userFilter);
Fred Quintana718d8a22009-04-29 17:53:20 -0700177 }
178
Christopher Tate0598d702014-03-11 18:16:46 -0700179 private final void handlePackageEvent(Intent intent, int userId) {
180 // Don't regenerate the services map when the package is removed or its
181 // ASEC container unmounted as a step in replacement. The subsequent
182 // _ADDED / _AVAILABLE call will regenerate the map in the final state.
183 final String action = intent.getAction();
184 // it's a new-component action if it isn't some sort of removal
185 final boolean isRemoval = Intent.ACTION_PACKAGE_REMOVED.equals(action)
186 || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action);
187 // if it's a removal, is it part of an update-in-place step?
188 final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
189
190 if (isRemoval && replacing) {
191 // package is going away, but it's the middle of an upgrade: keep the current
192 // state and do nothing here. This clause is intentionally empty.
193 } else {
Amith Yamasani460a7b42015-02-06 14:41:40 -0800194 int[] uids = null;
Christopher Tate0598d702014-03-11 18:16:46 -0700195 // either we're adding/changing, or it's a removal without replacement, so
Amith Yamasani460a7b42015-02-06 14:41:40 -0800196 // we need to update the set of available services
197 if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)
198 || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
199 uids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
200 } else {
201 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
202 if (uid > 0) {
203 uids = new int[] { uid };
204 }
205 }
206 generateServicesMap(uids, userId);
Christopher Tate0598d702014-03-11 18:16:46 -0700207 }
208 }
209
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700210 private final BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
211 @Override
212 public void onReceive(Context context, Intent intent) {
213 final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
214 if (uid != -1) {
Christopher Tate0598d702014-03-11 18:16:46 -0700215 handlePackageEvent(intent, UserHandle.getUserId(uid));
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700216 }
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800217 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700218 };
219
220 private final BroadcastReceiver mExternalReceiver = new BroadcastReceiver() {
221 @Override
222 public void onReceive(Context context, Intent intent) {
223 // External apps can't coexist with multi-user, so scan owner
Xiaohui Chen98404fd2015-08-17 16:09:02 -0700224 handlePackageEvent(intent, UserHandle.USER_SYSTEM);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700225 }
226 };
227
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800228 private final BroadcastReceiver mUserRemovedReceiver = new BroadcastReceiver() {
229 @Override
230 public void onReceive(Context context, Intent intent) {
231 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
232 if (DEBUG) {
233 Slog.d(TAG, "u" + userId + " removed - cleaning up");
234 }
235 onUserRemoved(userId);
236 }
237 };
238
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700239 public void invalidateCache(int userId) {
240 synchronized (mServicesLock) {
241 final UserServices<V> user = findOrCreateUserLocked(userId);
242 user.services = null;
Amith Yamasani37a40c22015-06-17 13:25:42 -0700243 onServicesChangedLocked(userId);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700244 }
245 }
246
247 public void dump(FileDescriptor fd, PrintWriter fout, String[] args, int userId) {
248 synchronized (mServicesLock) {
249 final UserServices<V> user = findOrCreateUserLocked(userId);
250 if (user.services != null) {
251 fout.println("RegisteredServicesCache: " + user.services.size() + " services");
252 for (ServiceInfo<?> info : user.services.values()) {
253 fout.println(" " + info);
254 }
255 } else {
256 fout.println("RegisteredServicesCache: services not loaded");
257 }
Fred Quintana718d8a22009-04-29 17:53:20 -0700258 }
259 }
260
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800261 public RegisteredServicesCacheListener<V> getListener() {
Fred Quintana718d8a22009-04-29 17:53:20 -0700262 synchronized (this) {
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800263 return mListener;
Fred Quintana718d8a22009-04-29 17:53:20 -0700264 }
265 }
266
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800267 public void setListener(RegisteredServicesCacheListener<V> listener, Handler handler) {
268 if (handler == null) {
269 handler = new Handler(mContext.getMainLooper());
Fred Quintana718d8a22009-04-29 17:53:20 -0700270 }
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800271 synchronized (this) {
272 mHandler = handler;
273 mListener = listener;
274 }
275 }
276
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700277 private void notifyListener(final V type, final int userId, final boolean removed) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800278 if (DEBUG) {
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800279 Log.d(TAG, "notifyListener: " + type + " is " + (removed ? "removed" : "added"));
280 }
281 RegisteredServicesCacheListener<V> listener;
Hongming Jin8e2bfc12018-05-30 11:01:06 -0700282 Handler handler;
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800283 synchronized (this) {
284 listener = mListener;
285 handler = mHandler;
286 }
287 if (listener == null) {
288 return;
289 }
Hongming Jin8e2bfc12018-05-30 11:01:06 -0700290
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800291 final RegisteredServicesCacheListener<V> listener2 = listener;
292 handler.post(new Runnable() {
293 public void run() {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700294 listener2.onServiceChanged(type, userId, removed);
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800295 }
296 });
Fred Quintana718d8a22009-04-29 17:53:20 -0700297 }
298
299 /**
300 * Value type that describes a Service. The information within can be used
301 * to bind to the service.
302 */
303 public static class ServiceInfo<V> {
Mathew Inwood1c77a112018-08-14 14:06:26 +0100304 @UnsupportedAppUsage
Fred Quintana718d8a22009-04-29 17:53:20 -0700305 public final V type;
Jeff Sharkey9d8a1042015-12-03 17:56:20 -0700306 public final ComponentInfo componentInfo;
Mathew Inwood1c77a112018-08-14 14:06:26 +0100307 @UnsupportedAppUsage
Fred Quintana718d8a22009-04-29 17:53:20 -0700308 public final ComponentName componentName;
Mathew Inwood1c77a112018-08-14 14:06:26 +0100309 @UnsupportedAppUsage
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700310 public final int uid;
Fred Quintana718d8a22009-04-29 17:53:20 -0700311
Fred Quintana56285a62010-12-02 14:20:51 -0800312 /** @hide */
Jeff Sharkey9d8a1042015-12-03 17:56:20 -0700313 public ServiceInfo(V type, ComponentInfo componentInfo, ComponentName componentName) {
Fred Quintana718d8a22009-04-29 17:53:20 -0700314 this.type = type;
Jeff Sharkey9d8a1042015-12-03 17:56:20 -0700315 this.componentInfo = componentInfo;
Fred Quintana718d8a22009-04-29 17:53:20 -0700316 this.componentName = componentName;
Jeff Sharkey9d8a1042015-12-03 17:56:20 -0700317 this.uid = (componentInfo != null) ? componentInfo.applicationInfo.uid : -1;
Fred Quintana718d8a22009-04-29 17:53:20 -0700318 }
319
Jeff Hamiltonc42c0dd2009-09-03 09:08:30 -0500320 @Override
Fred Quintana718d8a22009-04-29 17:53:20 -0700321 public String toString() {
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800322 return "ServiceInfo: " + type + ", " + componentName + ", uid " + uid;
Fred Quintana718d8a22009-04-29 17:53:20 -0700323 }
324 }
325
326 /**
327 * Accessor for the registered authenticators.
328 * @param type the account type of the authenticator
329 * @return the AuthenticatorInfo that matches the account type or null if none is present
330 */
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700331 public ServiceInfo<V> getServiceInfo(V type, int userId) {
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800332 synchronized (mServicesLock) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700333 // Find user and lazily populate cache
334 final UserServices<V> user = findOrCreateUserLocked(userId);
335 if (user.services == null) {
Amith Yamasani460a7b42015-02-06 14:41:40 -0800336 generateServicesMap(null, userId);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700337 }
338 return user.services.get(type);
Fred Quintana718d8a22009-04-29 17:53:20 -0700339 }
Fred Quintana718d8a22009-04-29 17:53:20 -0700340 }
341
342 /**
343 * @return a collection of {@link RegisteredServicesCache.ServiceInfo} objects for all
344 * registered authenticators.
345 */
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700346 public Collection<ServiceInfo<V>> getAllServices(int userId) {
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800347 synchronized (mServicesLock) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700348 // Find user and lazily populate cache
349 final UserServices<V> user = findOrCreateUserLocked(userId);
350 if (user.services == null) {
Amith Yamasani460a7b42015-02-06 14:41:40 -0800351 generateServicesMap(null, userId);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700352 }
Jeff Sharkeya706e2f2012-10-16 12:02:42 -0700353 return Collections.unmodifiableCollection(
354 new ArrayList<ServiceInfo<V>>(user.services.values()));
Fred Quintana718d8a22009-04-29 17:53:20 -0700355 }
Fred Quintana718d8a22009-04-29 17:53:20 -0700356 }
357
Fyodor Kupolov81446482016-08-24 11:27:49 -0700358 public void updateServices(int userId) {
359 if (DEBUG) {
360 Slog.d(TAG, "updateServices u" + userId);
361 }
362 List<ServiceInfo<V>> allServices;
363 synchronized (mServicesLock) {
364 final UserServices<V> user = findOrCreateUserLocked(userId);
365 // If services haven't been initialized yet - no updates required
366 if (user.services == null) {
367 return;
368 }
369 allServices = new ArrayList<>(user.services.values());
370 }
371 IntArray updatedUids = null;
372 for (ServiceInfo<V> service : allServices) {
Dianne Hackborn3accca02013-09-20 09:32:11 -0700373 long versionCode = service.componentInfo.applicationInfo.versionCode;
Fyodor Kupolov81446482016-08-24 11:27:49 -0700374 String pkg = service.componentInfo.packageName;
375 ApplicationInfo newAppInfo = null;
376 try {
377 newAppInfo = mContext.getPackageManager().getApplicationInfoAsUser(pkg, 0, userId);
378 } catch (NameNotFoundException e) {
379 // Package uninstalled - treat as null app info
380 }
381 // If package updated or removed
382 if ((newAppInfo == null) || (newAppInfo.versionCode != versionCode)) {
383 if (DEBUG) {
384 Slog.d(TAG, "Package " + pkg + " uid=" + service.uid
385 + " updated. New appInfo: " + newAppInfo);
386 }
387 if (updatedUids == null) {
388 updatedUids = new IntArray();
389 }
390 updatedUids.add(service.uid);
391 }
392 }
393 if (updatedUids != null && updatedUids.size() > 0) {
394 int[] updatedUidsArray = updatedUids.toArray();
395 generateServicesMap(updatedUidsArray, userId);
396 }
397 }
398
Hongming Jin8e2bfc12018-05-30 11:01:06 -0700399 /**
400 * @return whether the binding to service is allowed for instant apps.
401 */
402 public boolean getBindInstantServiceAllowed(int userId) {
403 mContext.enforceCallingOrSelfPermission(
404 Manifest.permission.MANAGE_BIND_INSTANT_SERVICE,
405 "getBindInstantServiceAllowed");
406
407 synchronized (mServicesLock) {
408 final UserServices<V> user = findOrCreateUserLocked(userId);
409 return user.mBindInstantServiceAllowed;
410 }
411 }
412
413 /**
414 * Set whether the binding to service is allowed or not for instant apps.
415 */
416 public void setBindInstantServiceAllowed(int userId, boolean allowed) {
417 mContext.enforceCallingOrSelfPermission(
418 Manifest.permission.MANAGE_BIND_INSTANT_SERVICE,
419 "setBindInstantServiceAllowed");
420
421 synchronized (mServicesLock) {
422 final UserServices<V> user = findOrCreateUserLocked(userId);
423 user.mBindInstantServiceAllowed = allowed;
424 }
425 }
426
Fyodor Kupolov9e0d81e2015-02-10 10:45:55 -0800427 @VisibleForTesting
428 protected boolean inSystemImage(int callerUid) {
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800429 String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid);
liulvpingbf76ee72016-09-08 09:16:48 +0800430 if (packages != null) {
431 for (String name : packages) {
432 try {
433 PackageInfo packageInfo =
434 mContext.getPackageManager().getPackageInfo(name, 0 /* flags */);
435 if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
436 return true;
437 }
438 } catch (PackageManager.NameNotFoundException e) {
439 return false;
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800440 }
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800441 }
442 }
443 return false;
444 }
445
Fyodor Kupolov9e0d81e2015-02-10 10:45:55 -0800446 @VisibleForTesting
447 protected List<ResolveInfo> queryIntentServices(int userId) {
448 final PackageManager pm = mContext.getPackageManager();
Hongming Jin8e2bfc12018-05-30 11:01:06 -0700449 int flags = PackageManager.GET_META_DATA
450 | PackageManager.MATCH_DIRECT_BOOT_AWARE
451 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
452 synchronized (mServicesLock) {
453 final UserServices<V> user = findOrCreateUserLocked(userId);
454 if (user.mBindInstantServiceAllowed) {
455 flags |= PackageManager.MATCH_INSTANT;
456 }
457 }
458 return pm.queryIntentServicesAsUser(new Intent(mInterfaceName), flags, userId);
Fyodor Kupolov9e0d81e2015-02-10 10:45:55 -0800459 }
460
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700461 /**
462 * Populate {@link UserServices#services} by scanning installed packages for
463 * given {@link UserHandle}.
Amith Yamasani460a7b42015-02-06 14:41:40 -0800464 * @param changedUids the array of uids that have been affected, as mentioned in the broadcast
465 * or null to assume that everything is affected.
466 * @param userId the user for whom to update the services map.
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700467 */
Amith Yamasani460a7b42015-02-06 14:41:40 -0800468 private void generateServicesMap(int[] changedUids, int userId) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800469 if (DEBUG) {
Fyodor Kupolov81446482016-08-24 11:27:49 -0700470 Slog.d(TAG, "generateServicesMap() for " + userId + ", changed UIDs = "
471 + Arrays.toString(changedUids));
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800472 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700473
Fyodor Kupolov81446482016-08-24 11:27:49 -0700474 final ArrayList<ServiceInfo<V>> serviceInfos = new ArrayList<>();
Fyodor Kupolov9e0d81e2015-02-10 10:45:55 -0800475 final List<ResolveInfo> resolveInfos = queryIntentServices(userId);
Fred Quintana718d8a22009-04-29 17:53:20 -0700476 for (ResolveInfo resolveInfo : resolveInfos) {
477 try {
478 ServiceInfo<V> info = parseServiceInfo(resolveInfo);
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800479 if (info == null) {
480 Log.w(TAG, "Unable to load service info " + resolveInfo.toString());
481 continue;
Fred Quintana718d8a22009-04-29 17:53:20 -0700482 }
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800483 serviceInfos.add(info);
Fyodor Kupolov9e0d81e2015-02-10 10:45:55 -0800484 } catch (XmlPullParserException|IOException e) {
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800485 Log.w(TAG, "Unable to load service info " + resolveInfo.toString(), e);
Fred Quintana718d8a22009-04-29 17:53:20 -0700486 }
487 }
488
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800489 synchronized (mServicesLock) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700490 final UserServices<V> user = findOrCreateUserLocked(userId);
491 final boolean firstScan = user.services == null;
492 if (firstScan) {
493 user.services = Maps.newHashMap();
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800494 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700495
Alon Albert3fa51e32010-11-11 09:24:04 -0800496 StringBuilder changes = new StringBuilder();
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800497 boolean changed = false;
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800498 for (ServiceInfo<V> info : serviceInfos) {
499 // four cases:
500 // - doesn't exist yet
501 // - add, notify user that it was added
502 // - exists and the UID is the same
503 // - replace, don't notify user
504 // - exists, the UID is different, and the new one is not a system package
505 // - ignore
506 // - exists, the UID is different, and the new one is a system package
507 // - add, notify user that it was added
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700508 Integer previousUid = user.persistentServices.get(info.type);
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800509 if (previousUid == null) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800510 if (DEBUG) {
511 changes.append(" New service added: ").append(info).append("\n");
512 }
513 changed = true;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700514 user.services.put(info.type, info);
515 user.persistentServices.put(info.type, info.uid);
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800516 if (!(user.mPersistentServicesFileDidNotExist && firstScan)) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700517 notifyListener(info.type, userId, false /* removed */);
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800518 }
519 } else if (previousUid == info.uid) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800520 if (DEBUG) {
Alon Albert3fa51e32010-11-11 09:24:04 -0800521 changes.append(" Existing service (nop): ").append(info).append("\n");
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800522 }
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700523 user.services.put(info.type, info);
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800524 } else if (inSystemImage(info.uid)
525 || !containsTypeAndUid(serviceInfos, info.type, previousUid)) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800526 if (DEBUG) {
527 if (inSystemImage(info.uid)) {
528 changes.append(" System service replacing existing: ").append(info)
529 .append("\n");
530 } else {
531 changes.append(" Existing service replacing a removed service: ")
532 .append(info).append("\n");
533 }
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800534 }
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800535 changed = true;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700536 user.services.put(info.type, info);
537 user.persistentServices.put(info.type, info.uid);
538 notifyListener(info.type, userId, false /* removed */);
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800539 } else {
540 // ignore
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800541 if (DEBUG) {
542 changes.append(" Existing service with new uid ignored: ").append(info)
543 .append("\n");
544 }
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800545 }
546 }
547
548 ArrayList<V> toBeRemoved = Lists.newArrayList();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700549 for (V v1 : user.persistentServices.keySet()) {
Amith Yamasani460a7b42015-02-06 14:41:40 -0800550 // Remove a persisted service that's not in the currently available services list.
551 // And only if it is in the list of changedUids.
552 if (!containsType(serviceInfos, v1)
553 && containsUid(changedUids, user.persistentServices.get(v1))) {
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800554 toBeRemoved.add(v1);
555 }
556 }
557 for (V v1 : toBeRemoved) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800558 if (DEBUG) {
559 changes.append(" Service removed: ").append(v1).append("\n");
560 }
561 changed = true;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700562 user.persistentServices.remove(v1);
Amith Yamasani460a7b42015-02-06 14:41:40 -0800563 user.services.remove(v1);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700564 notifyListener(v1, userId, true /* removed */);
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800565 }
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800566 if (DEBUG) {
Amith Yamasani460a7b42015-02-06 14:41:40 -0800567 Log.d(TAG, "user.services=");
568 for (V v : user.services.keySet()) {
569 Log.d(TAG, " " + v + " " + user.services.get(v));
570 }
571 Log.d(TAG, "user.persistentServices=");
572 for (V v : user.persistentServices.keySet()) {
573 Log.d(TAG, " " + v + " " + user.persistentServices.get(v));
574 }
575 }
576 if (DEBUG) {
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800577 if (changes.length() > 0) {
Dianne Hackborn4428e172012-08-24 17:43:05 -0700578 Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " +
579 serviceInfos.size() + " services:\n" + changes);
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800580 } else {
Dianne Hackborn4428e172012-08-24 17:43:05 -0700581 Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " +
582 serviceInfos.size() + " services unchanged");
583 }
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800584 }
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800585 if (changed) {
Amith Yamasani37a40c22015-06-17 13:25:42 -0700586 onServicesChangedLocked(userId);
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800587 writePersistentServicesLocked(user, userId);
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800588 }
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800589 }
590 }
591
Amith Yamasani37a40c22015-06-17 13:25:42 -0700592 protected void onServicesChangedLocked(int userId) {
593 // Feel free to override
594 }
595
Amith Yamasani460a7b42015-02-06 14:41:40 -0800596 /**
597 * Returns true if the list of changed uids is null (wildcard) or the specified uid
598 * is contained in the list of changed uids.
599 */
600 private boolean containsUid(int[] changedUids, int uid) {
601 return changedUids == null || ArrayUtils.contains(changedUids, uid);
602 }
603
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800604 private boolean containsType(ArrayList<ServiceInfo<V>> serviceInfos, V type) {
605 for (int i = 0, N = serviceInfos.size(); i < N; i++) {
606 if (serviceInfos.get(i).type.equals(type)) {
607 return true;
608 }
609 }
610
611 return false;
612 }
613
614 private boolean containsTypeAndUid(ArrayList<ServiceInfo<V>> serviceInfos, V type, int uid) {
615 for (int i = 0, N = serviceInfos.size(); i < N; i++) {
616 final ServiceInfo<V> serviceInfo = serviceInfos.get(i);
617 if (serviceInfo.type.equals(type) && serviceInfo.uid == uid) {
618 return true;
619 }
620 }
621
622 return false;
Fred Quintana718d8a22009-04-29 17:53:20 -0700623 }
624
Fyodor Kupolov9e0d81e2015-02-10 10:45:55 -0800625 @VisibleForTesting
626 protected ServiceInfo<V> parseServiceInfo(ResolveInfo service)
Fred Quintana718d8a22009-04-29 17:53:20 -0700627 throws XmlPullParserException, IOException {
628 android.content.pm.ServiceInfo si = service.serviceInfo;
629 ComponentName componentName = new ComponentName(si.packageName, si.name);
630
631 PackageManager pm = mContext.getPackageManager();
632
633 XmlResourceParser parser = null;
634 try {
635 parser = si.loadXmlMetaData(pm, mMetaDataName);
636 if (parser == null) {
637 throw new XmlPullParserException("No " + mMetaDataName + " meta-data");
638 }
639
640 AttributeSet attrs = Xml.asAttributeSet(parser);
641
642 int type;
643 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
644 && type != XmlPullParser.START_TAG) {
645 }
646
647 String nodeName = parser.getName();
648 if (!mAttributesName.equals(nodeName)) {
649 throw new XmlPullParserException(
650 "Meta-data does not start with " + mAttributesName + " tag");
651 }
652
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800653 V v = parseServiceAttributes(pm.getResourcesForApplication(si.applicationInfo),
654 si.packageName, attrs);
Fred Quintana718d8a22009-04-29 17:53:20 -0700655 if (v == null) {
656 return null;
657 }
Fred Quintanad4a1d2e2009-07-16 16:36:38 -0700658 final android.content.pm.ServiceInfo serviceInfo = service.serviceInfo;
Jeff Sharkey9d8a1042015-12-03 17:56:20 -0700659 return new ServiceInfo<V>(v, serviceInfo, componentName);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800660 } catch (NameNotFoundException e) {
661 throw new XmlPullParserException(
662 "Unable to load resources for pacakge " + si.packageName);
Fred Quintana718d8a22009-04-29 17:53:20 -0700663 } finally {
664 if (parser != null) parser.close();
665 }
666 }
667
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800668 /**
669 * Read all sync status back in to the initial engine state.
670 */
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800671 private void readPersistentServicesLocked(InputStream is)
672 throws XmlPullParserException, IOException {
673 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100674 parser.setInput(is, StandardCharsets.UTF_8.name());
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800675 int eventType = parser.getEventType();
676 while (eventType != XmlPullParser.START_TAG
677 && eventType != XmlPullParser.END_DOCUMENT) {
678 eventType = parser.next();
679 }
680 String tagName = parser.getName();
681 if ("services".equals(tagName)) {
682 eventType = parser.next();
683 do {
684 if (eventType == XmlPullParser.START_TAG && parser.getDepth() == 2) {
685 tagName = parser.getName();
686 if ("service".equals(tagName)) {
687 V service = mSerializerAndParser.createFromXml(parser);
688 if (service == null) {
689 break;
690 }
691 String uidString = parser.getAttributeValue(null, "uid");
692 final int uid = Integer.parseInt(uidString);
693 final int userId = UserHandle.getUserId(uid);
694 final UserServices<V> user = findOrCreateUserLocked(userId,
695 false /*loadFromFileIfNew*/) ;
696 user.persistentServices.put(service, uid);
697 }
698 }
699 eventType = parser.next();
700 } while (eventType != XmlPullParser.END_DOCUMENT);
701 }
702 }
703
704 private void migrateIfNecessaryLocked() {
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800705 if (mSerializerAndParser == null) {
706 return;
707 }
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800708 File systemDir = new File(getDataDirectory(), "system");
709 File syncDir = new File(systemDir, REGISTERED_SERVICES_DIR);
710 AtomicFile oldFile = new AtomicFile(new File(syncDir, mInterfaceName + ".xml"));
711 boolean oldFileExists = oldFile.getBaseFile().exists();
712
713 if (oldFileExists) {
714 File marker = new File(syncDir, mInterfaceName + ".xml.migrated");
715 // if not migrated, perform the migration and add a marker
716 if (!marker.exists()) {
717 if (DEBUG) {
718 Slog.i(TAG, "Marker file " + marker + " does not exist - running migration");
719 }
720 InputStream is = null;
721 try {
722 is = oldFile.openRead();
723 mUserServices.clear();
724 readPersistentServicesLocked(is);
725 } catch (Exception e) {
726 Log.w(TAG, "Error reading persistent services, starting from scratch", e);
727 } finally {
728 IoUtils.closeQuietly(is);
729 }
730 try {
731 for (UserInfo user : getUsers()) {
732 UserServices<V> userServices = mUserServices.get(user.id);
733 if (userServices != null) {
734 if (DEBUG) {
735 Slog.i(TAG, "Migrating u" + user.id + " services "
736 + userServices.persistentServices);
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800737 }
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800738 writePersistentServicesLocked(userServices, user.id);
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800739 }
740 }
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800741 marker.createNewFile();
742 } catch (Exception e) {
743 Log.w(TAG, "Migration failed", e);
744 }
745 // Migration is complete and we don't need to keep data for all users anymore,
746 // It will be loaded from a new location when requested
747 mUserServices.clear();
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800748 }
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800749 }
750 }
751
752 /**
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800753 * Writes services of a specified user to the file.
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800754 */
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800755 private void writePersistentServicesLocked(UserServices<V> user, int userId) {
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800756 if (mSerializerAndParser == null) {
757 return;
758 }
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800759 AtomicFile atomicFile = createFileForUser(userId);
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800760 FileOutputStream fos = null;
761 try {
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800762 fos = atomicFile.startWrite();
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800763 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100764 out.setOutput(fos, StandardCharsets.UTF_8.name());
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800765 out.startDocument(null, true);
766 out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
767 out.startTag(null, "services");
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800768 for (Map.Entry<V, Integer> service : user.persistentServices.entrySet()) {
769 out.startTag(null, "service");
770 out.attribute(null, "uid", Integer.toString(service.getValue()));
771 mSerializerAndParser.writeAsXml(service.getKey(), out);
772 out.endTag(null, "service");
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800773 }
774 out.endTag(null, "services");
775 out.endDocument();
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800776 atomicFile.finishWrite(fos);
Fyodor Kupolov9e0d81e2015-02-10 10:45:55 -0800777 } catch (IOException e1) {
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800778 Log.w(TAG, "Error writing accounts", e1);
779 if (fos != null) {
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800780 atomicFile.failWrite(fos);
Fred Quintana5ebbb4a2009-11-09 15:42:20 -0800781 }
782 }
783 }
784
Fyodor Kupolov9e0d81e2015-02-10 10:45:55 -0800785 @VisibleForTesting
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800786 protected void onUserRemoved(int userId) {
Amith Yamasani37a40c22015-06-17 13:25:42 -0700787 synchronized (mServicesLock) {
788 mUserServices.remove(userId);
789 }
Fyodor Kupolov259e7612015-02-11 14:13:34 -0800790 }
791
792 @VisibleForTesting
793 protected List<UserInfo> getUsers() {
794 return UserManager.get(mContext).getUsers(true);
795 }
796
797 @VisibleForTesting
798 protected UserInfo getUser(int userId) {
799 return UserManager.get(mContext).getUserInfo(userId);
800 }
801
802 private AtomicFile createFileForUser(int userId) {
803 File userDir = getUserSystemDirectory(userId);
804 File userFile = new File(userDir, REGISTERED_SERVICES_DIR + "/" + mInterfaceName + ".xml");
805 return new AtomicFile(userFile);
806 }
807
808 @VisibleForTesting
809 protected File getUserSystemDirectory(int userId) {
810 return Environment.getUserSystemDirectory(userId);
811 }
812
813 @VisibleForTesting
814 protected File getDataDirectory() {
815 return Environment.getDataDirectory();
816 }
817
818 @VisibleForTesting
Fyodor Kupolov9e0d81e2015-02-10 10:45:55 -0800819 protected Map<V, Integer> getPersistentServices(int userId) {
820 return findOrCreateUserLocked(userId).persistentServices;
821 }
822
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800823 public abstract V parseServiceAttributes(Resources res,
824 String packageName, AttributeSet attrs);
Fred Quintana718d8a22009-04-29 17:53:20 -0700825}