blob: 6f9858ced34ca512e2488819fd8c66ea598f6332 [file] [log] [blame]
Martijn Coenena7397882013-07-30 20:07:47 -07001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.nfc.cardemulation;
18
Mathew Inwood1961e1e2018-07-31 16:04:15 +010019import android.annotation.UnsupportedAppUsage;
Martijn Coenena7397882013-07-30 20:07:47 -070020import android.content.ComponentName;
21import android.content.pm.PackageManager;
Ruchi Kandoi44bb5792018-10-19 13:08:34 -070022import android.content.pm.PackageManager.NameNotFoundException;
Martijn Coenena7397882013-07-30 20:07:47 -070023import android.content.pm.ResolveInfo;
24import android.content.pm.ServiceInfo;
Martijn Coenena7397882013-07-30 20:07:47 -070025import android.content.res.Resources;
Martijn Coenen58d20652013-09-05 21:05:53 -070026import android.content.res.Resources.NotFoundException;
Martijn Coenena7397882013-07-30 20:07:47 -070027import android.content.res.TypedArray;
28import android.content.res.XmlResourceParser;
29import android.graphics.drawable.Drawable;
30import android.os.Parcel;
31import android.os.Parcelable;
32import android.util.AttributeSet;
33import android.util.Log;
34import android.util.Xml;
35
36import org.xmlpull.v1.XmlPullParser;
37import org.xmlpull.v1.XmlPullParserException;
38
Martijn Coenenaa1492d2014-04-11 12:54:22 -070039import java.io.FileDescriptor;
Martijn Coenena7397882013-07-30 20:07:47 -070040import java.io.IOException;
Martijn Coenenaa1492d2014-04-11 12:54:22 -070041import java.io.PrintWriter;
Martijn Coenena7397882013-07-30 20:07:47 -070042import java.util.ArrayList;
43import java.util.HashMap;
Martijn Coenened3a29e2015-01-23 11:29:54 -080044import java.util.List;
Martijn Coenenaa1492d2014-04-11 12:54:22 -070045import java.util.Map;
Martijn Coenena7397882013-07-30 20:07:47 -070046
47/**
48 * @hide
49 */
50public final class ApduServiceInfo implements Parcelable {
51 static final String TAG = "ApduServiceInfo";
52
53 /**
54 * The service that implements this
55 */
Mathew Inwood1961e1e2018-07-31 16:04:15 +010056 @UnsupportedAppUsage
Martijn Coenena7397882013-07-30 20:07:47 -070057 final ResolveInfo mService;
58
59 /**
60 * Description of the service
61 */
62 final String mDescription;
63
64 /**
Martijn Coenen38d3bb72013-08-07 20:03:03 -070065 * Whether this service represents AIDs running on the host CPU
Martijn Coenena7397882013-07-30 20:07:47 -070066 */
67 final boolean mOnHost;
68
69 /**
Ruchi Kandoi44bb5792018-10-19 13:08:34 -070070 * Offhost reader name.
71 * eg: SIM, eSE etc
72 */
73 String mOffHostName;
74
75 /**
76 * Offhost reader name from manifest file.
77 * Used for unsetOffHostSecureElement()
78 */
79 final String mStaticOffHostName;
80
81 /**
Martijn Coenenaa1492d2014-04-11 12:54:22 -070082 * Mapping from category to static AID group
Martijn Coenena7397882013-07-30 20:07:47 -070083 */
Mathew Inwood1961e1e2018-07-31 16:04:15 +010084 @UnsupportedAppUsage
Martijn Coenenaa1492d2014-04-11 12:54:22 -070085 final HashMap<String, AidGroup> mStaticAidGroups;
Martijn Coenena7397882013-07-30 20:07:47 -070086
87 /**
Martijn Coenenaa1492d2014-04-11 12:54:22 -070088 * Mapping from category to dynamic AID group
Martijn Coenena7397882013-07-30 20:07:47 -070089 */
Mathew Inwood1961e1e2018-07-31 16:04:15 +010090 @UnsupportedAppUsage
Martijn Coenenaa1492d2014-04-11 12:54:22 -070091 final HashMap<String, AidGroup> mDynamicAidGroups;
Martijn Coenena7397882013-07-30 20:07:47 -070092
93 /**
Martijn Coenenc3f00442013-08-28 19:23:41 -070094 * Whether this service should only be started when the device is unlocked.
95 */
96 final boolean mRequiresDeviceUnlock;
97
98 /**
Martijn Coenen58d20652013-09-05 21:05:53 -070099 * The id of the service banner specified in XML.
100 */
101 final int mBannerResourceId;
102
103 /**
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700104 * The uid of the package the service belongs to
105 */
106 final int mUid;
Martijn Coenen8abf6802015-04-20 13:44:58 +0200107
108 /**
Martijn Coenen8abf6802015-04-20 13:44:58 +0200109 * Settings Activity for this service
110 */
111 final String mSettingsActivityName;
112
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700113 /**
Martijn Coenena7397882013-07-30 20:07:47 -0700114 * @hide
115 */
Mathew Inwood1961e1e2018-07-31 16:04:15 +0100116 @UnsupportedAppUsage
Ruchi Kandoi44bb5792018-10-19 13:08:34 -0700117 public ApduServiceInfo(ResolveInfo info, String description,
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700118 ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups,
Martijn Coenena2344ea2015-06-05 10:45:50 +0200119 boolean requiresUnlock, int bannerResource, int uid,
Ruchi Kandoi44bb5792018-10-19 13:08:34 -0700120 String settingsActivityName, String offHost, String staticOffHost) {
Martijn Coenena7397882013-07-30 20:07:47 -0700121 this.mService = info;
122 this.mDescription = description;
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700123 this.mStaticAidGroups = new HashMap<String, AidGroup>();
124 this.mDynamicAidGroups = new HashMap<String, AidGroup>();
Ruchi Kandoi44bb5792018-10-19 13:08:34 -0700125 this.mOffHostName = offHost;
126 this.mStaticOffHostName = staticOffHost;
127 this.mOnHost = (offHost == null);
Martijn Coenenc3f00442013-08-28 19:23:41 -0700128 this.mRequiresDeviceUnlock = requiresUnlock;
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700129 for (AidGroup aidGroup : staticAidGroups) {
130 this.mStaticAidGroups.put(aidGroup.category, aidGroup);
131 }
132 for (AidGroup aidGroup : dynamicAidGroups) {
133 this.mDynamicAidGroups.put(aidGroup.category, aidGroup);
Martijn Coenena7397882013-07-30 20:07:47 -0700134 }
Martijn Coenen58d20652013-09-05 21:05:53 -0700135 this.mBannerResourceId = bannerResource;
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700136 this.mUid = uid;
Martijn Coenen8abf6802015-04-20 13:44:58 +0200137 this.mSettingsActivityName = settingsActivityName;
Martijn Coenena7397882013-07-30 20:07:47 -0700138 }
139
Mathew Inwood1961e1e2018-07-31 16:04:15 +0100140 @UnsupportedAppUsage
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700141 public ApduServiceInfo(PackageManager pm, ResolveInfo info, boolean onHost) throws
142 XmlPullParserException, IOException {
Martijn Coenena7397882013-07-30 20:07:47 -0700143 ServiceInfo si = info.serviceInfo;
Martijn Coenena7397882013-07-30 20:07:47 -0700144 XmlResourceParser parser = null;
145 try {
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700146 if (onHost) {
147 parser = si.loadXmlMetaData(pm, HostApduService.SERVICE_META_DATA);
148 if (parser == null) {
Martijn Coenen51b63222013-09-04 14:49:46 -0700149 throw new XmlPullParserException("No " + HostApduService.SERVICE_META_DATA +
150 " meta-data");
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700151 }
152 } else {
153 parser = si.loadXmlMetaData(pm, OffHostApduService.SERVICE_META_DATA);
154 if (parser == null) {
155 throw new XmlPullParserException("No " + OffHostApduService.SERVICE_META_DATA +
156 " meta-data");
157 }
Martijn Coenena7397882013-07-30 20:07:47 -0700158 }
159
160 int eventType = parser.getEventType();
161 while (eventType != XmlPullParser.START_TAG && eventType != XmlPullParser.END_DOCUMENT) {
162 eventType = parser.next();
163 }
164
165 String tagName = parser.getName();
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700166 if (onHost && !"host-apdu-service".equals(tagName)) {
Martijn Coenena7397882013-07-30 20:07:47 -0700167 throw new XmlPullParserException(
168 "Meta-data does not start with <host-apdu-service> tag");
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700169 } else if (!onHost && !"offhost-apdu-service".equals(tagName)) {
170 throw new XmlPullParserException(
171 "Meta-data does not start with <offhost-apdu-service> tag");
Martijn Coenena7397882013-07-30 20:07:47 -0700172 }
173
174 Resources res = pm.getResourcesForApplication(si.applicationInfo);
175 AttributeSet attrs = Xml.asAttributeSet(parser);
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700176 if (onHost) {
177 TypedArray sa = res.obtainAttributes(attrs,
178 com.android.internal.R.styleable.HostApduService);
179 mService = info;
180 mDescription = sa.getString(
181 com.android.internal.R.styleable.HostApduService_description);
Martijn Coenenc3f00442013-08-28 19:23:41 -0700182 mRequiresDeviceUnlock = sa.getBoolean(
183 com.android.internal.R.styleable.HostApduService_requireDeviceUnlock,
184 false);
Martijn Coenen58d20652013-09-05 21:05:53 -0700185 mBannerResourceId = sa.getResourceId(
186 com.android.internal.R.styleable.HostApduService_apduServiceBanner, -1);
Martijn Coenen8abf6802015-04-20 13:44:58 +0200187 mSettingsActivityName = sa.getString(
188 com.android.internal.R.styleable.HostApduService_settingsActivity);
Ruchi Kandoi44bb5792018-10-19 13:08:34 -0700189 mOffHostName = null;
190 mStaticOffHostName = mOffHostName;
Martijn Coenen58d20652013-09-05 21:05:53 -0700191 sa.recycle();
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700192 } else {
193 TypedArray sa = res.obtainAttributes(attrs,
194 com.android.internal.R.styleable.OffHostApduService);
195 mService = info;
196 mDescription = sa.getString(
197 com.android.internal.R.styleable.OffHostApduService_description);
Martijn Coenenc3f00442013-08-28 19:23:41 -0700198 mRequiresDeviceUnlock = false;
Martijn Coenen58d20652013-09-05 21:05:53 -0700199 mBannerResourceId = sa.getResourceId(
Martijn Coeneneed43392013-09-26 11:20:37 -0700200 com.android.internal.R.styleable.OffHostApduService_apduServiceBanner, -1);
Martijn Coenen8abf6802015-04-20 13:44:58 +0200201 mSettingsActivityName = sa.getString(
202 com.android.internal.R.styleable.HostApduService_settingsActivity);
Ruchi Kandoi44bb5792018-10-19 13:08:34 -0700203 mOffHostName = sa.getString(
204 com.android.internal.R.styleable.OffHostApduService_secureElementName);
205 if (mOffHostName != null) {
206 if (mOffHostName.equals("eSE")) {
207 mOffHostName = "eSE1";
208 } else if (mOffHostName.equals("SIM")) {
209 mOffHostName = "SIM1";
210 }
211 }
212 mStaticOffHostName = mOffHostName;
Martijn Coenen58d20652013-09-05 21:05:53 -0700213 sa.recycle();
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700214 }
215
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700216 mStaticAidGroups = new HashMap<String, AidGroup>();
217 mDynamicAidGroups = new HashMap<String, AidGroup>();
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700218 mOnHost = onHost;
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700219
Martijn Coenena7397882013-07-30 20:07:47 -0700220 final int depth = parser.getDepth();
221 AidGroup currentGroup = null;
222
223 // Parsed values for the current AID group
224 while (((eventType = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
225 && eventType != XmlPullParser.END_DOCUMENT) {
226 tagName = parser.getName();
227 if (eventType == XmlPullParser.START_TAG && "aid-group".equals(tagName) &&
228 currentGroup == null) {
229 final TypedArray groupAttrs = res.obtainAttributes(attrs,
230 com.android.internal.R.styleable.AidGroup);
231 // Get category of AID group
Martijn Coenena7397882013-07-30 20:07:47 -0700232 String groupCategory = groupAttrs.getString(
233 com.android.internal.R.styleable.AidGroup_category);
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700234 String groupDescription = groupAttrs.getString(
235 com.android.internal.R.styleable.AidGroup_description);
Martijn Coenen52246082013-08-30 11:14:46 -0700236 if (!CardEmulation.CATEGORY_PAYMENT.equals(groupCategory)) {
237 groupCategory = CardEmulation.CATEGORY_OTHER;
Martijn Coenena7397882013-07-30 20:07:47 -0700238 }
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700239 currentGroup = mStaticAidGroups.get(groupCategory);
Martijn Coenena7397882013-07-30 20:07:47 -0700240 if (currentGroup != null) {
Martijn Coenen52246082013-08-30 11:14:46 -0700241 if (!CardEmulation.CATEGORY_OTHER.equals(groupCategory)) {
Martijn Coenena7397882013-07-30 20:07:47 -0700242 Log.e(TAG, "Not allowing multiple aid-groups in the " +
243 groupCategory + " category");
244 currentGroup = null;
245 }
246 } else {
247 currentGroup = new AidGroup(groupCategory, groupDescription);
248 }
Martijn Coenen58d20652013-09-05 21:05:53 -0700249 groupAttrs.recycle();
Martijn Coenena7397882013-07-30 20:07:47 -0700250 } else if (eventType == XmlPullParser.END_TAG && "aid-group".equals(tagName) &&
251 currentGroup != null) {
252 if (currentGroup.aids.size() > 0) {
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700253 if (!mStaticAidGroups.containsKey(currentGroup.category)) {
254 mStaticAidGroups.put(currentGroup.category, currentGroup);
Martijn Coenena7397882013-07-30 20:07:47 -0700255 }
256 } else {
257 Log.e(TAG, "Not adding <aid-group> with empty or invalid AIDs");
258 }
259 currentGroup = null;
260 } else if (eventType == XmlPullParser.START_TAG && "aid-filter".equals(tagName) &&
261 currentGroup != null) {
262 final TypedArray a = res.obtainAttributes(attrs,
263 com.android.internal.R.styleable.AidFilter);
Martijn Coenen62c196a2013-08-09 13:43:34 -0700264 String aid = a.getString(com.android.internal.R.styleable.AidFilter_name).
265 toUpperCase();
Martijn Coenenb5144112014-07-02 12:44:33 -0700266 if (CardEmulation.isValidAid(aid) && !currentGroup.aids.contains(aid)) {
Martijn Coenena7397882013-07-30 20:07:47 -0700267 currentGroup.aids.add(aid);
Martijn Coenena7397882013-07-30 20:07:47 -0700268 } else {
269 Log.e(TAG, "Ignoring invalid or duplicate aid: " + aid);
270 }
Martijn Coenen58d20652013-09-05 21:05:53 -0700271 a.recycle();
Martijn Coenen826a73b2014-08-05 07:51:58 -0700272 } else if (eventType == XmlPullParser.START_TAG &&
273 "aid-prefix-filter".equals(tagName) && currentGroup != null) {
274 final TypedArray a = res.obtainAttributes(attrs,
275 com.android.internal.R.styleable.AidFilter);
276 String aid = a.getString(com.android.internal.R.styleable.AidFilter_name).
277 toUpperCase();
278 // Add wildcard char to indicate prefix
Martijn Coenen0985fb62014-09-16 10:09:12 -0700279 aid = aid.concat("*");
Martijn Coenen826a73b2014-08-05 07:51:58 -0700280 if (CardEmulation.isValidAid(aid) && !currentGroup.aids.contains(aid)) {
281 currentGroup.aids.add(aid);
282 } else {
283 Log.e(TAG, "Ignoring invalid or duplicate aid: " + aid);
284 }
285 a.recycle();
Love Khannae910e8b2017-05-12 13:53:42 +0530286 } else if (eventType == XmlPullParser.START_TAG &&
287 tagName.equals("aid-suffix-filter") && currentGroup != null) {
288 final TypedArray a = res.obtainAttributes(attrs,
289 com.android.internal.R.styleable.AidFilter);
290 String aid = a.getString(com.android.internal.R.styleable.AidFilter_name).
291 toUpperCase();
292 // Add wildcard char to indicate suffix
293 aid = aid.concat("#");
294 if (CardEmulation.isValidAid(aid) && !currentGroup.aids.contains(aid)) {
295 currentGroup.aids.add(aid);
296 } else {
297 Log.e(TAG, "Ignoring invalid or duplicate aid: " + aid);
298 }
299 a.recycle();
Martijn Coenena7397882013-07-30 20:07:47 -0700300 }
301 }
302 } catch (NameNotFoundException e) {
303 throw new XmlPullParserException("Unable to create context for: " + si.packageName);
304 } finally {
305 if (parser != null) parser.close();
306 }
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700307 // Set uid
308 mUid = si.applicationInfo.uid;
Martijn Coenena7397882013-07-30 20:07:47 -0700309 }
310
311 public ComponentName getComponent() {
312 return new ComponentName(mService.serviceInfo.packageName,
313 mService.serviceInfo.name);
314 }
315
Ruchi Kandoi44bb5792018-10-19 13:08:34 -0700316 public String getOffHostSecureElement() {
317 return mOffHostName;
318 }
319
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700320 /**
321 * Returns a consolidated list of AIDs from the AID groups
322 * registered by this service. Note that if a service has both
323 * a static (manifest-based) AID group for a category and a dynamic
324 * AID group, only the dynamically registered AIDs will be returned
325 * for that category.
326 * @return List of AIDs registered by the service
327 */
Martijn Coenened3a29e2015-01-23 11:29:54 -0800328 public List<String> getAids() {
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700329 final ArrayList<String> aids = new ArrayList<String>();
330 for (AidGroup group : getAidGroups()) {
331 aids.addAll(group.aids);
332 }
333 return aids;
Martijn Coenena7397882013-07-30 20:07:47 -0700334 }
335
Martijn Coenened3a29e2015-01-23 11:29:54 -0800336 public List<String> getPrefixAids() {
337 final ArrayList<String> prefixAids = new ArrayList<String>();
338 for (AidGroup group : getAidGroups()) {
339 for (String aid : group.aids) {
340 if (aid.endsWith("*")) {
341 prefixAids.add(aid);
342 }
343 }
344 }
345 return prefixAids;
346 }
347
Love Khannae910e8b2017-05-12 13:53:42 +0530348 public List<String> getSubsetAids() {
349 final ArrayList<String> subsetAids = new ArrayList<String>();
350 for (AidGroup group : getAidGroups()) {
351 for (String aid : group.aids) {
352 if (aid.endsWith("#")) {
353 subsetAids.add(aid);
354 }
355 }
356 }
357 return subsetAids;
358 }
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700359 /**
360 * Returns the registered AID group for this category.
361 */
362 public AidGroup getDynamicAidGroupForCategory(String category) {
363 return mDynamicAidGroups.get(category);
364 }
365
366 public boolean removeDynamicAidGroupForCategory(String category) {
367 return (mDynamicAidGroups.remove(category) != null);
368 }
369
370 /**
371 * Returns a consolidated list of AID groups
372 * registered by this service. Note that if a service has both
373 * a static (manifest-based) AID group for a category and a dynamic
374 * AID group, only the dynamically registered AID group will be returned
375 * for that category.
376 * @return List of AIDs registered by the service
377 */
Martijn Coenena7397882013-07-30 20:07:47 -0700378 public ArrayList<AidGroup> getAidGroups() {
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700379 final ArrayList<AidGroup> groups = new ArrayList<AidGroup>();
380 for (Map.Entry<String, AidGroup> entry : mDynamicAidGroups.entrySet()) {
381 groups.add(entry.getValue());
382 }
383 for (Map.Entry<String, AidGroup> entry : mStaticAidGroups.entrySet()) {
384 if (!mDynamicAidGroups.containsKey(entry.getKey())) {
385 // Consolidate AID groups - don't return static ones
386 // if a dynamic group exists for the category.
387 groups.add(entry.getValue());
388 }
389 }
390 return groups;
Martijn Coenena7397882013-07-30 20:07:47 -0700391 }
392
Martijn Coenen2f6f3a012014-04-25 17:00:21 -0700393 /**
394 * Returns the category to which this service has attributed the AID that is passed in,
395 * or null if we don't know this AID.
396 */
397 public String getCategoryForAid(String aid) {
398 ArrayList<AidGroup> groups = getAidGroups();
399 for (AidGroup group : groups) {
Martijn Coenen5e991a12014-09-16 16:03:28 -0700400 if (group.aids.contains(aid.toUpperCase())) {
Martijn Coenen2f6f3a012014-04-25 17:00:21 -0700401 return group.category;
402 }
403 }
404 return null;
405 }
406
Martijn Coenena7397882013-07-30 20:07:47 -0700407 public boolean hasCategory(String category) {
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700408 return (mStaticAidGroups.containsKey(category) || mDynamicAidGroups.containsKey(category));
Martijn Coenena7397882013-07-30 20:07:47 -0700409 }
410
Mathew Inwood1961e1e2018-07-31 16:04:15 +0100411 @UnsupportedAppUsage
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700412 public boolean isOnHost() {
413 return mOnHost;
414 }
415
Mathew Inwood1961e1e2018-07-31 16:04:15 +0100416 @UnsupportedAppUsage
Martijn Coenenc3f00442013-08-28 19:23:41 -0700417 public boolean requiresUnlock() {
418 return mRequiresDeviceUnlock;
419 }
420
Mathew Inwood1961e1e2018-07-31 16:04:15 +0100421 @UnsupportedAppUsage
Martijn Coenenfca357872013-09-18 17:26:18 +0200422 public String getDescription() {
423 return mDescription;
424 }
425
Mathew Inwood1961e1e2018-07-31 16:04:15 +0100426 @UnsupportedAppUsage
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700427 public int getUid() {
428 return mUid;
429 }
430
431 public void setOrReplaceDynamicAidGroup(AidGroup aidGroup) {
432 mDynamicAidGroups.put(aidGroup.getCategory(), aidGroup);
433 }
434
Ruchi Kandoi44bb5792018-10-19 13:08:34 -0700435 @UnsupportedAppUsage
436 public void setOffHostSecureElement(String offHost) {
437 mOffHostName = offHost;
438 }
439
440 /**
441 * Resets the off host Secure Element to statically defined
442 * by the service in the manifest file.
443 */
444 @UnsupportedAppUsage
445 public void unsetOffHostSecureElement() {
446 mOffHostName = mStaticOffHostName;
447 }
448
Martijn Coenena7397882013-07-30 20:07:47 -0700449 public CharSequence loadLabel(PackageManager pm) {
450 return mService.loadLabel(pm);
451 }
452
Martijn Coenen8abf6802015-04-20 13:44:58 +0200453 public CharSequence loadAppLabel(PackageManager pm) {
454 try {
455 return pm.getApplicationLabel(pm.getApplicationInfo(
456 mService.resolvePackageName, PackageManager.GET_META_DATA));
457 } catch (PackageManager.NameNotFoundException e) {
458 return null;
459 }
460 }
461
Martijn Coenena7397882013-07-30 20:07:47 -0700462 public Drawable loadIcon(PackageManager pm) {
463 return mService.loadIcon(pm);
464 }
465
Mathew Inwood1961e1e2018-07-31 16:04:15 +0100466 @UnsupportedAppUsage
Martijn Coenen58d20652013-09-05 21:05:53 -0700467 public Drawable loadBanner(PackageManager pm) {
468 Resources res;
469 try {
470 res = pm.getResourcesForApplication(mService.serviceInfo.packageName);
471 Drawable banner = res.getDrawable(mBannerResourceId);
472 return banner;
473 } catch (NotFoundException e) {
474 Log.e(TAG, "Could not load banner.");
475 return null;
476 } catch (NameNotFoundException e) {
477 Log.e(TAG, "Could not load banner.");
478 return null;
479 }
480 }
Martijn Coenen8abf6802015-04-20 13:44:58 +0200481
Mathew Inwood1961e1e2018-07-31 16:04:15 +0100482 @UnsupportedAppUsage
Martijn Coenen8abf6802015-04-20 13:44:58 +0200483 public String getSettingsActivityName() { return mSettingsActivityName; }
Martijn Coenen58d20652013-09-05 21:05:53 -0700484
Martijn Coenena7397882013-07-30 20:07:47 -0700485 @Override
486 public String toString() {
487 StringBuilder out = new StringBuilder("ApduService: ");
488 out.append(getComponent());
489 out.append(", description: " + mDescription);
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700490 out.append(", Static AID Groups: ");
491 for (AidGroup aidGroup : mStaticAidGroups.values()) {
492 out.append(aidGroup.toString());
493 }
494 out.append(", Dynamic AID Groups: ");
495 for (AidGroup aidGroup : mDynamicAidGroups.values()) {
Martijn Coenena7397882013-07-30 20:07:47 -0700496 out.append(aidGroup.toString());
497 }
498 return out.toString();
499 }
500
501 @Override
502 public boolean equals(Object o) {
503 if (this == o) return true;
504 if (!(o instanceof ApduServiceInfo)) return false;
505 ApduServiceInfo thatService = (ApduServiceInfo) o;
506
507 return thatService.getComponent().equals(this.getComponent());
508 }
509
510 @Override
511 public int hashCode() {
512 return getComponent().hashCode();
513 }
514
515
516 @Override
517 public int describeContents() {
518 return 0;
519 }
520
521 @Override
522 public void writeToParcel(Parcel dest, int flags) {
523 mService.writeToParcel(dest, flags);
524 dest.writeString(mDescription);
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700525 dest.writeInt(mOnHost ? 1 : 0);
Ruchi Kandoi44bb5792018-10-19 13:08:34 -0700526 dest.writeString(mOffHostName);
527 dest.writeString(mStaticOffHostName);
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700528 dest.writeInt(mStaticAidGroups.size());
529 if (mStaticAidGroups.size() > 0) {
530 dest.writeTypedList(new ArrayList<AidGroup>(mStaticAidGroups.values()));
531 }
532 dest.writeInt(mDynamicAidGroups.size());
533 if (mDynamicAidGroups.size() > 0) {
534 dest.writeTypedList(new ArrayList<AidGroup>(mDynamicAidGroups.values()));
Martijn Coenena7397882013-07-30 20:07:47 -0700535 }
Martijn Coenenc3f00442013-08-28 19:23:41 -0700536 dest.writeInt(mRequiresDeviceUnlock ? 1 : 0);
Martijn Coenen58d20652013-09-05 21:05:53 -0700537 dest.writeInt(mBannerResourceId);
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700538 dest.writeInt(mUid);
Martijn Coenen8abf6802015-04-20 13:44:58 +0200539 dest.writeString(mSettingsActivityName);
Martijn Coenena7397882013-07-30 20:07:47 -0700540 };
541
Mathew Inwood1961e1e2018-07-31 16:04:15 +0100542 @UnsupportedAppUsage
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700543 public static final @android.annotation.NonNull Parcelable.Creator<ApduServiceInfo> CREATOR =
Martijn Coenena7397882013-07-30 20:07:47 -0700544 new Parcelable.Creator<ApduServiceInfo>() {
545 @Override
546 public ApduServiceInfo createFromParcel(Parcel source) {
547 ResolveInfo info = ResolveInfo.CREATOR.createFromParcel(source);
548 String description = source.readString();
Martijn Coenen5e991a12014-09-16 16:03:28 -0700549 boolean onHost = source.readInt() != 0;
Ruchi Kandoi44bb5792018-10-19 13:08:34 -0700550 String offHostName = source.readString();
551 String staticOffHostName = source.readString();
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700552 ArrayList<AidGroup> staticAidGroups = new ArrayList<AidGroup>();
553 int numStaticGroups = source.readInt();
554 if (numStaticGroups > 0) {
555 source.readTypedList(staticAidGroups, AidGroup.CREATOR);
556 }
557 ArrayList<AidGroup> dynamicAidGroups = new ArrayList<AidGroup>();
558 int numDynamicGroups = source.readInt();
559 if (numDynamicGroups > 0) {
560 source.readTypedList(dynamicAidGroups, AidGroup.CREATOR);
Martijn Coenena7397882013-07-30 20:07:47 -0700561 }
Martijn Coenen5e991a12014-09-16 16:03:28 -0700562 boolean requiresUnlock = source.readInt() != 0;
Martijn Coenen58d20652013-09-05 21:05:53 -0700563 int bannerResource = source.readInt();
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700564 int uid = source.readInt();
Martijn Coenen8abf6802015-04-20 13:44:58 +0200565 String settingsActivityName = source.readString();
Ruchi Kandoi44bb5792018-10-19 13:08:34 -0700566 return new ApduServiceInfo(info, description, staticAidGroups,
Martijn Coenena2344ea2015-06-05 10:45:50 +0200567 dynamicAidGroups, requiresUnlock, bannerResource, uid,
Ruchi Kandoi44bb5792018-10-19 13:08:34 -0700568 settingsActivityName, offHostName, staticOffHostName);
Martijn Coenena7397882013-07-30 20:07:47 -0700569 }
570
571 @Override
572 public ApduServiceInfo[] newArray(int size) {
573 return new ApduServiceInfo[size];
574 }
575 };
576
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700577 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
578 pw.println(" " + getComponent() +
579 " (Description: " + getDescription() + ")");
Ruchi Kandoi44bb5792018-10-19 13:08:34 -0700580 if (mOnHost) {
581 pw.println(" On Host Service");
582 } else {
583 pw.println(" Off-host Service");
584 pw.println(" " + "Current off-host SE" + mOffHostName
585 + " static off-host: " + mOffHostName);
586 }
587 pw.println(" Static off-host Secure Element:");
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700588 pw.println(" Static AID groups:");
589 for (AidGroup group : mStaticAidGroups.values()) {
590 pw.println(" Category: " + group.category);
591 for (String aid : group.aids) {
592 pw.println(" AID: " + aid);
Martijn Coenena7397882013-07-30 20:07:47 -0700593 }
594 }
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700595 pw.println(" Dynamic AID groups:");
596 for (AidGroup group : mDynamicAidGroups.values()) {
597 pw.println(" Category: " + group.category);
598 for (String aid : group.aids) {
599 pw.println(" AID: " + aid);
Martijn Coenena7397882013-07-30 20:07:47 -0700600 }
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700601 }
Martijn Coenen8abf6802015-04-20 13:44:58 +0200602 pw.println(" Settings Activity: " + mSettingsActivityName);
Martijn Coenena7397882013-07-30 20:07:47 -0700603 }
604}