1718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana/* 2718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * Copyright (C) 2009 The Android Open Source Project 3718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * 4718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * Licensed under the Apache License, Version 2.0 (the "License"); 5718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * you may not use this file except in compliance with the License. 6718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * You may obtain a copy of the License at 7718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * 8718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * http://www.apache.org/licenses/LICENSE-2.0 9718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * 10718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * Unless required by applicable law or agreed to in writing, software 11718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * distributed under the License is distributed on an "AS IS" BASIS, 12718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * See the License for the specific language governing permissions and 14718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * limitations under the License. 15718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 16718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 17718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanapackage android.content.pm; 18718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 19718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.content.BroadcastReceiver; 206ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport android.content.ComponentName; 216ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport android.content.Context; 22718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.content.Intent; 23718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.content.IntentFilter; 2420cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackbornimport android.content.pm.PackageManager.NameNotFoundException; 2520cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackbornimport android.content.res.Resources; 26718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.content.res.XmlResourceParser; 275ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport android.os.Environment; 285ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport android.os.Handler; 296ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport android.os.UserHandle; 3039606a007a5b1309dd000234f2b8cf156c49fd0fDianne Hackbornimport android.util.AtomicFile; 31718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.util.AttributeSet; 326ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport android.util.Log; 336ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport android.util.Slog; 346ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport android.util.SparseArray; 35718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.util.Xml; 36718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 378b2c3a14603d163d7564e6f60286995079687690Jeff Sharkeyimport com.android.internal.annotations.GuardedBy; 382269d1572e5fcfb725ea55f5764d8c3280d69f6dDianne Hackbornimport com.android.internal.util.FastXmlSerializer; 395ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport com.google.android.collect.Lists; 406ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport com.google.android.collect.Maps; 415ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 42718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport org.xmlpull.v1.XmlPullParser; 436ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport org.xmlpull.v1.XmlPullParserException; 445ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport org.xmlpull.v1.XmlSerializer; 45718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 466ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport java.io.File; 476ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport java.io.FileDescriptor; 486ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport java.io.FileInputStream; 496ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport java.io.FileOutputStream; 506ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport java.io.IOException; 516ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport java.io.PrintWriter; 526ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport java.util.ArrayList; 536ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport java.util.Collection; 546ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport java.util.Collections; 556ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport java.util.List; 566ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport java.util.Map; 576ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey 58718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana/** 596ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey * Cache of registered services. This cache is lazily built by interrogating 606ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey * {@link PackageManager} on a per-user basis. It's updated as packages are 616ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey * added, removed and changed. Users are responsible for calling 626ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey * {@link #invalidateCache(int)} when a user is started, since 636ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey * {@link PackageManager} broadcasts aren't sent for stopped users. 646ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey * <p> 656ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey * The services are referred to by type V and are made available via the 666ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey * {@link #getServiceInfo} method. 676ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey * 68718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * @hide 69718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 70718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanapublic abstract class RegisteredServicesCache<V> { 71718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private static final String TAG = "PackageManager"; 7240e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn private static final boolean DEBUG = false; 73718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 74718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public final Context mContext; 75718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private final String mInterfaceName; 76718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private final String mMetaDataName; 77718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private final String mAttributesName; 785ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private final XmlSerializerAndParser<V> mSerializerAndParser; 79718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 805ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private final Object mServicesLock = new Object(); 816ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey 828b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey @GuardedBy("mServicesLock") 835ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private boolean mPersistentServicesFileDidNotExist; 848b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey @GuardedBy("mServicesLock") 85f4bf0ae2a7c2d9d92c5c8abdb82baa53b4c9ccdaDianne Hackborn private final SparseArray<UserServices<V>> mUserServices = new SparseArray<UserServices<V>>(2); 866ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey 876ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey private static class UserServices<V> { 888b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey @GuardedBy("mServicesLock") 896ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey public final Map<V, Integer> persistentServices = Maps.newHashMap(); 908b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey @GuardedBy("mServicesLock") 916ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey public Map<V, ServiceInfo<V>> services = null; 926ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey } 936ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey 946ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey private UserServices<V> findOrCreateUserLocked(int userId) { 956ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey UserServices<V> services = mUserServices.get(userId); 966ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey if (services == null) { 976ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey services = new UserServices<V>(); 986ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey mUserServices.put(userId, services); 996ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey } 1006ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey return services; 1016ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey } 1023ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana 1035ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana /** 1045ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana * This file contains the list of known services. We would like to maintain this forever 1055ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana * so we store it as an XML file. 1065ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana */ 1075ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private final AtomicFile mPersistentServicesFile; 108718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 1095ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // the listener and handler are synchronized on "this" and must be updated together 1105ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private RegisteredServicesCacheListener<V> mListener; 1115ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private Handler mHandler; 112718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 113718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public RegisteredServicesCache(Context context, String interfaceName, String metaDataName, 1145ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana String attributeName, XmlSerializerAndParser<V> serializerAndParser) { 115718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mContext = context; 116718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mInterfaceName = interfaceName; 117718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mMetaDataName = metaDataName; 118718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mAttributesName = attributeName; 1195ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mSerializerAndParser = serializerAndParser; 1205ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 1215ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana File dataDir = Environment.getDataDirectory(); 1225ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana File systemDir = new File(dataDir, "system"); 1235ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana File syncDir = new File(systemDir, "registered_services"); 1245ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServicesFile = new AtomicFile(new File(syncDir, interfaceName + ".xml")); 1255ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 1266ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey // Load persisted services from disk 1276ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey readPersistentServicesLocked(); 1285ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 1295ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana IntentFilter intentFilter = new IntentFilter(); 1305ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 1315ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 1325ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 1335ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana intentFilter.addDataScheme("package"); 1346ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey mContext.registerReceiverAsUser(mPackageReceiver, UserHandle.ALL, intentFilter, null, null); 1356ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey 13608675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu // Register for events related to sdcard installation. 13708675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu IntentFilter sdFilter = new IntentFilter(); 138b56ae20b22fd7283df32072a431ab6d4965f3c1bSuchi Amalapurapu sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); 139b56ae20b22fd7283df32072a431ab6d4965f3c1bSuchi Amalapurapu sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 1406ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey mContext.registerReceiver(mExternalReceiver, sdFilter); 141718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 142718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 1436ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey private final BroadcastReceiver mPackageReceiver = new BroadcastReceiver() { 1446ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey @Override 1456ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey public void onReceive(Context context, Intent intent) { 1466ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); 1476ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey if (uid != -1) { 1486ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey generateServicesMap(UserHandle.getUserId(uid)); 1496ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey } 1506ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey } 1516ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey }; 1526ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey 1536ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey private final BroadcastReceiver mExternalReceiver = new BroadcastReceiver() { 1546ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey @Override 1556ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey public void onReceive(Context context, Intent intent) { 1566ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey // External apps can't coexist with multi-user, so scan owner 1576ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey generateServicesMap(UserHandle.USER_OWNER); 1586ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey } 1596ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey }; 1606ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey 1616ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey public void invalidateCache(int userId) { 1625ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana synchronized (mServicesLock) { 1636ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey final UserServices<V> user = findOrCreateUserLocked(userId); 1646ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey user.services = null; 1655ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 1666ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey } 1676ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey 1686ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey public void dump(FileDescriptor fd, PrintWriter fout, String[] args, int userId) { 1696ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey synchronized (mServicesLock) { 1706ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey final UserServices<V> user = findOrCreateUserLocked(userId); 1716ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey if (user.services != null) { 1726ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey fout.println("RegisteredServicesCache: " + user.services.size() + " services"); 1736ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey for (ServiceInfo<?> info : user.services.values()) { 1746ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey fout.println(" " + info); 1756ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey } 1766ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey } else { 1776ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey fout.println("RegisteredServicesCache: services not loaded"); 1786ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey } 179718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 180718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 181718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 1825ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana public RegisteredServicesCacheListener<V> getListener() { 183718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana synchronized (this) { 1845ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return mListener; 1855ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 1865ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 187718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 1885ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana public void setListener(RegisteredServicesCacheListener<V> listener, Handler handler) { 1895ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (handler == null) { 1905ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana handler = new Handler(mContext.getMainLooper()); 1915ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 1925ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana synchronized (this) { 1935ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mHandler = handler; 1945ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mListener = listener; 195718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 196718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 197718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 1986ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey private void notifyListener(final V type, final int userId, final boolean removed) { 19940e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn if (DEBUG) { 2005ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.d(TAG, "notifyListener: " + type + " is " + (removed ? "removed" : "added")); 2015ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 2025ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana RegisteredServicesCacheListener<V> listener; 2035ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Handler handler; 204718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana synchronized (this) { 2055ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana listener = mListener; 2065ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana handler = mHandler; 2075ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 2085ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (listener == null) { 2095ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return; 210718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 2115ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 2125ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana final RegisteredServicesCacheListener<V> listener2 = listener; 2135ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana handler.post(new Runnable() { 2145ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana public void run() { 2156ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey listener2.onServiceChanged(type, userId, removed); 2165ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 2175ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana }); 218718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 219718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 220718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana /** 221718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * Value type that describes a Service. The information within can be used 222718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * to bind to the service. 223718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 224718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public static class ServiceInfo<V> { 225718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public final V type; 226718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public final ComponentName componentName; 227d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana public final int uid; 228718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 22956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana /** @hide */ 23056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana public ServiceInfo(V type, ComponentName componentName, int uid) { 231718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana this.type = type; 232718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana this.componentName = componentName; 233d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana this.uid = uid; 234718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 235718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 236c42c0dd1c4e2f7a4abaac1b2c9a6344448f9db7aJeff Hamilton @Override 237718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public String toString() { 2385ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return "ServiceInfo: " + type + ", " + componentName + ", uid " + uid; 239718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 240718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 241718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 242718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana /** 243718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * Accessor for the registered authenticators. 244718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * @param type the account type of the authenticator 245718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * @return the AuthenticatorInfo that matches the account type or null if none is present 246718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 2476ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey public ServiceInfo<V> getServiceInfo(V type, int userId) { 2485ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana synchronized (mServicesLock) { 2496ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey // Find user and lazily populate cache 2506ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey final UserServices<V> user = findOrCreateUserLocked(userId); 2516ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey if (user.services == null) { 2526ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey generateServicesMap(userId); 2536ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey } 2546ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey return user.services.get(type); 255718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 256718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 257718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 258718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana /** 259718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * @return a collection of {@link RegisteredServicesCache.ServiceInfo} objects for all 260718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * registered authenticators. 261718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 2626ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey public Collection<ServiceInfo<V>> getAllServices(int userId) { 2635ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana synchronized (mServicesLock) { 2646ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey // Find user and lazily populate cache 2656ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey final UserServices<V> user = findOrCreateUserLocked(userId); 2666ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey if (user.services == null) { 2676ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey generateServicesMap(userId); 2686ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey } 269a706e2fd0059b1bb86c487722dbc9fc0fda9c980Jeff Sharkey return Collections.unmodifiableCollection( 270a706e2fd0059b1bb86c487722dbc9fc0fda9c980Jeff Sharkey new ArrayList<ServiceInfo<V>>(user.services.values())); 271718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 272718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 273718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 2745ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private boolean inSystemImage(int callerUid) { 2755ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid); 2765ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (String name : packages) { 2775ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana try { 2785ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana PackageInfo packageInfo = 2795ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mContext.getPackageManager().getPackageInfo(name, 0 /* flags */); 2805ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 2815ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return true; 2825ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 2835ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } catch (PackageManager.NameNotFoundException e) { 2845ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return false; 2855ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 2865ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 2875ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return false; 2885ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 289718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 2906ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey /** 2916ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey * Populate {@link UserServices#services} by scanning installed packages for 2926ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey * given {@link UserHandle}. 2936ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey */ 2946ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey private void generateServicesMap(int userId) { 29540e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn if (DEBUG) { 29640e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn Slog.d(TAG, "generateServicesMap() for " + userId); 29740e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn } 2986ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey 2996ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey final PackageManager pm = mContext.getPackageManager(); 3006ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey final ArrayList<ServiceInfo<V>> serviceInfos = new ArrayList<ServiceInfo<V>>(); 3016ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey final List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser( 3026ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey new Intent(mInterfaceName), PackageManager.GET_META_DATA, userId); 303718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana for (ResolveInfo resolveInfo : resolveInfos) { 304718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana try { 305718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana ServiceInfo<V> info = parseServiceInfo(resolveInfo); 3065ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (info == null) { 3075ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.w(TAG, "Unable to load service info " + resolveInfo.toString()); 3085ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana continue; 309718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 3105ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana serviceInfos.add(info); 311718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } catch (XmlPullParserException e) { 3125ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.w(TAG, "Unable to load service info " + resolveInfo.toString(), e); 313718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } catch (IOException e) { 3145ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.w(TAG, "Unable to load service info " + resolveInfo.toString(), e); 315718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 316718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 317718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 3185ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana synchronized (mServicesLock) { 3196ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey final UserServices<V> user = findOrCreateUserLocked(userId); 3206ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey final boolean firstScan = user.services == null; 3216ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey if (firstScan) { 3226ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey user.services = Maps.newHashMap(); 3236ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey } else { 3246ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey user.services.clear(); 3255ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3266ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey 3273fa51e3430e3bf902ae4f2d72dfb956103b6bd2dAlon Albert StringBuilder changes = new StringBuilder(); 32840e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn boolean changed = false; 3295ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (ServiceInfo<V> info : serviceInfos) { 3305ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // four cases: 3315ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - doesn't exist yet 3325ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - add, notify user that it was added 3335ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - exists and the UID is the same 3345ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - replace, don't notify user 3355ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - exists, the UID is different, and the new one is not a system package 3365ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - ignore 3375ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - exists, the UID is different, and the new one is a system package 3385ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - add, notify user that it was added 3396ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey Integer previousUid = user.persistentServices.get(info.type); 3405ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (previousUid == null) { 34140e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn if (DEBUG) { 34240e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn changes.append(" New service added: ").append(info).append("\n"); 34340e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn } 34440e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn changed = true; 3456ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey user.services.put(info.type, info); 3466ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey user.persistentServices.put(info.type, info.uid); 3476ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey if (!(mPersistentServicesFileDidNotExist && firstScan)) { 3486ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey notifyListener(info.type, userId, false /* removed */); 3495ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3505ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } else if (previousUid == info.uid) { 35140e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn if (DEBUG) { 3523fa51e3430e3bf902ae4f2d72dfb956103b6bd2dAlon Albert changes.append(" Existing service (nop): ").append(info).append("\n"); 3535ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3546ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey user.services.put(info.type, info); 3555ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } else if (inSystemImage(info.uid) 3565ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana || !containsTypeAndUid(serviceInfos, info.type, previousUid)) { 35740e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn if (DEBUG) { 35840e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn if (inSystemImage(info.uid)) { 35940e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn changes.append(" System service replacing existing: ").append(info) 36040e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn .append("\n"); 36140e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn } else { 36240e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn changes.append(" Existing service replacing a removed service: ") 36340e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn .append(info).append("\n"); 36440e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn } 3655ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 36640e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn changed = true; 3676ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey user.services.put(info.type, info); 3686ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey user.persistentServices.put(info.type, info.uid); 3696ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey notifyListener(info.type, userId, false /* removed */); 3705ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } else { 3715ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // ignore 37240e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn if (DEBUG) { 37340e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn changes.append(" Existing service with new uid ignored: ").append(info) 37440e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn .append("\n"); 37540e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn } 3765ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3775ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3785ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 3795ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana ArrayList<V> toBeRemoved = Lists.newArrayList(); 3806ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey for (V v1 : user.persistentServices.keySet()) { 3815ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (!containsType(serviceInfos, v1)) { 3825ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana toBeRemoved.add(v1); 3835ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3845ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3855ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (V v1 : toBeRemoved) { 38640e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn if (DEBUG) { 38740e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn changes.append(" Service removed: ").append(v1).append("\n"); 38840e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn } 38940e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn changed = true; 3906ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey user.persistentServices.remove(v1); 3916ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey notifyListener(v1, userId, true /* removed */); 3925ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 39340e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn if (DEBUG) { 39440e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn if (changes.length() > 0) { 3954428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " + 3964428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn serviceInfos.size() + " services:\n" + changes); 39740e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn } else { 3984428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " + 3994428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn serviceInfos.size() + " services unchanged"); 4004428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn } 4015ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 40240e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn if (changed) { 40340e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn writePersistentServicesLocked(); 40440e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn } 4055ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4065ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4075ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 4085ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private boolean containsType(ArrayList<ServiceInfo<V>> serviceInfos, V type) { 4095ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (int i = 0, N = serviceInfos.size(); i < N; i++) { 4105ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (serviceInfos.get(i).type.equals(type)) { 4115ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return true; 4125ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4135ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4145ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 4155ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return false; 4165ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4175ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 4185ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private boolean containsTypeAndUid(ArrayList<ServiceInfo<V>> serviceInfos, V type, int uid) { 4195ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (int i = 0, N = serviceInfos.size(); i < N; i++) { 4205ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana final ServiceInfo<V> serviceInfo = serviceInfos.get(i); 4215ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (serviceInfo.type.equals(type) && serviceInfo.uid == uid) { 4225ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return true; 4235ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4245ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4255ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 4265ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return false; 427718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 428718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 429718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private ServiceInfo<V> parseServiceInfo(ResolveInfo service) 430718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana throws XmlPullParserException, IOException { 431718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana android.content.pm.ServiceInfo si = service.serviceInfo; 432718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana ComponentName componentName = new ComponentName(si.packageName, si.name); 433718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 434718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana PackageManager pm = mContext.getPackageManager(); 435718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 436718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana XmlResourceParser parser = null; 437718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana try { 438718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana parser = si.loadXmlMetaData(pm, mMetaDataName); 439718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (parser == null) { 440718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana throw new XmlPullParserException("No " + mMetaDataName + " meta-data"); 441718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 442718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 443718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana AttributeSet attrs = Xml.asAttributeSet(parser); 444718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 445718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana int type; 446718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 447718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana && type != XmlPullParser.START_TAG) { 448718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 449718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 450718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana String nodeName = parser.getName(); 451718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (!mAttributesName.equals(nodeName)) { 452718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana throw new XmlPullParserException( 453718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana "Meta-data does not start with " + mAttributesName + " tag"); 454718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 455718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 45620cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn V v = parseServiceAttributes(pm.getResourcesForApplication(si.applicationInfo), 45720cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn si.packageName, attrs); 458718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (v == null) { 459718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana return null; 460718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 461d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana final android.content.pm.ServiceInfo serviceInfo = service.serviceInfo; 462d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana final ApplicationInfo applicationInfo = serviceInfo.applicationInfo; 463d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana final int uid = applicationInfo.uid; 464d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana return new ServiceInfo<V>(v, componentName, uid); 46520cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn } catch (NameNotFoundException e) { 46620cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn throw new XmlPullParserException( 46720cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn "Unable to load resources for pacakge " + si.packageName); 468718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } finally { 469718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (parser != null) parser.close(); 470718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 471718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 472718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 4735ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana /** 4745ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana * Read all sync status back in to the initial engine state. 4755ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana */ 4765ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private void readPersistentServicesLocked() { 4776ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey mUserServices.clear(); 4785ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (mSerializerAndParser == null) { 4795ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return; 4805ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4815ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana FileInputStream fis = null; 4825ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana try { 4835ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServicesFileDidNotExist = !mPersistentServicesFile.getBaseFile().exists(); 4845ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (mPersistentServicesFileDidNotExist) { 4855ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return; 4865ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4875ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana fis = mPersistentServicesFile.openRead(); 4885ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana XmlPullParser parser = Xml.newPullParser(); 4895ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana parser.setInput(fis, null); 4905ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana int eventType = parser.getEventType(); 491293ad6c6749044d97ea2a5f3fbd5c6ad58124584Jeff Sharkey while (eventType != XmlPullParser.START_TAG 492293ad6c6749044d97ea2a5f3fbd5c6ad58124584Jeff Sharkey && eventType != XmlPullParser.END_DOCUMENT) { 4935ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana eventType = parser.next(); 4945ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4955ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana String tagName = parser.getName(); 4965ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if ("services".equals(tagName)) { 4975ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana eventType = parser.next(); 4985ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana do { 4995ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (eventType == XmlPullParser.START_TAG && parser.getDepth() == 2) { 5005ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana tagName = parser.getName(); 5015ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if ("service".equals(tagName)) { 5025ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana V service = mSerializerAndParser.createFromXml(parser); 5035ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (service == null) { 5045ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana break; 5055ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 5065ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana String uidString = parser.getAttributeValue(null, "uid"); 5076ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey final int uid = Integer.parseInt(uidString); 5086ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey final int userId = UserHandle.getUserId(uid); 5096ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey final UserServices<V> user = findOrCreateUserLocked(userId); 5106ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey user.persistentServices.put(service, uid); 5115ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 5125ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 5135ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana eventType = parser.next(); 5145ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } while (eventType != XmlPullParser.END_DOCUMENT); 5155ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 5165ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } catch (Exception e) { 5175ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.w(TAG, "Error reading persistent services, starting from scratch", e); 5185ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } finally { 5195ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (fis != null) { 5205ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana try { 5215ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana fis.close(); 5225ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } catch (java.io.IOException e1) { 5235ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 5245ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 5255ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 5265ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 5275ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 5285ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana /** 5295ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana * Write all sync status to the sync status file. 5305ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana */ 5315ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private void writePersistentServicesLocked() { 5325ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (mSerializerAndParser == null) { 5335ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return; 5345ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 5355ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana FileOutputStream fos = null; 5365ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana try { 5375ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana fos = mPersistentServicesFile.startWrite(); 5385ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana XmlSerializer out = new FastXmlSerializer(); 5395ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.setOutput(fos, "utf-8"); 5405ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.startDocument(null, true); 5415ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 5425ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.startTag(null, "services"); 5436ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey for (int i = 0; i < mUserServices.size(); i++) { 5446ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey final UserServices<V> user = mUserServices.valueAt(i); 5456ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey for (Map.Entry<V, Integer> service : user.persistentServices.entrySet()) { 5466ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey out.startTag(null, "service"); 5476ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey out.attribute(null, "uid", Integer.toString(service.getValue())); 5486ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey mSerializerAndParser.writeAsXml(service.getKey(), out); 5496ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey out.endTag(null, "service"); 5506ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey } 5515ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 5525ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.endTag(null, "services"); 5535ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.endDocument(); 5545ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServicesFile.finishWrite(fos); 5555ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } catch (java.io.IOException e1) { 5565ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.w(TAG, "Error writing accounts", e1); 5575ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (fos != null) { 5585ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServicesFile.failWrite(fos); 5595ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 5605ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 5615ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 5625ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 56320cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn public abstract V parseServiceAttributes(Resources res, 56420cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn String packageName, AttributeSet attrs); 565718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana} 566