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; 29718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.util.Log; 30718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.util.AttributeSet; 31718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.util.Xml; 32718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 33718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.util.Map; 34718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.util.Collection; 35718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.util.Collections; 365ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport java.util.HashMap; 37718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.util.List; 385ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport java.util.ArrayList; 395ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport java.util.concurrent.atomic.AtomicReference; 405ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport java.io.File; 415ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport java.io.FileOutputStream; 42718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.io.FileDescriptor; 43718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.io.PrintWriter; 44718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.io.IOException; 455ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport java.io.FileInputStream; 465ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 475ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport com.android.internal.os.AtomicFile; 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 2545ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 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) { 3343fa51e3430e3bf902ae4f2d72dfb956103b6bd2dAlon Albert Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " + 3353fa51e3430e3bf902ae4f2d72dfb956103b6bd2dAlon Albert serviceInfos.size() + " services:\n" + changes); 3365ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana writePersistentServicesLocked(); 3375ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } else { 3383fa51e3430e3bf902ae4f2d72dfb956103b6bd2dAlon Albert Log.d(TAG, "generateServicesMap(" + mInterfaceName + "): " + 3393fa51e3430e3bf902ae4f2d72dfb956103b6bd2dAlon Albert serviceInfos.size() + " services unchanged"); 3405ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3415ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServicesFileDidNotExist = false; 3425ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3435ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3445ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 3455ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private boolean containsType(ArrayList<ServiceInfo<V>> serviceInfos, V type) { 3465ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (int i = 0, N = serviceInfos.size(); i < N; i++) { 3475ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (serviceInfos.get(i).type.equals(type)) { 3485ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return true; 3495ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3505ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3515ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 3525ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return false; 3535ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3545ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 3555ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private boolean containsTypeAndUid(ArrayList<ServiceInfo<V>> serviceInfos, V type, int uid) { 3565ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (int i = 0, N = serviceInfos.size(); i < N; i++) { 3575ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana final ServiceInfo<V> serviceInfo = serviceInfos.get(i); 3585ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (serviceInfo.type.equals(type) && serviceInfo.uid == uid) { 3595ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return true; 3605ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3615ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3625ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 3635ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return false; 364718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 365718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 366718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private ServiceInfo<V> parseServiceInfo(ResolveInfo service) 367718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana throws XmlPullParserException, IOException { 368718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana android.content.pm.ServiceInfo si = service.serviceInfo; 369718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana ComponentName componentName = new ComponentName(si.packageName, si.name); 370718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 371718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana PackageManager pm = mContext.getPackageManager(); 372718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 373718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana XmlResourceParser parser = null; 374718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana try { 375718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana parser = si.loadXmlMetaData(pm, mMetaDataName); 376718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (parser == null) { 377718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana throw new XmlPullParserException("No " + mMetaDataName + " meta-data"); 378718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 379718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 380718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana AttributeSet attrs = Xml.asAttributeSet(parser); 381718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 382718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana int type; 383718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 384718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana && type != XmlPullParser.START_TAG) { 385718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 386718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 387718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana String nodeName = parser.getName(); 388718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (!mAttributesName.equals(nodeName)) { 389718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana throw new XmlPullParserException( 390718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana "Meta-data does not start with " + mAttributesName + " tag"); 391718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 392718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 39320cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn V v = parseServiceAttributes(pm.getResourcesForApplication(si.applicationInfo), 39420cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn si.packageName, attrs); 395718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (v == null) { 396718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana return null; 397718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 398d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana final android.content.pm.ServiceInfo serviceInfo = service.serviceInfo; 399d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana final ApplicationInfo applicationInfo = serviceInfo.applicationInfo; 400d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana final int uid = applicationInfo.uid; 401d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana return new ServiceInfo<V>(v, componentName, uid); 40220cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn } catch (NameNotFoundException e) { 40320cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn throw new XmlPullParserException( 40420cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn "Unable to load resources for pacakge " + si.packageName); 405718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } finally { 406718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (parser != null) parser.close(); 407718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 408718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 409718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 4105ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana /** 4115ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana * Read all sync status back in to the initial engine state. 4125ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana */ 4135ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private void readPersistentServicesLocked() { 4145ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServices = Maps.newHashMap(); 4155ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (mSerializerAndParser == null) { 4165ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return; 4175ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4185ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana FileInputStream fis = null; 4195ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana try { 4205ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServicesFileDidNotExist = !mPersistentServicesFile.getBaseFile().exists(); 4215ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (mPersistentServicesFileDidNotExist) { 4225ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return; 4235ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4245ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana fis = mPersistentServicesFile.openRead(); 4255ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana XmlPullParser parser = Xml.newPullParser(); 4265ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana parser.setInput(fis, null); 4275ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana int eventType = parser.getEventType(); 4285ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana while (eventType != XmlPullParser.START_TAG) { 4295ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana eventType = parser.next(); 4305ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4315ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana String tagName = parser.getName(); 4325ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if ("services".equals(tagName)) { 4335ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana eventType = parser.next(); 4345ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana do { 4355ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (eventType == XmlPullParser.START_TAG && parser.getDepth() == 2) { 4365ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana tagName = parser.getName(); 4375ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if ("service".equals(tagName)) { 4385ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana V service = mSerializerAndParser.createFromXml(parser); 4395ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (service == null) { 4405ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana break; 4415ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4425ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana String uidString = parser.getAttributeValue(null, "uid"); 4435ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana int uid = Integer.parseInt(uidString); 4445ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServices.put(service, uid); 4455ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4465ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4475ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana eventType = parser.next(); 4485ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } while (eventType != XmlPullParser.END_DOCUMENT); 4495ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4505ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } catch (Exception e) { 4515ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.w(TAG, "Error reading persistent services, starting from scratch", e); 4525ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } finally { 4535ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (fis != null) { 4545ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana try { 4555ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana fis.close(); 4565ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } catch (java.io.IOException e1) { 4575ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4585ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4595ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4605ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4615ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 4625ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana /** 4635ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana * Write all sync status to the sync status file. 4645ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana */ 4655ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private void writePersistentServicesLocked() { 4665ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (mSerializerAndParser == null) { 4675ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return; 4685ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4695ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana FileOutputStream fos = null; 4705ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana try { 4715ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana fos = mPersistentServicesFile.startWrite(); 4725ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana XmlSerializer out = new FastXmlSerializer(); 4735ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.setOutput(fos, "utf-8"); 4745ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.startDocument(null, true); 4755ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 4765ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.startTag(null, "services"); 4775ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (Map.Entry<V, Integer> service : mPersistentServices.entrySet()) { 4785ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.startTag(null, "service"); 4795ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.attribute(null, "uid", Integer.toString(service.getValue())); 4805ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mSerializerAndParser.writeAsXml(service.getKey(), out); 4815ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.endTag(null, "service"); 4825ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4835ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.endTag(null, "services"); 4845ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.endDocument(); 4855ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServicesFile.finishWrite(fos); 4865ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } catch (java.io.IOException e1) { 4875ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.w(TAG, "Error writing accounts", e1); 4885ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (fos != null) { 4895ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServicesFile.failWrite(fos); 4905ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4915ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4925ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4935ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 49420cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn public abstract V parseServiceAttributes(Resources res, 49520cb56e26e91df91bd64d4251222e0d421cdbe47Dianne Hackborn String packageName, AttributeSet attrs); 496718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana} 497