RegisteredServicesCache.java revision 4428e17c5e05c0dad76da8f1c28ccba62a66cd91
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.Context; 20718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.content.BroadcastReceiver; 21718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.content.Intent; 22718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.content.IntentFilter; 23718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.content.ComponentName; 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; 2939606a007a5b1309dd000234f2b8cf156c49fd0fDianne Hackbornimport android.util.AtomicFile; 30718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.util.Log; 31718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.util.AttributeSet; 32718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.util.Xml; 33718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 34718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.util.Map; 35718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.util.Collection; 36718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.util.Collections; 375ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport java.util.HashMap; 38718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.util.List; 395ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport java.util.ArrayList; 405ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport java.util.concurrent.atomic.AtomicReference; 415ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport java.io.File; 425ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport java.io.FileOutputStream; 43718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.io.FileDescriptor; 44718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.io.PrintWriter; 45718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.io.IOException; 465ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport java.io.FileInputStream; 475ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 482269d1572e5fcfb725ea55f5764d8c3280d69f6dDianne Hackbornimport com.android.internal.util.FastXmlSerializer; 49718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 50718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport com.google.android.collect.Maps; 515ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport com.google.android.collect.Lists; 525ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 53718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport org.xmlpull.v1.XmlPullParserException; 54718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport org.xmlpull.v1.XmlPullParser; 555ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport org.xmlpull.v1.XmlSerializer; 56718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 57718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana/** 58718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * A cache of registered services. This cache 59718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * is built by interrogating the {@link PackageManager} and is updated as packages are added, 60718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * removed and changed. The services are referred to by type V and 61718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * are made available via the {@link #getServiceInfo} method. 62718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * @hide 63718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 64718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanapublic abstract class RegisteredServicesCache<V> { 65718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private static final String TAG = "PackageManager"; 66718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 67718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public final Context mContext; 68718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private final String mInterfaceName; 69718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private final String mMetaDataName; 70718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private final String mAttributesName; 715ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private final XmlSerializerAndParser<V> mSerializerAndParser; 725ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private final AtomicReference<BroadcastReceiver> mReceiver; 73718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 745ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private final Object mServicesLock = new Object(); 755ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // synchronized on mServicesLock 765ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private HashMap<V, Integer> mPersistentServices; 775ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // synchronized on mServicesLock 785ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private Map<V, ServiceInfo<V>> mServices; 795ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // synchronized on mServicesLock 805ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private boolean mPersistentServicesFileDidNotExist; 813ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana 825ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana /** 835ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana * This file contains the list of known services. We would like to maintain this forever 845ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana * so we store it as an XML file. 855ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana */ 865ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private final AtomicFile mPersistentServicesFile; 87718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 885ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // the listener and handler are synchronized on "this" and must be updated together 895ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private RegisteredServicesCacheListener<V> mListener; 905ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private Handler mHandler; 91718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 92718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public RegisteredServicesCache(Context context, String interfaceName, String metaDataName, 935ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana String attributeName, XmlSerializerAndParser<V> serializerAndParser) { 94718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mContext = context; 95718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mInterfaceName = interfaceName; 96718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mMetaDataName = metaDataName; 97718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mAttributesName = attributeName; 985ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mSerializerAndParser = serializerAndParser; 995ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 1005ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana File dataDir = Environment.getDataDirectory(); 1015ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana File systemDir = new File(dataDir, "system"); 1025ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana File syncDir = new File(systemDir, "registered_services"); 1035ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServicesFile = new AtomicFile(new File(syncDir, interfaceName + ".xml")); 1045ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 1055ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana generateServicesMap(); 1065ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 1075ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana final BroadcastReceiver receiver = new BroadcastReceiver() { 1085ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana @Override 1095ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana public void onReceive(Context context1, Intent intent) { 1105ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana generateServicesMap(); 1115ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 1125ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana }; 1135ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mReceiver = new AtomicReference<BroadcastReceiver>(receiver); 1145ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana IntentFilter intentFilter = new IntentFilter(); 1155ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 1165ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 1175ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 1185ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana intentFilter.addDataScheme("package"); 1195ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mContext.registerReceiver(receiver, intentFilter); 12008675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu // Register for events related to sdcard installation. 12108675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu IntentFilter sdFilter = new IntentFilter(); 122b56ae20b22fd7283df32072a431ab6d4965f3c1bSuchi Amalapurapu sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); 123b56ae20b22fd7283df32072a431ab6d4965f3c1bSuchi Amalapurapu sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 12408675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu mContext.registerReceiver(receiver, sdFilter); 125718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 126718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 127718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public void dump(FileDescriptor fd, PrintWriter fout, String[] args) { 1285ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Map<V, ServiceInfo<V>> services; 1295ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana synchronized (mServicesLock) { 1305ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana services = mServices; 1315ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 132718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana fout.println("RegisteredServicesCache: " + services.size() + " services"); 133718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana for (ServiceInfo info : services.values()) { 134718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana fout.println(" " + info); 135718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 136718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 137718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 1385ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana public RegisteredServicesCacheListener<V> getListener() { 139718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana synchronized (this) { 1405ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return mListener; 1415ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 1425ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 143718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 1445ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana public void setListener(RegisteredServicesCacheListener<V> listener, Handler handler) { 1455ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (handler == null) { 1465ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana handler = new Handler(mContext.getMainLooper()); 1475ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 1485ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana synchronized (this) { 1495ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mHandler = handler; 1505ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mListener = listener; 151718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 152718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 153718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 1545ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private void notifyListener(final V type, final boolean removed) { 1555ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (Log.isLoggable(TAG, Log.VERBOSE)) { 1565ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.d(TAG, "notifyListener: " + type + " is " + (removed ? "removed" : "added")); 1575ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 1585ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana RegisteredServicesCacheListener<V> listener; 1595ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Handler handler; 160718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana synchronized (this) { 1615ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana listener = mListener; 1625ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana handler = mHandler; 1635ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 1645ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (listener == null) { 1655ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return; 166718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 1675ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 1685ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana final RegisteredServicesCacheListener<V> listener2 = listener; 1695ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana handler.post(new Runnable() { 1705ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana public void run() { 1715ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana listener2.onServiceChanged(type, removed); 1725ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 1735ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana }); 174718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 175718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 176718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana /** 177718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * Value type that describes a Service. The information within can be used 178718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * to bind to the service. 179718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 180718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public static class ServiceInfo<V> { 181718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public final V type; 182718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public final ComponentName componentName; 183d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana public final int uid; 184718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 18556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana /** @hide */ 18656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana public ServiceInfo(V type, ComponentName componentName, int uid) { 187718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana this.type = type; 188718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana this.componentName = componentName; 189d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana this.uid = uid; 190718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 191718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 192c42c0dd1c4e2f7a4abaac1b2c9a6344448f9db7aJeff Hamilton @Override 193718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public String toString() { 1945ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return "ServiceInfo: " + type + ", " + componentName + ", uid " + uid; 195718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 196718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 197718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 198718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana /** 199718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * Accessor for the registered authenticators. 200718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * @param type the account type of the authenticator 201718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * @return the AuthenticatorInfo that matches the account type or null if none is present 202718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 2039788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana public ServiceInfo<V> getServiceInfo(V type) { 2045ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana synchronized (mServicesLock) { 2055ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return mServices.get(type); 206718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 207718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 208718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 209718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana /** 210718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * @return a collection of {@link RegisteredServicesCache.ServiceInfo} objects for all 211718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * registered authenticators. 212718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 213718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public Collection<ServiceInfo<V>> getAllServices() { 2145ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana synchronized (mServicesLock) { 2155ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return Collections.unmodifiableCollection(mServices.values()); 216718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 217718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 218718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 219718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana /** 220718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * Stops the monitoring of package additions, removals and changes. 221718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 222718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public void close() { 2235ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana final BroadcastReceiver receiver = mReceiver.getAndSet(null); 2245ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (receiver != null) { 2255ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mContext.unregisterReceiver(receiver); 2265ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 227718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 228718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 229c42c0dd1c4e2f7a4abaac1b2c9a6344448f9db7aJeff Hamilton @Override 230718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana protected void finalize() throws Throwable { 2315ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (mReceiver.get() != null) { 2325ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.e(TAG, "RegisteredServicesCache finalized without being closed"); 233718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 234718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana close(); 235718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana super.finalize(); 236718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 237718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 2385ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private boolean inSystemImage(int callerUid) { 2395ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid); 2405ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (String name : packages) { 2415ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana try { 2425ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana PackageInfo packageInfo = 2435ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mContext.getPackageManager().getPackageInfo(name, 0 /* flags */); 2445ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 2455ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return true; 2465ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 2475ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } catch (PackageManager.NameNotFoundException e) { 2485ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return false; 2495ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 2505ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 2515ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return false; 2525ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 253718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 25426ff6626fc4ee0ae46f01ad309b366921da589feKenny Root public void generateServicesMap() { 2555ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana PackageManager pm = mContext.getPackageManager(); 2565ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana ArrayList<ServiceInfo<V>> serviceInfos = new ArrayList<ServiceInfo<V>>(); 2575ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana List<ResolveInfo> resolveInfos = pm.queryIntentServices(new Intent(mInterfaceName), 2585ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana PackageManager.GET_META_DATA); 259718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana for (ResolveInfo resolveInfo : resolveInfos) { 260718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana try { 261718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana ServiceInfo<V> info = parseServiceInfo(resolveInfo); 2625ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (info == null) { 2635ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.w(TAG, "Unable to load service info " + resolveInfo.toString()); 2645ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana continue; 265718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 2665ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana serviceInfos.add(info); 267718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } catch (XmlPullParserException e) { 2685ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.w(TAG, "Unable to load service info " + resolveInfo.toString(), e); 269718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } catch (IOException e) { 2705ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.w(TAG, "Unable to load service info " + resolveInfo.toString(), e); 271718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 272718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 273718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 2745ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana synchronized (mServicesLock) { 2755ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (mPersistentServices == null) { 2765ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana readPersistentServicesLocked(); 2775ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 2785ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mServices = Maps.newHashMap(); 2793fa51e3430e3bf902ae4f2d72dfb956103b6bd2dAlon Albert StringBuilder changes = new StringBuilder(); 2805ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (ServiceInfo<V> info : serviceInfos) { 2815ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // four cases: 2825ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - doesn't exist yet 2835ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - add, notify user that it was added 2845ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - exists and the UID is the same 2855ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - replace, don't notify user 2865ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - exists, the UID is different, and the new one is not a system package 2875ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - ignore 2885ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - exists, the UID is different, and the new one is a system package 2895ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - add, notify user that it was added 2905ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Integer previousUid = mPersistentServices.get(info.type); 2915ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (previousUid == null) { 2923fa51e3430e3bf902ae4f2d72dfb956103b6bd2dAlon Albert changes.append(" New service added: ").append(info).append("\n"); 2935ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mServices.put(info.type, info); 2945ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServices.put(info.type, info.uid); 2955ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (!mPersistentServicesFileDidNotExist) { 2965ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana notifyListener(info.type, false /* removed */); 2975ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 2985ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } else if (previousUid == info.uid) { 2995ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (Log.isLoggable(TAG, Log.VERBOSE)) { 3003fa51e3430e3bf902ae4f2d72dfb956103b6bd2dAlon Albert changes.append(" Existing service (nop): ").append(info).append("\n"); 3015ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3025ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mServices.put(info.type, info); 3035ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } else if (inSystemImage(info.uid) 3045ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana || !containsTypeAndUid(serviceInfos, info.type, previousUid)) { 3053fa51e3430e3bf902ae4f2d72dfb956103b6bd2dAlon Albert if (inSystemImage(info.uid)) { 3063fa51e3430e3bf902ae4f2d72dfb956103b6bd2dAlon Albert changes.append(" System service replacing existing: ").append(info) 3073fa51e3430e3bf902ae4f2d72dfb956103b6bd2dAlon Albert .append("\n"); 3083fa51e3430e3bf902ae4f2d72dfb956103b6bd2dAlon Albert } else { 3093fa51e3430e3bf902ae4f2d72dfb956103b6bd2dAlon Albert changes.append(" Existing service replacing a removed service: ") 3103fa51e3430e3bf902ae4f2d72dfb956103b6bd2dAlon Albert .append(info).append("\n"); 3115ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3125ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mServices.put(info.type, info); 3135ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServices.put(info.type, info.uid); 3145ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana notifyListener(info.type, false /* removed */); 3155ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } else { 3165ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // ignore 3173fa51e3430e3bf902ae4f2d72dfb956103b6bd2dAlon Albert changes.append(" Existing service with new uid ignored: ").append(info) 3183fa51e3430e3bf902ae4f2d72dfb956103b6bd2dAlon Albert .append("\n"); 3195ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3205ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3215ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 3225ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana ArrayList<V> toBeRemoved = Lists.newArrayList(); 3235ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (V v1 : mPersistentServices.keySet()) { 3245ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (!containsType(serviceInfos, v1)) { 3255ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana toBeRemoved.add(v1); 3265ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3275ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3285ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (V v1 : toBeRemoved) { 3295ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServices.remove(v1); 3303fa51e3430e3bf902ae4f2d72dfb956103b6bd2dAlon Albert changes.append(" Service removed: ").append(v1).append("\n"); 3315ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana notifyListener(v1, true /* removed */); 3325ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3333fa51e3430e3bf902ae4f2d72dfb956103b6bd2dAlon Albert if (changes.length() > 0) { 3344428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn if (Log.isLoggable(TAG, Log.VERBOSE)) { 3354428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " + 3364428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn serviceInfos.size() + " services:\n" + changes); 3374428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn } 3385ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana writePersistentServicesLocked(); 3395ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } else { 3404428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn if (Log.isLoggable(TAG, Log.VERBOSE)) { 3414428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " + 3424428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn serviceInfos.size() + " services unchanged"); 3434428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn } 3445ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3455ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServicesFileDidNotExist = false; 3465ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3475ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3485ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 3495ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private boolean containsType(ArrayList<ServiceInfo<V>> serviceInfos, V type) { 3505ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (int i = 0, N = serviceInfos.size(); i < N; i++) { 3515ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (serviceInfos.get(i).type.equals(type)) { 3525ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return true; 3535ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3545ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3555ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 3565ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return false; 3575ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3585ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 3595ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private boolean containsTypeAndUid(ArrayList<ServiceInfo<V>> serviceInfos, V type, int uid) { 3605ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (int i = 0, N = serviceInfos.size(); i < N; i++) { 3615ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana final ServiceInfo<V> serviceInfo = serviceInfos.get(i); 3625ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (serviceInfo.type.equals(type) && serviceInfo.uid == uid) { 3635ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return true; 3645ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3655ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3665ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 3675ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return false; 368718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 369718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 370718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private ServiceInfo<V> parseServiceInfo(ResolveInfo service) 371718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana throws XmlPullParserException, IOException { 372718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana android.content.pm.ServiceInfo si = service.serviceInfo; 373718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana ComponentName componentName = new ComponentName(si.packageName, si.name); 374718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 375718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana PackageManager pm = mContext.getPackageManager(); 376718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 377718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana XmlResourceParser parser = null; 378718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana try { 379718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana parser = si.loadXmlMetaData(pm, mMetaDataName); 380718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (parser == null) { 381718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana throw new XmlPullParserException("No " + mMetaDataName + " meta-data"); 382718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 383718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 384718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana AttributeSet attrs = Xml.asAttributeSet(parser); 385718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 386718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana int type; 387718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 388718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana && type != XmlPullParser.START_TAG) { 389718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 390718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 391718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana String nodeName = parser.getName(); 392718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (!mAttributesName.equals(nodeName)) { 393718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana throw new XmlPullParserException( 394718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana "Meta-data does not start with " + mAttributesName + " tag"); 395718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 396718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 39720cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn V v = parseServiceAttributes(pm.getResourcesForApplication(si.applicationInfo), 39820cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn si.packageName, attrs); 399718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (v == null) { 400718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana return null; 401718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 402d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana final android.content.pm.ServiceInfo serviceInfo = service.serviceInfo; 403d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana final ApplicationInfo applicationInfo = serviceInfo.applicationInfo; 404d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana final int uid = applicationInfo.uid; 405d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana return new ServiceInfo<V>(v, componentName, uid); 40620cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn } catch (NameNotFoundException e) { 40720cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn throw new XmlPullParserException( 40820cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn "Unable to load resources for pacakge " + si.packageName); 409718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } finally { 410718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (parser != null) parser.close(); 411718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 412718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 413718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 4145ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana /** 4155ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana * Read all sync status back in to the initial engine state. 4165ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana */ 4175ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private void readPersistentServicesLocked() { 4185ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServices = Maps.newHashMap(); 4195ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (mSerializerAndParser == null) { 4205ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return; 4215ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4225ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana FileInputStream fis = null; 4235ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana try { 4245ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServicesFileDidNotExist = !mPersistentServicesFile.getBaseFile().exists(); 4255ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (mPersistentServicesFileDidNotExist) { 4265ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return; 4275ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4285ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana fis = mPersistentServicesFile.openRead(); 4295ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana XmlPullParser parser = Xml.newPullParser(); 4305ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana parser.setInput(fis, null); 4315ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana int eventType = parser.getEventType(); 4325ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana while (eventType != XmlPullParser.START_TAG) { 4335ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana eventType = parser.next(); 4345ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4355ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana String tagName = parser.getName(); 4365ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if ("services".equals(tagName)) { 4375ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana eventType = parser.next(); 4385ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana do { 4395ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (eventType == XmlPullParser.START_TAG && parser.getDepth() == 2) { 4405ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana tagName = parser.getName(); 4415ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if ("service".equals(tagName)) { 4425ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana V service = mSerializerAndParser.createFromXml(parser); 4435ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (service == null) { 4445ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana break; 4455ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4465ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana String uidString = parser.getAttributeValue(null, "uid"); 4475ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana int uid = Integer.parseInt(uidString); 4485ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServices.put(service, uid); 4495ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4505ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4515ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana eventType = parser.next(); 4525ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } while (eventType != XmlPullParser.END_DOCUMENT); 4535ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4545ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } catch (Exception e) { 4555ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.w(TAG, "Error reading persistent services, starting from scratch", e); 4565ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } finally { 4575ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (fis != null) { 4585ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana try { 4595ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana fis.close(); 4605ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } catch (java.io.IOException e1) { 4615ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4625ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4635ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4645ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4655ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 4665ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana /** 4675ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana * Write all sync status to the sync status file. 4685ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana */ 4695ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private void writePersistentServicesLocked() { 4705ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (mSerializerAndParser == null) { 4715ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return; 4725ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4735ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana FileOutputStream fos = null; 4745ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana try { 4755ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana fos = mPersistentServicesFile.startWrite(); 4765ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana XmlSerializer out = new FastXmlSerializer(); 4775ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.setOutput(fos, "utf-8"); 4785ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.startDocument(null, true); 4795ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 4805ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.startTag(null, "services"); 4815ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (Map.Entry<V, Integer> service : mPersistentServices.entrySet()) { 4825ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.startTag(null, "service"); 4835ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.attribute(null, "uid", Integer.toString(service.getValue())); 4845ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mSerializerAndParser.writeAsXml(service.getKey(), out); 4855ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.endTag(null, "service"); 4865ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4875ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.endTag(null, "services"); 4885ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.endDocument(); 4895ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServicesFile.finishWrite(fos); 4905ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } catch (java.io.IOException e1) { 4915ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.w(TAG, "Error writing accounts", e1); 4925ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (fos != null) { 4935ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServicesFile.failWrite(fos); 4945ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4955ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4965ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4975ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 49820cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn public abstract V parseServiceAttributes(Resources res, 49920cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn String packageName, AttributeSet attrs); 500718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana} 501