RegisteredServicesCache.java revision b56ae20b22fd7283df32072a431ab6d4965f3c1b
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; 24718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.content.res.XmlResourceParser; 255ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport android.os.Environment; 265ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport android.os.Handler; 27718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.util.Log; 28718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.util.AttributeSet; 29718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.util.Xml; 30718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 31718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.util.Map; 32718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.util.Collection; 33718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.util.Collections; 345ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport java.util.HashMap; 35718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.util.List; 365ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport java.util.ArrayList; 375ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport java.util.concurrent.atomic.AtomicReference; 385ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport java.io.File; 395ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport java.io.FileOutputStream; 40718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.io.FileDescriptor; 41718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.io.PrintWriter; 42718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.io.IOException; 435ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport java.io.FileInputStream; 445ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 455ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport com.android.internal.os.AtomicFile; 46d4a4729c0cac582a2dcec7c8cfb316b81885a0f0Tom Taylorimport com.android.common.FastXmlSerializer; 47718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 48718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport com.google.android.collect.Maps; 495ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport com.google.android.collect.Lists; 505ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 51718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport org.xmlpull.v1.XmlPullParserException; 52718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport org.xmlpull.v1.XmlPullParser; 535ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintanaimport org.xmlpull.v1.XmlSerializer; 54718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 55718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana/** 56718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * A cache of registered services. This cache 57718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * is built by interrogating the {@link PackageManager} and is updated as packages are added, 58718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * removed and changed. The services are referred to by type V and 59718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * are made available via the {@link #getServiceInfo} method. 60718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * @hide 61718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 62718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanapublic abstract class RegisteredServicesCache<V> { 63718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private static final String TAG = "PackageManager"; 64718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 65718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public final Context mContext; 66718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private final String mInterfaceName; 67718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private final String mMetaDataName; 68718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private final String mAttributesName; 695ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private final XmlSerializerAndParser<V> mSerializerAndParser; 705ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private final AtomicReference<BroadcastReceiver> mReceiver; 71718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 725ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private final Object mServicesLock = new Object(); 735ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // synchronized on mServicesLock 745ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private HashMap<V, Integer> mPersistentServices; 755ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // synchronized on mServicesLock 765ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private Map<V, ServiceInfo<V>> mServices; 775ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // synchronized on mServicesLock 785ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private boolean mPersistentServicesFileDidNotExist; 793ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana 805ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana /** 815ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana * This file contains the list of known services. We would like to maintain this forever 825ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana * so we store it as an XML file. 835ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana */ 845ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private final AtomicFile mPersistentServicesFile; 85718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 865ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // the listener and handler are synchronized on "this" and must be updated together 875ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private RegisteredServicesCacheListener<V> mListener; 885ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private Handler mHandler; 89718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 90718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public RegisteredServicesCache(Context context, String interfaceName, String metaDataName, 915ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana String attributeName, XmlSerializerAndParser<V> serializerAndParser) { 92718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mContext = context; 93718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mInterfaceName = interfaceName; 94718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mMetaDataName = metaDataName; 95718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mAttributesName = attributeName; 965ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mSerializerAndParser = serializerAndParser; 975ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 985ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana File dataDir = Environment.getDataDirectory(); 995ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana File systemDir = new File(dataDir, "system"); 1005ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana File syncDir = new File(systemDir, "registered_services"); 1015ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServicesFile = new AtomicFile(new File(syncDir, interfaceName + ".xml")); 1025ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 1035ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana generateServicesMap(); 1045ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 1055ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana final BroadcastReceiver receiver = new BroadcastReceiver() { 1065ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana @Override 1075ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana public void onReceive(Context context1, Intent intent) { 1085ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana generateServicesMap(); 1095ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 1105ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana }; 1115ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mReceiver = new AtomicReference<BroadcastReceiver>(receiver); 1125ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana IntentFilter intentFilter = new IntentFilter(); 1135ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 1145ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 1155ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 1165ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana intentFilter.addDataScheme("package"); 1175ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mContext.registerReceiver(receiver, intentFilter); 11808675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu // Register for events related to sdcard installation. 11908675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu IntentFilter sdFilter = new IntentFilter(); 120b56ae20b22fd7283df32072a431ab6d4965f3c1bSuchi Amalapurapu sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); 121b56ae20b22fd7283df32072a431ab6d4965f3c1bSuchi Amalapurapu sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 12208675a3376819a82aa5ab344bc3e7b1635c30b05Suchi Amalapurapu mContext.registerReceiver(receiver, sdFilter); 123718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 124718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 125718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public void dump(FileDescriptor fd, PrintWriter fout, String[] args) { 1265ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Map<V, ServiceInfo<V>> services; 1275ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana synchronized (mServicesLock) { 1285ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana services = mServices; 1295ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 130718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana fout.println("RegisteredServicesCache: " + services.size() + " services"); 131718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana for (ServiceInfo info : services.values()) { 132718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana fout.println(" " + info); 133718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 134718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 135718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 1365ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana public RegisteredServicesCacheListener<V> getListener() { 137718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana synchronized (this) { 1385ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return mListener; 1395ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 1405ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 141718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 1425ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana public void setListener(RegisteredServicesCacheListener<V> listener, Handler handler) { 1435ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (handler == null) { 1445ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana handler = new Handler(mContext.getMainLooper()); 1455ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 1465ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana synchronized (this) { 1475ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mHandler = handler; 1485ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mListener = listener; 149718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 150718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 151718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 1525ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private void notifyListener(final V type, final boolean removed) { 1535ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (Log.isLoggable(TAG, Log.VERBOSE)) { 1545ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.d(TAG, "notifyListener: " + type + " is " + (removed ? "removed" : "added")); 1555ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 1565ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana RegisteredServicesCacheListener<V> listener; 1575ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Handler handler; 158718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana synchronized (this) { 1595ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana listener = mListener; 1605ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana handler = mHandler; 1615ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 1625ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (listener == null) { 1635ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return; 164718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 1655ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 1665ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana final RegisteredServicesCacheListener<V> listener2 = listener; 1675ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana handler.post(new Runnable() { 1685ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana public void run() { 1695ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana listener2.onServiceChanged(type, removed); 1705ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 1715ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana }); 172718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 173718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 174718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana /** 175718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * Value type that describes a Service. The information within can be used 176718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * to bind to the service. 177718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 178718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public static class ServiceInfo<V> { 179718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public final V type; 180718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public final ComponentName componentName; 181d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana public final int uid; 182718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 183d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana private ServiceInfo(V type, ComponentName componentName, int uid) { 184718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana this.type = type; 185718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana this.componentName = componentName; 186d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana this.uid = uid; 187718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 188718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 189c42c0dd1c4e2f7a4abaac1b2c9a6344448f9db7aJeff Hamilton @Override 190718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public String toString() { 1915ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return "ServiceInfo: " + type + ", " + componentName + ", uid " + uid; 192718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 193718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 194718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 195718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana /** 196718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * Accessor for the registered authenticators. 197718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * @param type the account type of the authenticator 198718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * @return the AuthenticatorInfo that matches the account type or null if none is present 199718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 2009788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana public ServiceInfo<V> getServiceInfo(V type) { 2015ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana synchronized (mServicesLock) { 2025ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return mServices.get(type); 203718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 204718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 205718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 206718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana /** 207718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * @return a collection of {@link RegisteredServicesCache.ServiceInfo} objects for all 208718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * registered authenticators. 209718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 210718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public Collection<ServiceInfo<V>> getAllServices() { 2115ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana synchronized (mServicesLock) { 2125ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return Collections.unmodifiableCollection(mServices.values()); 213718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 214718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 215718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 216718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana /** 217718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * Stops the monitoring of package additions, removals and changes. 218718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 219718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public void close() { 2205ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana final BroadcastReceiver receiver = mReceiver.getAndSet(null); 2215ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (receiver != null) { 2225ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mContext.unregisterReceiver(receiver); 2235ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 224718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 225718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 226c42c0dd1c4e2f7a4abaac1b2c9a6344448f9db7aJeff Hamilton @Override 227718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana protected void finalize() throws Throwable { 2285ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (mReceiver.get() != null) { 2295ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.e(TAG, "RegisteredServicesCache finalized without being closed"); 230718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 231718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana close(); 232718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana super.finalize(); 233718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 234718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 2355ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private boolean inSystemImage(int callerUid) { 2365ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid); 2375ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (String name : packages) { 2385ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana try { 2395ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana PackageInfo packageInfo = 2405ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mContext.getPackageManager().getPackageInfo(name, 0 /* flags */); 2415ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 2425ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return true; 2435ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 2445ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } catch (PackageManager.NameNotFoundException e) { 2455ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return false; 2465ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 2475ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 2485ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return false; 2495ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 250718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 2515ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana void generateServicesMap() { 2525ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana PackageManager pm = mContext.getPackageManager(); 2535ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana ArrayList<ServiceInfo<V>> serviceInfos = new ArrayList<ServiceInfo<V>>(); 2545ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana List<ResolveInfo> resolveInfos = pm.queryIntentServices(new Intent(mInterfaceName), 2555ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana PackageManager.GET_META_DATA); 256718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana for (ResolveInfo resolveInfo : resolveInfos) { 257718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana try { 258718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana ServiceInfo<V> info = parseServiceInfo(resolveInfo); 2595ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (info == null) { 2605ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.w(TAG, "Unable to load service info " + resolveInfo.toString()); 2615ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana continue; 262718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 2635ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana serviceInfos.add(info); 264718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } catch (XmlPullParserException e) { 2655ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.w(TAG, "Unable to load service info " + resolveInfo.toString(), e); 266718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } catch (IOException e) { 2675ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.w(TAG, "Unable to load service info " + resolveInfo.toString(), e); 268718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 269718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 270718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 2715ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana synchronized (mServicesLock) { 2725ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (Log.isLoggable(TAG, Log.VERBOSE)) { 2735ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.d(TAG, "generateServicesMap: " + mInterfaceName); 2745ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 2755ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (mPersistentServices == null) { 2765ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana readPersistentServicesLocked(); 2775ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 2785ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mServices = Maps.newHashMap(); 2795ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana boolean changed = false; 2805ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (Log.isLoggable(TAG, Log.VERBOSE)) { 2815ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.d(TAG, "found " + serviceInfos.size() + " services"); 2825ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 2835ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (ServiceInfo<V> info : serviceInfos) { 2845ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // four cases: 2855ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - doesn't exist yet 2865ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - add, notify user that it was added 2875ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - exists and the UID is the same 2885ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - replace, don't notify user 2895ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - exists, the UID is different, and the new one is not a system package 2905ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - ignore 2915ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - exists, the UID is different, and the new one is a system package 2925ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // - add, notify user that it was added 2935ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Integer previousUid = mPersistentServices.get(info.type); 2945ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (previousUid == null) { 2955ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (Log.isLoggable(TAG, Log.VERBOSE)) { 2965ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.d(TAG, "encountered new type: " + info); 2975ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 2985ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana changed = true; 2995ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mServices.put(info.type, info); 3005ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServices.put(info.type, info.uid); 3015ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (!mPersistentServicesFileDidNotExist) { 3025ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana notifyListener(info.type, false /* removed */); 3035ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3045ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } else if (previousUid == info.uid) { 3055ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (Log.isLoggable(TAG, Log.VERBOSE)) { 3065ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.d(TAG, "encountered existing type with the same uid: " + info); 3075ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3085ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mServices.put(info.type, info); 3095ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } else if (inSystemImage(info.uid) 3105ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana || !containsTypeAndUid(serviceInfos, info.type, previousUid)) { 3115ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (Log.isLoggable(TAG, Log.VERBOSE)) { 3125ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (inSystemImage(info.uid)) { 3135ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.d(TAG, "encountered existing type with a new uid but from" 3145ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana + " the system: " + info); 3155ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } else { 3165ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.d(TAG, "encountered existing type with a new uid but existing was" 3175ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana + " removed: " + info); 3185ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3195ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3205ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana changed = true; 3215ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mServices.put(info.type, info); 3225ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServices.put(info.type, info.uid); 3235ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana notifyListener(info.type, false /* removed */); 3245ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } else { 3255ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana // ignore 3265ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (Log.isLoggable(TAG, Log.VERBOSE)) { 3275ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.d(TAG, "encountered existing type with a new uid, ignoring: " + info); 3285ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3295ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3305ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3315ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 3325ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana ArrayList<V> toBeRemoved = Lists.newArrayList(); 3335ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (V v1 : mPersistentServices.keySet()) { 3345ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (!containsType(serviceInfos, v1)) { 3355ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana toBeRemoved.add(v1); 3365ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3375ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3385ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (V v1 : toBeRemoved) { 3395ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServices.remove(v1); 3405ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana changed = true; 3415ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana notifyListener(v1, true /* removed */); 3425ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3435ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (changed) { 3445ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (Log.isLoggable(TAG, Log.VERBOSE)) { 3455ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.d(TAG, "writing updated list of persistent services"); 3465ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3475ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana writePersistentServicesLocked(); 3485ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } else { 3495ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (Log.isLoggable(TAG, Log.VERBOSE)) { 3505ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.d(TAG, "persistent services did not change, so not writing anything"); 3515ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3525ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3535ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServicesFileDidNotExist = false; 3545ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3555ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3565ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 3575ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private boolean containsType(ArrayList<ServiceInfo<V>> serviceInfos, V type) { 3585ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (int i = 0, N = serviceInfos.size(); i < N; i++) { 3595ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (serviceInfos.get(i).type.equals(type)) { 3605ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return true; 3615ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3625ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3635ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 3645ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return false; 3655ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3665ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 3675ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private boolean containsTypeAndUid(ArrayList<ServiceInfo<V>> serviceInfos, V type, int uid) { 3685ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (int i = 0, N = serviceInfos.size(); i < N; i++) { 3695ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana final ServiceInfo<V> serviceInfo = serviceInfos.get(i); 3705ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (serviceInfo.type.equals(type) && serviceInfo.uid == uid) { 3715ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return true; 3725ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3735ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 3745ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 3755ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return false; 376718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 377718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 378718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private ServiceInfo<V> parseServiceInfo(ResolveInfo service) 379718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana throws XmlPullParserException, IOException { 380718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana android.content.pm.ServiceInfo si = service.serviceInfo; 381718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana ComponentName componentName = new ComponentName(si.packageName, si.name); 382718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 383718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana PackageManager pm = mContext.getPackageManager(); 384718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 385718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana XmlResourceParser parser = null; 386718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana try { 387718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana parser = si.loadXmlMetaData(pm, mMetaDataName); 388718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (parser == null) { 389718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana throw new XmlPullParserException("No " + mMetaDataName + " meta-data"); 390718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 391718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 392718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana AttributeSet attrs = Xml.asAttributeSet(parser); 393718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 394718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana int type; 395718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 396718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana && type != XmlPullParser.START_TAG) { 397718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 398718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 399718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana String nodeName = parser.getName(); 400718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (!mAttributesName.equals(nodeName)) { 401718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana throw new XmlPullParserException( 402718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana "Meta-data does not start with " + mAttributesName + " tag"); 403718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 404718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 4059788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana V v = parseServiceAttributes(si.packageName, attrs); 406718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (v == null) { 407718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana return null; 408718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 409d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana final android.content.pm.ServiceInfo serviceInfo = service.serviceInfo; 410d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana final ApplicationInfo applicationInfo = serviceInfo.applicationInfo; 411d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana final int uid = applicationInfo.uid; 412d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana return new ServiceInfo<V>(v, componentName, uid); 413718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } finally { 414718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (parser != null) parser.close(); 415718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 416718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 417718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 4185ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana /** 4195ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana * Read all sync status back in to the initial engine state. 4205ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana */ 4215ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private void readPersistentServicesLocked() { 4225ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServices = Maps.newHashMap(); 4235ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (mSerializerAndParser == null) { 4245ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return; 4255ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4265ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana FileInputStream fis = null; 4275ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana try { 4285ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServicesFileDidNotExist = !mPersistentServicesFile.getBaseFile().exists(); 4295ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (mPersistentServicesFileDidNotExist) { 4305ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return; 4315ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4325ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana fis = mPersistentServicesFile.openRead(); 4335ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana XmlPullParser parser = Xml.newPullParser(); 4345ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana parser.setInput(fis, null); 4355ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana int eventType = parser.getEventType(); 4365ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana while (eventType != XmlPullParser.START_TAG) { 4375ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana eventType = parser.next(); 4385ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4395ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana String tagName = parser.getName(); 4405ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if ("services".equals(tagName)) { 4415ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana eventType = parser.next(); 4425ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana do { 4435ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (eventType == XmlPullParser.START_TAG && parser.getDepth() == 2) { 4445ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana tagName = parser.getName(); 4455ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if ("service".equals(tagName)) { 4465ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana V service = mSerializerAndParser.createFromXml(parser); 4475ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (service == null) { 4485ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana break; 4495ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4505ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana String uidString = parser.getAttributeValue(null, "uid"); 4515ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana int uid = Integer.parseInt(uidString); 4525ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServices.put(service, uid); 4535ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4545ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4555ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana eventType = parser.next(); 4565ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } while (eventType != XmlPullParser.END_DOCUMENT); 4575ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4585ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } catch (Exception e) { 4595ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.w(TAG, "Error reading persistent services, starting from scratch", e); 4605ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } finally { 4615ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (fis != null) { 4625ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana try { 4635ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana fis.close(); 4645ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } catch (java.io.IOException e1) { 4655ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4665ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4675ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4685ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4695ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 4705ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana /** 4715ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana * Write all sync status to the sync status file. 4725ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana */ 4735ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana private void writePersistentServicesLocked() { 4745ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (mSerializerAndParser == null) { 4755ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana return; 4765ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4775ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana FileOutputStream fos = null; 4785ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana try { 4795ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana fos = mPersistentServicesFile.startWrite(); 4805ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana XmlSerializer out = new FastXmlSerializer(); 4815ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.setOutput(fos, "utf-8"); 4825ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.startDocument(null, true); 4835ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 4845ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.startTag(null, "services"); 4855ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana for (Map.Entry<V, Integer> service : mPersistentServices.entrySet()) { 4865ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.startTag(null, "service"); 4875ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.attribute(null, "uid", Integer.toString(service.getValue())); 4885ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mSerializerAndParser.writeAsXml(service.getKey(), out); 4895ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.endTag(null, "service"); 4905ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4915ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.endTag(null, "services"); 4925ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana out.endDocument(); 4935ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServicesFile.finishWrite(fos); 4945ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } catch (java.io.IOException e1) { 4955ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana Log.w(TAG, "Error writing accounts", e1); 4965ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana if (fos != null) { 4975ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana mPersistentServicesFile.failWrite(fos); 4985ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 4995ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 5005ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana } 5015ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana 5029788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana public abstract V parseServiceAttributes(String packageName, AttributeSet attrs); 503718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana} 504