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