1c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton/*
2c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton * Copyright (C) 2011 The Android Open Source Project
3c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton *
4c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton * Licensed under the Apache License, Version 2.0 (the "License");
5c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton * you may not use this file except in compliance with the License.
6c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton * You may obtain a copy of the License at
7c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton *
8c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton *      http://www.apache.org/licenses/LICENSE-2.0
9c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton *
10c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton * Unless required by applicable law or agreed to in writing, software
11c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton * distributed under the License is distributed on an "AS IS" BASIS,
12c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton * See the License for the specific language governing permissions and
14c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton * limitations under the License.
15c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton */
16c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
17c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonpackage com.android.nfc;
18c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
19c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport java.io.File;
20c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport java.io.FileDescriptor;
21c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport java.io.FileNotFoundException;
22c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport java.io.FileReader;
23c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport java.io.IOException;
24c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport java.io.PrintWriter;
25c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport java.util.ArrayList;
26c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport java.util.HashMap;
27c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
28c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport org.xmlpull.v1.XmlPullParser;
29c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport org.xmlpull.v1.XmlPullParserException;
30c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport org.xmlpull.v1.XmlPullParserFactory;
31c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
32c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport android.content.Context;
33c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport android.content.pm.ApplicationInfo;
34c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport android.content.pm.PackageInfo;
35c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport android.content.pm.PackageManager;
36c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport android.content.pm.Signature;
37c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport android.content.pm.PackageManager.NameNotFoundException;
38c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport android.os.Environment;
39c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport android.util.Log;
40c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
41c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonpublic class NfceeAccessControl {
42c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    static final String TAG = "NfceeAccess";
43c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    static final boolean DBG = true;
44c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
45c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    public static final String NFCEE_ACCESS_PATH = "/etc/nfcee_access.xml";
46c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
47c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    /**
48c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     * Map of signatures to valid packages names, as read from nfcee_access.xml.
49c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     * An empty list of package names indicates that any package
50c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     * with this signature is allowed.
51c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     */
52c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    final HashMap<Signature, String[]> mNfceeAccess;  // contents final after onCreate()
53c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
54c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    /**
55c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     * Map from UID to NFCEE access, used as a cache.
56c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     * Note: if a UID contains multiple packages they must all be
57c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     * signed with the same certificate so in effect UID == certificate
58c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     * used to sign the package.
59c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     */
60c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    final HashMap<Integer, Boolean> mUidCache;  // contents guarded by this
61c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
62c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    final Context mContext;
63c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    final boolean mDebugPrintSignature;
64c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
65c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    NfceeAccessControl(Context context) {
66c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        mContext = context;
67c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        mNfceeAccess = new HashMap<Signature, String[]>();
68c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        mUidCache = new HashMap<Integer, Boolean>();
69c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        mDebugPrintSignature = parseNfceeAccess();
70c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    }
71c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
72c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    /**
73c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     * Check if the {uid, pkg} combination may use NFCEE.
74c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     * Also verify with package manager that this {uid, pkg} combination
75c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     * is valid if it is not cached.
76c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     */
77c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    public boolean check(int uid, String pkg) {
78c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        synchronized (this) {
79c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            Boolean cached = mUidCache.get(uid);
80c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            if (cached != null) {
81c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                return cached;
82c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            }
83c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
84c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            boolean access = false;
85c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
86c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            // Ensure the claimed package is present in the calling UID
87c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            PackageManager pm = mContext.getPackageManager();
88c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            String[] pkgs = pm.getPackagesForUid(uid);
89c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            for (String uidPkg : pkgs) {
90c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                if (uidPkg.equals(pkg)) {
91c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    // Ensure the package has access permissions
92c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    if (checkPackageNfceeAccess(pkg)) {
93c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        access = true;
94c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    }
95c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    break;
96c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                }
97c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            }
98c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
99c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            mUidCache.put(uid, access);
100c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            return access;
101c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        }
102c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    }
103c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
104c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    /**
105c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     * Check if the given ApplicationInfo may use the NFCEE.
106c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     * Assumes ApplicationInfo came from package manager,
107c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     * so no need to confirm {uid, pkg} is valid.
108c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     */
109c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    public boolean check(ApplicationInfo info) {
110c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        synchronized (this) {
111c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            Boolean access = mUidCache.get(info.uid);
112c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            if (access == null) {
113c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                access = checkPackageNfceeAccess(info.packageName);
114c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                mUidCache.put(info.uid, access);
115c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            }
116c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            return access;
117c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        }
118c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    }
119c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
120c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    public void invalidateCache() {
121c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        synchronized (this) {
122c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            mUidCache.clear();
123c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        }
124c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    }
125c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
126c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    /**
127c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     * Check with package manager if the pkg may use NFCEE.
128c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     * Does not use cache.
129c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     */
130c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    boolean checkPackageNfceeAccess(String pkg) {
131c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        PackageManager pm = mContext.getPackageManager();
132c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        try {
133c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
134c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            if (info.signatures == null) {
135c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                return false;
136c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            }
137c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
138c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            for (Signature s : info.signatures){
139c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                if (s == null) {
140c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    continue;
141c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                }
142c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                String[] packages = mNfceeAccess.get(s);
143c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                if (packages == null) {
144c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    continue;
145c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                }
146c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                if (packages.length == 0) {
147c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    // wildcard access
148c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    if (DBG) Log.d(TAG, "Granted NFCEE access to " + pkg + " (wildcard)");
149c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    return true;
150c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                }
151c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                for (String p : packages) {
152c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    if (pkg.equals(p)) {
153c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        // explicit package access
154c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        if (DBG) Log.d(TAG, "Granted access to " + pkg + " (explicit)");
155c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        return true;
156c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    }
157c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                }
158c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            }
159c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
160c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            if (mDebugPrintSignature) {
161c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                Log.w(TAG, "denied NFCEE access for " + pkg + " with signature:");
162c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                for (Signature s : info.signatures) {
163c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    if (s != null) {
164c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        Log.w(TAG, s.toCharsString());
165c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    }
166c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                }
167c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            }
168c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        } catch (NameNotFoundException e) {
169c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            // ignore
170c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        }
171c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        return false;
172c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    }
173c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
174c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    /**
175c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     * Parse nfcee_access.xml, populate mNfceeAccess
176c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     * Policy is to ignore unexpected XML elements and continue processing,
177c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     * except for obvious errors within a <signer> group since they might cause
178c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     * package names to by ignored and therefore wildcard access granted
179c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     * by mistake. Those errors invalidate the entire <signer> group.
180c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton     */
181c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    boolean parseNfceeAccess() {
182c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        File file = new File(Environment.getRootDirectory(), NFCEE_ACCESS_PATH);
183c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        FileReader reader = null;
184c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        boolean debug = false;
185c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        try {
186c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            reader = new FileReader(file);
187c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
188c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            XmlPullParser parser = factory.newPullParser();
189c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            parser.setInput(reader);
190c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
191c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            int event;
192c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            ArrayList<String> packages = new ArrayList<String>();
193c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            Signature signature = null;
194c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
195c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            while (true) {
196c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                event = parser.next();
197c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                String tag = parser.getName();
198c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                if (event == XmlPullParser.START_TAG && "signer".equals(tag)) {
199c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    signature = null;
200c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    packages.clear();
201c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    for (int i = 0; i < parser.getAttributeCount(); i++) {
202c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        if ("android:signature".equals(parser.getAttributeName(i))) {
203c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                            signature = new Signature(parser.getAttributeValue(i));
204c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                            break;
205c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        }
206c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    }
207c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    if (signature == null) {
208c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        Log.w(TAG, "signer tag is missing android:signature attribute, igorning");
209c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        continue;
210c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    }
211c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    if (mNfceeAccess.containsKey(signature)) {
212c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        Log.w(TAG, "duplicate signature, ignoring");
213c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        signature = null;
214c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        continue;
215c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    }
216c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                } else if (event == XmlPullParser.END_TAG && "signer".equals(tag)) {
217c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    if (signature == null) {
218c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        Log.w(TAG, "mis-matched signer tag");
219c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        continue;
220c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    }
221c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly                    mNfceeAccess.put(signature, packages.toArray(new String[0]));
222c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    packages.clear();
223c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                } else if (event == XmlPullParser.START_TAG && "package".equals(tag)) {
224c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    if (signature == null) {
225c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        Log.w(TAG, "ignoring unnested packge tag");
226c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        continue;
227c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    }
228c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    String name = null;
229c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    for (int i = 0; i < parser.getAttributeCount(); i++) {
230c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        if ("android:name".equals(parser.getAttributeName(i))) {
231c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                            name = parser.getAttributeValue(i);
232c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                            break;
233c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        }
234c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    }
235c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    if (name == null) {
236c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        Log.w(TAG, "package missing android:name, ignoring signer group");
237c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        signature = null;  // invalidate signer
238c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        continue;
239c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    }
240c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    // check for duplicate package names
241c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    if (packages.contains(name)) {
242c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        Log.w(TAG, "duplicate package name in signer group, ignoring");
243c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                        continue;
244c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    }
245c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    packages.add(name);
246c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                } else if (event == XmlPullParser.START_TAG && "debug".equals(tag)) {
247c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    debug = true;
248c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                } else if (event == XmlPullParser.END_DOCUMENT) {
249c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    break;
250c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                }
251c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            }
252c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        } catch (XmlPullParserException e) {
253c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            Log.w(TAG, "failed to load NFCEE access list", e);
254c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            mNfceeAccess.clear();  // invalidate entire access list
255c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        } catch (FileNotFoundException e) {
256c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            Log.w(TAG, "could not find " + NFCEE_ACCESS_PATH + ", no NFCEE access allowed");
257c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        } catch (IOException e) {
258c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            Log.e(TAG, "Failed to load NFCEE access list", e);
259c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            mNfceeAccess.clear();  // invalidate entire access list
260c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        } finally {
261c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            if (reader != null) {
262c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                try {
263c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    reader.close();
264c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                } catch (IOException e2)  { }
265c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            }
266c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        }
267c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        Log.i(TAG, "read " + mNfceeAccess.size() + " signature(s) for NFCEE access");
268c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        return debug;
269c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    }
270c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
271c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
272c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        pw.println("mNfceeAccess=");
273c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        for (Signature s : mNfceeAccess.keySet()) {
274c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            pw.printf("\t%s [", s.toCharsString());
275c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            String[] ps = mNfceeAccess.get(s);
276c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            for (String p : ps) {
277c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                pw.printf("%s, ", p);
278c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            }
279c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            pw.println("]");
280c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        }
281c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        synchronized (this) {
282c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            pw.println("mNfceeUidCache=");
283c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            for (Integer uid : mUidCache.keySet()) {
284c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                Boolean b = mUidCache.get(uid);
285c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                pw.printf("\t%d %s\n", uid, b);
286c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            }
287c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        }
288c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    }
289c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton}
290