RegisteredServicesCache.java revision d4a1d2e14297a3387fdb5761090961e714370492
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; 25718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.util.Log; 26718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.util.AttributeSet; 27718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport android.util.Xml; 28718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 29718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.util.Map; 30718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.util.Collection; 31718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.util.Collections; 32718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.util.List; 33718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.io.FileDescriptor; 34718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.io.PrintWriter; 35718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport java.io.IOException; 36718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 37718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport com.google.android.collect.Maps; 38718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport org.xmlpull.v1.XmlPullParserException; 39718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanaimport org.xmlpull.v1.XmlPullParser; 40718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 41718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana/** 42718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * A cache of registered services. This cache 43718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * is built by interrogating the {@link PackageManager} and is updated as packages are added, 44718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * removed and changed. The services are referred to by type V and 45718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * are made available via the {@link #getServiceInfo} method. 46718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * @hide 47718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 48718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintanapublic abstract class RegisteredServicesCache<V> { 49718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private static final String TAG = "PackageManager"; 50718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 51718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public final Context mContext; 52718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private final String mInterfaceName; 53718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private final String mMetaDataName; 54718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private final String mAttributesName; 55718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 56718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana // no need to be synchronized since the map is never changed once mService is written 57718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private volatile Map<V, ServiceInfo<V>> mServices; 58718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 59718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana // synchronized on "this" 60718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private BroadcastReceiver mReceiver = null; 61718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 62718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public RegisteredServicesCache(Context context, String interfaceName, String metaDataName, 63718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana String attributeName) { 64718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mContext = context; 65718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mInterfaceName = interfaceName; 66718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mMetaDataName = metaDataName; 67718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mAttributesName = attributeName; 68718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 69718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 70718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public void dump(FileDescriptor fd, PrintWriter fout, String[] args) { 71718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana getAllServices(); 72718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana Map<V, ServiceInfo<V>> services = mServices; 73718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana fout.println("RegisteredServicesCache: " + services.size() + " services"); 74718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana for (ServiceInfo info : services.values()) { 75718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana fout.println(" " + info); 76718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 77718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 78718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 79718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private boolean maybeRegisterForPackageChanges() { 80718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana synchronized (this) { 81718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (mReceiver == null) { 82718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana synchronized (this) { 83718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mReceiver = new BroadcastReceiver() { 84718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public void onReceive(Context context, Intent intent) { 85718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mServices = generateServicesMap(); 86718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 87718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana }; 88718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 89718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 90718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana IntentFilter intentFilter = new IntentFilter(); 91718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 92718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 93718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 94718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mContext.registerReceiver(mReceiver, intentFilter); 95718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana return true; 96718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 97718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana return false; 98718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 99718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 100718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 101718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private void maybeUnregisterForPackageChanges() { 102718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana synchronized (this) { 103718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (mReceiver != null) { 104718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mContext.unregisterReceiver(mReceiver); 105718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mReceiver = null; 106718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 107718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 108718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 109718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 110718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana /** 111718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * Value type that describes a Service. The information within can be used 112718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * to bind to the service. 113718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 114718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public static class ServiceInfo<V> { 115718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public final V type; 116718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public final ComponentName componentName; 117d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana public final int uid; 118718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 119d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana private ServiceInfo(V type, ComponentName componentName, int uid) { 120718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana this.type = type; 121718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana this.componentName = componentName; 122d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana this.uid = uid; 123718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 124718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 125718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public String toString() { 126718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana return "ServiceInfo: " + type + ", " + componentName; 127718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 128718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 129718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 130718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana /** 131718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * Accessor for the registered authenticators. 132718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * @param type the account type of the authenticator 133718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * @return the AuthenticatorInfo that matches the account type or null if none is present 134718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 1359788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana public ServiceInfo<V> getServiceInfo(V type) { 136718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (mServices == null) { 137718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana maybeRegisterForPackageChanges(); 138718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mServices = generateServicesMap(); 139718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 140718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana return mServices.get(type); 141718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 142718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 143718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana /** 144718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * @return a collection of {@link RegisteredServicesCache.ServiceInfo} objects for all 145718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * registered authenticators. 146718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 147718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public Collection<ServiceInfo<V>> getAllServices() { 148718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (mServices == null) { 149718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana maybeRegisterForPackageChanges(); 150718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana mServices = generateServicesMap(); 151718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 152718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana return Collections.unmodifiableCollection(mServices.values()); 153718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 154718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 155718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana /** 156718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana * Stops the monitoring of package additions, removals and changes. 157718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana */ 158718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana public void close() { 159718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana maybeUnregisterForPackageChanges(); 160718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 161718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 162718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana protected void finalize() throws Throwable { 163718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana synchronized (this) { 164718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (mReceiver != null) { 165718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana Log.e(TAG, "RegisteredServicesCache finalized without being closed"); 166718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 167718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 168718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana close(); 169718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana super.finalize(); 170718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 171718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 172718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private Map<V, ServiceInfo<V>> generateServicesMap() { 173718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana Map<V, ServiceInfo<V>> services = Maps.newHashMap(); 174718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana PackageManager pm = mContext.getPackageManager(); 175718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 176718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana List<ResolveInfo> resolveInfos = 177718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana pm.queryIntentServices(new Intent(mInterfaceName), PackageManager.GET_META_DATA); 178718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 179718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana for (ResolveInfo resolveInfo : resolveInfos) { 180718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana try { 181718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana ServiceInfo<V> info = parseServiceInfo(resolveInfo); 182718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (info != null) { 183718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana services.put(info.type, info); 184718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } else { 185718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana Log.w(TAG, "Unable to load input method " + resolveInfo.toString()); 186718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 187718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } catch (XmlPullParserException e) { 188718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana Log.w(TAG, "Unable to load input method " + resolveInfo.toString(), e); 189718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } catch (IOException e) { 190718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana Log.w(TAG, "Unable to load input method " + resolveInfo.toString(), e); 191718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 192718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 193718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 194718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana return services; 195718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 196718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 197718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana private ServiceInfo<V> parseServiceInfo(ResolveInfo service) 198718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana throws XmlPullParserException, IOException { 199718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana android.content.pm.ServiceInfo si = service.serviceInfo; 200718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana ComponentName componentName = new ComponentName(si.packageName, si.name); 201718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 202718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana PackageManager pm = mContext.getPackageManager(); 203718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 204718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana XmlResourceParser parser = null; 205718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana try { 206718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana parser = si.loadXmlMetaData(pm, mMetaDataName); 207718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (parser == null) { 208718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana throw new XmlPullParserException("No " + mMetaDataName + " meta-data"); 209718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 210718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 211718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana AttributeSet attrs = Xml.asAttributeSet(parser); 212718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 213718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana int type; 214718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 215718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana && type != XmlPullParser.START_TAG) { 216718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 217718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 218718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana String nodeName = parser.getName(); 219718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (!mAttributesName.equals(nodeName)) { 220718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana throw new XmlPullParserException( 221718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana "Meta-data does not start with " + mAttributesName + " tag"); 222718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 223718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 2249788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana V v = parseServiceAttributes(si.packageName, attrs); 225718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (v == null) { 226718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana return null; 227718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 228d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana final android.content.pm.ServiceInfo serviceInfo = service.serviceInfo; 229d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana final ApplicationInfo applicationInfo = serviceInfo.applicationInfo; 230d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana final int uid = applicationInfo.uid; 231d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana return new ServiceInfo<V>(v, componentName, uid); 232718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } finally { 233718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana if (parser != null) parser.close(); 234718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 235718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana } 236718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana 2379788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana public abstract V parseServiceAttributes(String packageName, AttributeSet attrs); 238718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana} 239