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