blob: 7a873f8210fff8a98ebecc3e740511535da280b4 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 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.content.pm;
18
19import org.xmlpull.v1.XmlPullParser;
20import org.xmlpull.v1.XmlPullParserException;
21
22import android.content.ComponentName;
23import android.content.Intent;
24import android.content.IntentFilter;
25import android.content.res.AssetManager;
26import android.content.res.Configuration;
27import android.content.res.Resources;
28import android.content.res.TypedArray;
29import android.content.res.XmlResourceParser;
30import android.os.Bundle;
31import android.os.PatternMatcher;
32import android.util.AttributeSet;
33import android.util.Config;
34import android.util.DisplayMetrics;
35import android.util.Log;
36import android.util.TypedValue;
37import com.android.internal.util.XmlUtils;
38
39import java.io.File;
40import java.io.IOException;
41import java.io.InputStream;
42import java.lang.ref.WeakReference;
43import java.security.cert.Certificate;
44import java.security.cert.CertificateEncodingException;
45import java.util.ArrayList;
46import java.util.Enumeration;
47import java.util.Iterator;
Mitsuru Oshima8d112672009-04-27 12:01:23 -070048import java.util.List;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import java.util.jar.JarEntry;
50import java.util.jar.JarFile;
51
52/**
53 * Package archive parsing
54 *
55 * {@hide}
56 */
57public class PackageParser {
58
59 private String mArchiveSourcePath;
60 private String[] mSeparateProcesses;
61 private int mSdkVersion;
62
63 private int mParseError = PackageManager.INSTALL_SUCCEEDED;
64
65 private static final Object mSync = new Object();
66 private static WeakReference<byte[]> mReadBuffer;
67
68 /** If set to true, we will only allow package files that exactly match
69 * the DTD. Otherwise, we try to get as much from the package as we
70 * can without failing. This should normally be set to false, to
71 * support extensions to the DTD in future versions. */
72 private static final boolean RIGID_PARSER = false;
73
74 private static final String TAG = "PackageParser";
75
76 public PackageParser(String archiveSourcePath) {
77 mArchiveSourcePath = archiveSourcePath;
78 }
79
80 public void setSeparateProcesses(String[] procs) {
81 mSeparateProcesses = procs;
82 }
83
84 public void setSdkVersion(int sdkVersion) {
85 mSdkVersion = sdkVersion;
86 }
87
88 private static final boolean isPackageFilename(String name) {
89 return name.endsWith(".apk");
90 }
91
92 /**
93 * Generate and return the {@link PackageInfo} for a parsed package.
94 *
95 * @param p the parsed package.
96 * @param flags indicating which optional information is included.
97 */
98 public static PackageInfo generatePackageInfo(PackageParser.Package p,
99 int gids[], int flags) {
100
101 PackageInfo pi = new PackageInfo();
102 pi.packageName = p.packageName;
103 pi.versionCode = p.mVersionCode;
104 pi.versionName = p.mVersionName;
105 pi.sharedUserId = p.mSharedUserId;
106 pi.sharedUserLabel = p.mSharedUserLabel;
107 pi.applicationInfo = p.applicationInfo;
108 if ((flags&PackageManager.GET_GIDS) != 0) {
109 pi.gids = gids;
110 }
111 if ((flags&PackageManager.GET_CONFIGURATIONS) != 0) {
112 int N = p.configPreferences.size();
113 if (N > 0) {
114 pi.configPreferences = new ConfigurationInfo[N];
115 for (int i=0; i<N; i++) {
116 pi.configPreferences[i] = p.configPreferences.get(i);
117 }
118 }
119 }
120 if ((flags&PackageManager.GET_ACTIVITIES) != 0) {
121 int N = p.activities.size();
122 if (N > 0) {
123 pi.activities = new ActivityInfo[N];
124 for (int i=0; i<N; i++) {
125 final Activity activity = p.activities.get(i);
126 if (activity.info.enabled
127 || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
128 pi.activities[i] = generateActivityInfo(p.activities.get(i), flags);
129 }
130 }
131 }
132 }
133 if ((flags&PackageManager.GET_RECEIVERS) != 0) {
134 int N = p.receivers.size();
135 if (N > 0) {
136 pi.receivers = new ActivityInfo[N];
137 for (int i=0; i<N; i++) {
138 final Activity activity = p.receivers.get(i);
139 if (activity.info.enabled
140 || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
141 pi.receivers[i] = generateActivityInfo(p.receivers.get(i), flags);
142 }
143 }
144 }
145 }
146 if ((flags&PackageManager.GET_SERVICES) != 0) {
147 int N = p.services.size();
148 if (N > 0) {
149 pi.services = new ServiceInfo[N];
150 for (int i=0; i<N; i++) {
151 final Service service = p.services.get(i);
152 if (service.info.enabled
153 || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
154 pi.services[i] = generateServiceInfo(p.services.get(i), flags);
155 }
156 }
157 }
158 }
159 if ((flags&PackageManager.GET_PROVIDERS) != 0) {
160 int N = p.providers.size();
161 if (N > 0) {
162 pi.providers = new ProviderInfo[N];
163 for (int i=0; i<N; i++) {
164 final Provider provider = p.providers.get(i);
165 if (provider.info.enabled
166 || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
167 pi.providers[i] = generateProviderInfo(p.providers.get(i), flags);
168 }
169 }
170 }
171 }
172 if ((flags&PackageManager.GET_INSTRUMENTATION) != 0) {
173 int N = p.instrumentation.size();
174 if (N > 0) {
175 pi.instrumentation = new InstrumentationInfo[N];
176 for (int i=0; i<N; i++) {
177 pi.instrumentation[i] = generateInstrumentationInfo(
178 p.instrumentation.get(i), flags);
179 }
180 }
181 }
182 if ((flags&PackageManager.GET_PERMISSIONS) != 0) {
183 int N = p.permissions.size();
184 if (N > 0) {
185 pi.permissions = new PermissionInfo[N];
186 for (int i=0; i<N; i++) {
187 pi.permissions[i] = generatePermissionInfo(p.permissions.get(i), flags);
188 }
189 }
190 N = p.requestedPermissions.size();
191 if (N > 0) {
192 pi.requestedPermissions = new String[N];
193 for (int i=0; i<N; i++) {
194 pi.requestedPermissions[i] = p.requestedPermissions.get(i);
195 }
196 }
197 }
198 if ((flags&PackageManager.GET_SIGNATURES) != 0) {
199 int N = p.mSignatures.length;
200 if (N > 0) {
201 pi.signatures = new Signature[N];
202 System.arraycopy(p.mSignatures, 0, pi.signatures, 0, N);
203 }
204 }
205 return pi;
206 }
207
208 private Certificate[] loadCertificates(JarFile jarFile, JarEntry je,
209 byte[] readBuffer) {
210 try {
211 // We must read the stream for the JarEntry to retrieve
212 // its certificates.
213 InputStream is = jarFile.getInputStream(je);
214 while (is.read(readBuffer, 0, readBuffer.length) != -1) {
215 // not using
216 }
217 is.close();
218 return je != null ? je.getCertificates() : null;
219 } catch (IOException e) {
220 Log.w(TAG, "Exception reading " + je.getName() + " in "
221 + jarFile.getName(), e);
222 }
223 return null;
224 }
225
226 public final static int PARSE_IS_SYSTEM = 0x0001;
227 public final static int PARSE_CHATTY = 0x0002;
228 public final static int PARSE_MUST_BE_APK = 0x0004;
229 public final static int PARSE_IGNORE_PROCESSES = 0x0008;
230
231 public int getParseError() {
232 return mParseError;
233 }
234
235 public Package parsePackage(File sourceFile, String destFileName,
236 DisplayMetrics metrics, int flags) {
237 mParseError = PackageManager.INSTALL_SUCCEEDED;
238
239 mArchiveSourcePath = sourceFile.getPath();
240 if (!sourceFile.isFile()) {
241 Log.w(TAG, "Skipping dir: " + mArchiveSourcePath);
242 mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
243 return null;
244 }
245 if (!isPackageFilename(sourceFile.getName())
246 && (flags&PARSE_MUST_BE_APK) != 0) {
247 if ((flags&PARSE_IS_SYSTEM) == 0) {
248 // We expect to have non-.apk files in the system dir,
249 // so don't warn about them.
250 Log.w(TAG, "Skipping non-package file: " + mArchiveSourcePath);
251 }
252 mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
253 return null;
254 }
255
256 if ((flags&PARSE_CHATTY) != 0 && Config.LOGD) Log.d(
257 TAG, "Scanning package: " + mArchiveSourcePath);
258
259 XmlResourceParser parser = null;
260 AssetManager assmgr = null;
261 boolean assetError = true;
262 try {
263 assmgr = new AssetManager();
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700264 int cookie = assmgr.addAssetPath(mArchiveSourcePath);
265 if(cookie != 0) {
266 parser = assmgr.openXmlResourceParser(cookie, "AndroidManifest.xml");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267 assetError = false;
268 } else {
269 Log.w(TAG, "Failed adding asset path:"+mArchiveSourcePath);
270 }
271 } catch (Exception e) {
272 Log.w(TAG, "Unable to read AndroidManifest.xml of "
273 + mArchiveSourcePath, e);
274 }
275 if(assetError) {
276 if (assmgr != null) assmgr.close();
277 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
278 return null;
279 }
280 String[] errorText = new String[1];
281 Package pkg = null;
282 Exception errorException = null;
283 try {
284 // XXXX todo: need to figure out correct configuration.
285 Resources res = new Resources(assmgr, metrics, null);
286 pkg = parsePackage(res, parser, flags, errorText);
287 } catch (Exception e) {
288 errorException = e;
289 mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
290 }
291
292
293 if (pkg == null) {
294 if (errorException != null) {
295 Log.w(TAG, mArchiveSourcePath, errorException);
296 } else {
297 Log.w(TAG, mArchiveSourcePath + " (at "
298 + parser.getPositionDescription()
299 + "): " + errorText[0]);
300 }
301 parser.close();
302 assmgr.close();
303 if (mParseError == PackageManager.INSTALL_SUCCEEDED) {
304 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
305 }
306 return null;
307 }
308
309 parser.close();
310 assmgr.close();
311
312 pkg.applicationInfo.sourceDir = destFileName;
313 pkg.applicationInfo.publicSourceDir = destFileName;
314 pkg.mSignatures = null;
315
316 return pkg;
317 }
318
319 public boolean collectCertificates(Package pkg, int flags) {
320 pkg.mSignatures = null;
321
322 WeakReference<byte[]> readBufferRef;
323 byte[] readBuffer = null;
324 synchronized (mSync) {
325 readBufferRef = mReadBuffer;
326 if (readBufferRef != null) {
327 mReadBuffer = null;
328 readBuffer = readBufferRef.get();
329 }
330 if (readBuffer == null) {
331 readBuffer = new byte[8192];
332 readBufferRef = new WeakReference<byte[]>(readBuffer);
333 }
334 }
335
336 try {
337 JarFile jarFile = new JarFile(mArchiveSourcePath);
338
339 Certificate[] certs = null;
340
341 if ((flags&PARSE_IS_SYSTEM) != 0) {
342 // If this package comes from the system image, then we
343 // can trust it... we'll just use the AndroidManifest.xml
344 // to retrieve its signatures, not validating all of the
345 // files.
346 JarEntry jarEntry = jarFile.getJarEntry("AndroidManifest.xml");
347 certs = loadCertificates(jarFile, jarEntry, readBuffer);
348 if (certs == null) {
349 Log.e(TAG, "Package " + pkg.packageName
350 + " has no certificates at entry "
351 + jarEntry.getName() + "; ignoring!");
352 jarFile.close();
353 mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
354 return false;
355 }
356 if (false) {
357 Log.i(TAG, "File " + mArchiveSourcePath + ": entry=" + jarEntry
358 + " certs=" + (certs != null ? certs.length : 0));
359 if (certs != null) {
360 final int N = certs.length;
361 for (int i=0; i<N; i++) {
362 Log.i(TAG, " Public key: "
363 + certs[i].getPublicKey().getEncoded()
364 + " " + certs[i].getPublicKey());
365 }
366 }
367 }
368
369 } else {
370 Enumeration entries = jarFile.entries();
371 while (entries.hasMoreElements()) {
372 JarEntry je = (JarEntry)entries.nextElement();
373 if (je.isDirectory()) continue;
374 if (je.getName().startsWith("META-INF/")) continue;
375 Certificate[] localCerts = loadCertificates(jarFile, je,
376 readBuffer);
377 if (false) {
378 Log.i(TAG, "File " + mArchiveSourcePath + " entry " + je.getName()
379 + ": certs=" + certs + " ("
380 + (certs != null ? certs.length : 0) + ")");
381 }
382 if (localCerts == null) {
383 Log.e(TAG, "Package " + pkg.packageName
384 + " has no certificates at entry "
385 + je.getName() + "; ignoring!");
386 jarFile.close();
387 mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
388 return false;
389 } else if (certs == null) {
390 certs = localCerts;
391 } else {
392 // Ensure all certificates match.
393 for (int i=0; i<certs.length; i++) {
394 boolean found = false;
395 for (int j=0; j<localCerts.length; j++) {
396 if (certs[i] != null &&
397 certs[i].equals(localCerts[j])) {
398 found = true;
399 break;
400 }
401 }
402 if (!found || certs.length != localCerts.length) {
403 Log.e(TAG, "Package " + pkg.packageName
404 + " has mismatched certificates at entry "
405 + je.getName() + "; ignoring!");
406 jarFile.close();
407 mParseError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
408 return false;
409 }
410 }
411 }
412 }
413 }
414 jarFile.close();
415
416 synchronized (mSync) {
417 mReadBuffer = readBufferRef;
418 }
419
420 if (certs != null && certs.length > 0) {
421 final int N = certs.length;
422 pkg.mSignatures = new Signature[certs.length];
423 for (int i=0; i<N; i++) {
424 pkg.mSignatures[i] = new Signature(
425 certs[i].getEncoded());
426 }
427 } else {
428 Log.e(TAG, "Package " + pkg.packageName
429 + " has no certificates; ignoring!");
430 mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
431 return false;
432 }
433 } catch (CertificateEncodingException e) {
434 Log.w(TAG, "Exception reading " + mArchiveSourcePath, e);
435 mParseError = PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
436 return false;
437 } catch (IOException e) {
438 Log.w(TAG, "Exception reading " + mArchiveSourcePath, e);
439 mParseError = PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
440 return false;
441 } catch (RuntimeException e) {
442 Log.w(TAG, "Exception reading " + mArchiveSourcePath, e);
443 mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
444 return false;
445 }
446
447 return true;
448 }
449
450 public static String parsePackageName(String packageFilePath, int flags) {
451 XmlResourceParser parser = null;
452 AssetManager assmgr = null;
453 try {
454 assmgr = new AssetManager();
455 int cookie = assmgr.addAssetPath(packageFilePath);
456 parser = assmgr.openXmlResourceParser(cookie, "AndroidManifest.xml");
457 } catch (Exception e) {
458 if (assmgr != null) assmgr.close();
459 Log.w(TAG, "Unable to read AndroidManifest.xml of "
460 + packageFilePath, e);
461 return null;
462 }
463 AttributeSet attrs = parser;
464 String errors[] = new String[1];
465 String packageName = null;
466 try {
467 packageName = parsePackageName(parser, attrs, flags, errors);
468 } catch (IOException e) {
469 Log.w(TAG, packageFilePath, e);
470 } catch (XmlPullParserException e) {
471 Log.w(TAG, packageFilePath, e);
472 } finally {
473 if (parser != null) parser.close();
474 if (assmgr != null) assmgr.close();
475 }
476 if (packageName == null) {
477 Log.e(TAG, "parsePackageName error: " + errors[0]);
478 return null;
479 }
480 return packageName;
481 }
482
483 private static String validateName(String name, boolean requiresSeparator) {
484 final int N = name.length();
485 boolean hasSep = false;
486 boolean front = true;
487 for (int i=0; i<N; i++) {
488 final char c = name.charAt(i);
489 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
490 front = false;
491 continue;
492 }
493 if (!front) {
494 if ((c >= '0' && c <= '9') || c == '_') {
495 continue;
496 }
497 }
498 if (c == '.') {
499 hasSep = true;
500 front = true;
501 continue;
502 }
503 return "bad character '" + c + "'";
504 }
505 return hasSep || !requiresSeparator
506 ? null : "must have at least one '.' separator";
507 }
508
509 private static String parsePackageName(XmlPullParser parser,
510 AttributeSet attrs, int flags, String[] outError)
511 throws IOException, XmlPullParserException {
512
513 int type;
514 while ((type=parser.next()) != parser.START_TAG
515 && type != parser.END_DOCUMENT) {
516 ;
517 }
518
519 if (type != parser.START_TAG) {
520 outError[0] = "No start tag found";
521 return null;
522 }
523 if ((flags&PARSE_CHATTY) != 0 && Config.LOGV) Log.v(
524 TAG, "Root element name: '" + parser.getName() + "'");
525 if (!parser.getName().equals("manifest")) {
526 outError[0] = "No <manifest> tag";
527 return null;
528 }
529 String pkgName = attrs.getAttributeValue(null, "package");
530 if (pkgName == null || pkgName.length() == 0) {
531 outError[0] = "<manifest> does not specify package";
532 return null;
533 }
534 String nameError = validateName(pkgName, true);
535 if (nameError != null && !"android".equals(pkgName)) {
536 outError[0] = "<manifest> specifies bad package name \""
537 + pkgName + "\": " + nameError;
538 return null;
539 }
540
541 return pkgName.intern();
542 }
543
544 /**
545 * Temporary.
546 */
547 static public Signature stringToSignature(String str) {
548 final int N = str.length();
549 byte[] sig = new byte[N];
550 for (int i=0; i<N; i++) {
551 sig[i] = (byte)str.charAt(i);
552 }
553 return new Signature(sig);
554 }
555
556 private Package parsePackage(
557 Resources res, XmlResourceParser parser, int flags, String[] outError)
558 throws XmlPullParserException, IOException {
559 AttributeSet attrs = parser;
560
561 String pkgName = parsePackageName(parser, attrs, flags, outError);
562 if (pkgName == null) {
563 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
564 return null;
565 }
566 int type;
567
568 final Package pkg = new Package(pkgName);
569 pkg.mSystem = (flags&PARSE_IS_SYSTEM) != 0;
570 boolean foundApp = false;
571
572 TypedArray sa = res.obtainAttributes(attrs,
573 com.android.internal.R.styleable.AndroidManifest);
574 pkg.mVersionCode = sa.getInteger(
575 com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
576 pkg.mVersionName = sa.getNonResourceString(
577 com.android.internal.R.styleable.AndroidManifest_versionName);
578 if (pkg.mVersionName != null) {
579 pkg.mVersionName = pkg.mVersionName.intern();
580 }
581 String str = sa.getNonResourceString(
582 com.android.internal.R.styleable.AndroidManifest_sharedUserId);
583 if (str != null) {
584 String nameError = validateName(str, true);
585 if (nameError != null && !"android".equals(pkgName)) {
586 outError[0] = "<manifest> specifies bad sharedUserId name \""
587 + str + "\": " + nameError;
588 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
589 return null;
590 }
591 pkg.mSharedUserId = str.intern();
592 pkg.mSharedUserLabel = sa.getResourceId(
593 com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
594 }
595 sa.recycle();
596
597 final int innerDepth = parser.getDepth();
598
599 int outerDepth = parser.getDepth();
600 while ((type=parser.next()) != parser.END_DOCUMENT
601 && (type != parser.END_TAG || parser.getDepth() > outerDepth)) {
602 if (type == parser.END_TAG || type == parser.TEXT) {
603 continue;
604 }
605
606 String tagName = parser.getName();
607 if (tagName.equals("application")) {
608 if (foundApp) {
609 if (RIGID_PARSER) {
610 outError[0] = "<manifest> has more than one <application>";
611 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
612 return null;
613 } else {
614 Log.w(TAG, "<manifest> has more than one <application>");
615 XmlUtils.skipCurrentTag(parser);
616 continue;
617 }
618 }
619
620 foundApp = true;
621 if (!parseApplication(pkg, res, parser, attrs, flags, outError)) {
622 return null;
623 }
624 } else if (tagName.equals("permission-group")) {
625 if (parsePermissionGroup(pkg, res, parser, attrs, outError) == null) {
626 return null;
627 }
628 } else if (tagName.equals("permission")) {
629 if (parsePermission(pkg, res, parser, attrs, outError) == null) {
630 return null;
631 }
632 } else if (tagName.equals("permission-tree")) {
633 if (parsePermissionTree(pkg, res, parser, attrs, outError) == null) {
634 return null;
635 }
636 } else if (tagName.equals("uses-permission")) {
637 sa = res.obtainAttributes(attrs,
638 com.android.internal.R.styleable.AndroidManifestUsesPermission);
639
640 String name = sa.getNonResourceString(
641 com.android.internal.R.styleable.AndroidManifestUsesPermission_name);
642
643 sa.recycle();
644
645 if (name != null && !pkg.requestedPermissions.contains(name)) {
646 pkg.requestedPermissions.add(name);
647 }
648
649 XmlUtils.skipCurrentTag(parser);
650
651 } else if (tagName.equals("uses-configuration")) {
652 ConfigurationInfo cPref = new ConfigurationInfo();
653 sa = res.obtainAttributes(attrs,
654 com.android.internal.R.styleable.AndroidManifestUsesConfiguration);
655 cPref.reqTouchScreen = sa.getInt(
656 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen,
657 Configuration.TOUCHSCREEN_UNDEFINED);
658 cPref.reqKeyboardType = sa.getInt(
659 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType,
660 Configuration.KEYBOARD_UNDEFINED);
661 if (sa.getBoolean(
662 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard,
663 false)) {
664 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
665 }
666 cPref.reqNavigation = sa.getInt(
667 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqNavigation,
668 Configuration.NAVIGATION_UNDEFINED);
669 if (sa.getBoolean(
670 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav,
671 false)) {
672 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
673 }
674 sa.recycle();
675 pkg.configPreferences.add(cPref);
676
677 XmlUtils.skipCurrentTag(parser);
678
679 } else if (tagName.equals("uses-sdk")) {
680 if (mSdkVersion > 0) {
681 sa = res.obtainAttributes(attrs,
682 com.android.internal.R.styleable.AndroidManifestUsesSdk);
683
684 int vers = sa.getInt(
685 com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion, 0);
686
687 sa.recycle();
688
689 if (vers > mSdkVersion) {
690 outError[0] = "Requires newer sdk version #" + vers
691 + " (current version is #" + mSdkVersion + ")";
692 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
693 return null;
694 }
695 }
696
697 XmlUtils.skipCurrentTag(parser);
698
699 } else if (tagName.equals("instrumentation")) {
700 if (parseInstrumentation(pkg, res, parser, attrs, outError) == null) {
701 return null;
702 }
703 } else if (tagName.equals("eat-comment")) {
704 // Just skip this tag
705 XmlUtils.skipCurrentTag(parser);
706 continue;
707 } else if (RIGID_PARSER) {
708 outError[0] = "Bad element under <manifest>: "
709 + parser.getName();
710 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
711 return null;
712 } else {
713 Log.w(TAG, "Bad element under <manifest>: "
714 + parser.getName());
715 XmlUtils.skipCurrentTag(parser);
716 continue;
717 }
718 }
719
720 if (!foundApp && pkg.instrumentation.size() == 0) {
721 outError[0] = "<manifest> does not contain an <application> or <instrumentation>";
722 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
723 }
724
725 if (pkg.usesLibraries.size() > 0) {
726 pkg.usesLibraryFiles = new String[pkg.usesLibraries.size()];
727 pkg.usesLibraries.toArray(pkg.usesLibraryFiles);
728 }
729
Mitsuru Oshima8d112672009-04-27 12:01:23 -0700730 int size = pkg.supportsDensityList.size();
731 if (size > 0) {
732 int densities[] = pkg.supportsDensities = new int[size];
733 List<Integer> densityList = pkg.supportsDensityList;
734 for (int i = 0; i < size; i++) {
735 densities[i] = densityList.get(i);
736 }
737 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 return pkg;
739 }
740
741 private static String buildClassName(String pkg, CharSequence clsSeq,
742 String[] outError) {
743 if (clsSeq == null || clsSeq.length() <= 0) {
744 outError[0] = "Empty class name in package " + pkg;
745 return null;
746 }
747 String cls = clsSeq.toString();
748 char c = cls.charAt(0);
749 if (c == '.') {
750 return (pkg + cls).intern();
751 }
752 if (cls.indexOf('.') < 0) {
753 StringBuilder b = new StringBuilder(pkg);
754 b.append('.');
755 b.append(cls);
756 return b.toString().intern();
757 }
758 if (c >= 'a' && c <= 'z') {
759 return cls.intern();
760 }
761 outError[0] = "Bad class name " + cls + " in package " + pkg;
762 return null;
763 }
764
765 private static String buildCompoundName(String pkg,
766 CharSequence procSeq, String type, String[] outError) {
767 String proc = procSeq.toString();
768 char c = proc.charAt(0);
769 if (pkg != null && c == ':') {
770 if (proc.length() < 2) {
771 outError[0] = "Bad " + type + " name " + proc + " in package " + pkg
772 + ": must be at least two characters";
773 return null;
774 }
775 String subName = proc.substring(1);
776 String nameError = validateName(subName, false);
777 if (nameError != null) {
778 outError[0] = "Invalid " + type + " name " + proc + " in package "
779 + pkg + ": " + nameError;
780 return null;
781 }
782 return (pkg + proc).intern();
783 }
784 String nameError = validateName(proc, true);
785 if (nameError != null && !"system".equals(proc)) {
786 outError[0] = "Invalid " + type + " name " + proc + " in package "
787 + pkg + ": " + nameError;
788 return null;
789 }
790 return proc.intern();
791 }
792
793 private static String buildProcessName(String pkg, String defProc,
794 CharSequence procSeq, int flags, String[] separateProcesses,
795 String[] outError) {
796 if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) {
797 return defProc != null ? defProc : pkg;
798 }
799 if (separateProcesses != null) {
800 for (int i=separateProcesses.length-1; i>=0; i--) {
801 String sp = separateProcesses[i];
802 if (sp.equals(pkg) || sp.equals(defProc) || sp.equals(procSeq)) {
803 return pkg;
804 }
805 }
806 }
807 if (procSeq == null || procSeq.length() <= 0) {
808 return defProc;
809 }
810 return buildCompoundName(pkg, procSeq, "package", outError);
811 }
812
813 private static String buildTaskAffinityName(String pkg, String defProc,
814 CharSequence procSeq, String[] outError) {
815 if (procSeq == null) {
816 return defProc;
817 }
818 if (procSeq.length() <= 0) {
819 return null;
820 }
821 return buildCompoundName(pkg, procSeq, "taskAffinity", outError);
822 }
823
824 private PermissionGroup parsePermissionGroup(Package owner, Resources res,
825 XmlPullParser parser, AttributeSet attrs, String[] outError)
826 throws XmlPullParserException, IOException {
827 PermissionGroup perm = new PermissionGroup(owner);
828
829 TypedArray sa = res.obtainAttributes(attrs,
830 com.android.internal.R.styleable.AndroidManifestPermissionGroup);
831
832 if (!parsePackageItemInfo(owner, perm.info, outError,
833 "<permission-group>", sa,
834 com.android.internal.R.styleable.AndroidManifestPermissionGroup_name,
835 com.android.internal.R.styleable.AndroidManifestPermissionGroup_label,
836 com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon)) {
837 sa.recycle();
838 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
839 return null;
840 }
841
842 perm.info.descriptionRes = sa.getResourceId(
843 com.android.internal.R.styleable.AndroidManifestPermissionGroup_description,
844 0);
845
846 sa.recycle();
847
848 if (!parseAllMetaData(res, parser, attrs, "<permission-group>", perm,
849 outError)) {
850 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
851 return null;
852 }
853
854 owner.permissionGroups.add(perm);
855
856 return perm;
857 }
858
859 private Permission parsePermission(Package owner, Resources res,
860 XmlPullParser parser, AttributeSet attrs, String[] outError)
861 throws XmlPullParserException, IOException {
862 Permission perm = new Permission(owner);
863
864 TypedArray sa = res.obtainAttributes(attrs,
865 com.android.internal.R.styleable.AndroidManifestPermission);
866
867 if (!parsePackageItemInfo(owner, perm.info, outError,
868 "<permission>", sa,
869 com.android.internal.R.styleable.AndroidManifestPermission_name,
870 com.android.internal.R.styleable.AndroidManifestPermission_label,
871 com.android.internal.R.styleable.AndroidManifestPermission_icon)) {
872 sa.recycle();
873 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
874 return null;
875 }
876
877 perm.info.group = sa.getNonResourceString(
878 com.android.internal.R.styleable.AndroidManifestPermission_permissionGroup);
879 if (perm.info.group != null) {
880 perm.info.group = perm.info.group.intern();
881 }
882
883 perm.info.descriptionRes = sa.getResourceId(
884 com.android.internal.R.styleable.AndroidManifestPermission_description,
885 0);
886
887 perm.info.protectionLevel = sa.getInt(
888 com.android.internal.R.styleable.AndroidManifestPermission_protectionLevel,
889 PermissionInfo.PROTECTION_NORMAL);
890
891 sa.recycle();
892
893 if (perm.info.protectionLevel == -1) {
894 outError[0] = "<permission> does not specify protectionLevel";
895 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
896 return null;
897 }
898
899 if (!parseAllMetaData(res, parser, attrs, "<permission>", perm,
900 outError)) {
901 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
902 return null;
903 }
904
905 owner.permissions.add(perm);
906
907 return perm;
908 }
909
910 private Permission parsePermissionTree(Package owner, Resources res,
911 XmlPullParser parser, AttributeSet attrs, String[] outError)
912 throws XmlPullParserException, IOException {
913 Permission perm = new Permission(owner);
914
915 TypedArray sa = res.obtainAttributes(attrs,
916 com.android.internal.R.styleable.AndroidManifestPermissionTree);
917
918 if (!parsePackageItemInfo(owner, perm.info, outError,
919 "<permission-tree>", sa,
920 com.android.internal.R.styleable.AndroidManifestPermissionTree_name,
921 com.android.internal.R.styleable.AndroidManifestPermissionTree_label,
922 com.android.internal.R.styleable.AndroidManifestPermissionTree_icon)) {
923 sa.recycle();
924 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
925 return null;
926 }
927
928 sa.recycle();
929
930 int index = perm.info.name.indexOf('.');
931 if (index > 0) {
932 index = perm.info.name.indexOf('.', index+1);
933 }
934 if (index < 0) {
935 outError[0] = "<permission-tree> name has less than three segments: "
936 + perm.info.name;
937 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
938 return null;
939 }
940
941 perm.info.descriptionRes = 0;
942 perm.info.protectionLevel = PermissionInfo.PROTECTION_NORMAL;
943 perm.tree = true;
944
945 if (!parseAllMetaData(res, parser, attrs, "<permission-tree>", perm,
946 outError)) {
947 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
948 return null;
949 }
950
951 owner.permissions.add(perm);
952
953 return perm;
954 }
955
956 private Instrumentation parseInstrumentation(Package owner, Resources res,
957 XmlPullParser parser, AttributeSet attrs, String[] outError)
958 throws XmlPullParserException, IOException {
959 TypedArray sa = res.obtainAttributes(attrs,
960 com.android.internal.R.styleable.AndroidManifestInstrumentation);
961
962 Instrumentation a = new Instrumentation(owner);
963
964 if (!parsePackageItemInfo(owner, a.info, outError, "<instrumentation>", sa,
965 com.android.internal.R.styleable.AndroidManifestInstrumentation_name,
966 com.android.internal.R.styleable.AndroidManifestInstrumentation_label,
967 com.android.internal.R.styleable.AndroidManifestInstrumentation_icon)) {
968 sa.recycle();
969 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
970 return null;
971 }
972
973 a.component = new ComponentName(owner.applicationInfo.packageName,
974 a.info.name);
975
976 String str;
977 str = sa.getNonResourceString(
978 com.android.internal.R.styleable.AndroidManifestInstrumentation_targetPackage);
979 a.info.targetPackage = str != null ? str.intern() : null;
980
981 a.info.handleProfiling = sa.getBoolean(
982 com.android.internal.R.styleable.AndroidManifestInstrumentation_handleProfiling,
983 false);
984
985 a.info.functionalTest = sa.getBoolean(
986 com.android.internal.R.styleable.AndroidManifestInstrumentation_functionalTest,
987 false);
988
989 sa.recycle();
990
991 if (a.info.targetPackage == null) {
992 outError[0] = "<instrumentation> does not specify targetPackage";
993 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
994 return null;
995 }
996
997 if (!parseAllMetaData(res, parser, attrs, "<instrumentation>", a,
998 outError)) {
999 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1000 return null;
1001 }
1002
1003 owner.instrumentation.add(a);
1004
1005 return a;
1006 }
1007
1008 private boolean parseApplication(Package owner, Resources res,
1009 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
1010 throws XmlPullParserException, IOException {
1011 final ApplicationInfo ai = owner.applicationInfo;
1012 final String pkgName = owner.applicationInfo.packageName;
1013
1014 TypedArray sa = res.obtainAttributes(attrs,
1015 com.android.internal.R.styleable.AndroidManifestApplication);
1016
1017 String name = sa.getNonResourceString(
1018 com.android.internal.R.styleable.AndroidManifestApplication_name);
1019 if (name != null) {
1020 ai.className = buildClassName(pkgName, name, outError);
1021 if (ai.className == null) {
1022 sa.recycle();
1023 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1024 return false;
1025 }
1026 }
1027
1028 String manageSpaceActivity = sa.getNonResourceString(
1029 com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity);
1030 if (manageSpaceActivity != null) {
1031 ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity,
1032 outError);
1033 }
1034
1035 TypedValue v = sa.peekValue(
1036 com.android.internal.R.styleable.AndroidManifestApplication_label);
1037 if (v != null && (ai.labelRes=v.resourceId) == 0) {
1038 ai.nonLocalizedLabel = v.coerceToString();
1039 }
1040
1041 ai.icon = sa.getResourceId(
1042 com.android.internal.R.styleable.AndroidManifestApplication_icon, 0);
1043 ai.theme = sa.getResourceId(
1044 com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);
1045 ai.descriptionRes = sa.getResourceId(
1046 com.android.internal.R.styleable.AndroidManifestApplication_description, 0);
1047
1048 if ((flags&PARSE_IS_SYSTEM) != 0) {
1049 if (sa.getBoolean(
1050 com.android.internal.R.styleable.AndroidManifestApplication_persistent,
1051 false)) {
1052 ai.flags |= ApplicationInfo.FLAG_PERSISTENT;
1053 }
1054 }
1055
1056 if (sa.getBoolean(
1057 com.android.internal.R.styleable.AndroidManifestApplication_debuggable,
1058 false)) {
1059 ai.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
1060 }
1061
1062 if (sa.getBoolean(
1063 com.android.internal.R.styleable.AndroidManifestApplication_hasCode,
1064 true)) {
1065 ai.flags |= ApplicationInfo.FLAG_HAS_CODE;
1066 }
1067
1068 if (sa.getBoolean(
1069 com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting,
1070 false)) {
1071 ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING;
1072 }
1073
1074 if (sa.getBoolean(
1075 com.android.internal.R.styleable.AndroidManifestApplication_allowClearUserData,
1076 true)) {
1077 ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
1078 }
1079
1080 String str;
1081 str = sa.getNonResourceString(
1082 com.android.internal.R.styleable.AndroidManifestApplication_permission);
1083 ai.permission = (str != null && str.length() > 0) ? str.intern() : null;
1084
1085 str = sa.getNonResourceString(
1086 com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity);
1087 ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName,
1088 str, outError);
1089
1090 if (outError[0] == null) {
1091 ai.processName = buildProcessName(ai.packageName, null, sa.getNonResourceString(
1092 com.android.internal.R.styleable.AndroidManifestApplication_process),
1093 flags, mSeparateProcesses, outError);
1094
1095 ai.enabled = sa.getBoolean(com.android.internal.R.styleable.AndroidManifestApplication_enabled, true);
1096 }
1097
1098 sa.recycle();
1099
1100 if (outError[0] != null) {
1101 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1102 return false;
1103 }
1104
1105 final int innerDepth = parser.getDepth();
1106
1107 int type;
1108 while ((type=parser.next()) != parser.END_DOCUMENT
1109 && (type != parser.END_TAG || parser.getDepth() > innerDepth)) {
1110 if (type == parser.END_TAG || type == parser.TEXT) {
1111 continue;
1112 }
1113
1114 String tagName = parser.getName();
1115 if (tagName.equals("activity")) {
1116 Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false);
1117 if (a == null) {
1118 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1119 return false;
1120 }
1121
1122 owner.activities.add(a);
1123
1124 } else if (tagName.equals("receiver")) {
1125 Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true);
1126 if (a == null) {
1127 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1128 return false;
1129 }
1130
1131 owner.receivers.add(a);
1132
1133 } else if (tagName.equals("service")) {
1134 Service s = parseService(owner, res, parser, attrs, flags, outError);
1135 if (s == null) {
1136 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1137 return false;
1138 }
1139
1140 owner.services.add(s);
1141
1142 } else if (tagName.equals("provider")) {
1143 Provider p = parseProvider(owner, res, parser, attrs, flags, outError);
1144 if (p == null) {
1145 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1146 return false;
1147 }
1148
1149 owner.providers.add(p);
1150
1151 } else if (tagName.equals("activity-alias")) {
1152 Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError, false);
1153 if (a == null) {
1154 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1155 return false;
1156 }
1157
1158 owner.activities.add(a);
1159
1160 } else if (parser.getName().equals("meta-data")) {
1161 // note: application meta-data is stored off to the side, so it can
1162 // remain null in the primary copy (we like to avoid extra copies because
1163 // it can be large)
1164 if ((owner.mAppMetaData = parseMetaData(res, parser, attrs, owner.mAppMetaData,
1165 outError)) == null) {
1166 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1167 return false;
1168 }
1169
1170 } else if (tagName.equals("uses-library")) {
1171 sa = res.obtainAttributes(attrs,
1172 com.android.internal.R.styleable.AndroidManifestUsesLibrary);
1173
1174 String lname = sa.getNonResourceString(
1175 com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
1176
1177 sa.recycle();
1178
1179 if (lname != null && !owner.usesLibraries.contains(lname)) {
1180 owner.usesLibraries.add(lname);
1181 }
1182
1183 XmlUtils.skipCurrentTag(parser);
1184
Mitsuru Oshima8d112672009-04-27 12:01:23 -07001185 } else if (tagName.equals("supports-density")) {
1186 sa = res.obtainAttributes(attrs,
1187 com.android.internal.R.styleable.AndroidManifestSupportsDensity);
1188
1189 int density = sa.getInteger(
1190 com.android.internal.R.styleable.AndroidManifestSupportsDensity_density, -1);
1191
1192 sa.recycle();
1193
1194 if (density != -1 && !owner.supportsDensityList.contains(density)) {
1195 owner.supportsDensityList.add(density);
1196 }
1197
1198 XmlUtils.skipCurrentTag(parser);
1199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 } else {
1201 if (!RIGID_PARSER) {
1202 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
1203 Log.w(TAG, "Unknown element under <application>: " + tagName);
1204 XmlUtils.skipCurrentTag(parser);
1205 continue;
1206 } else {
1207 outError[0] = "Bad element under <application>: " + tagName;
1208 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1209 return false;
1210 }
1211 }
1212 }
1213
1214 return true;
1215 }
1216
1217 private boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
1218 String[] outError, String tag, TypedArray sa,
1219 int nameRes, int labelRes, int iconRes) {
1220 String name = sa.getNonResourceString(nameRes);
1221 if (name == null) {
1222 outError[0] = tag + " does not specify android:name";
1223 return false;
1224 }
1225
1226 outInfo.name
1227 = buildClassName(owner.applicationInfo.packageName, name, outError);
1228 if (outInfo.name == null) {
1229 return false;
1230 }
1231
1232 int iconVal = sa.getResourceId(iconRes, 0);
1233 if (iconVal != 0) {
1234 outInfo.icon = iconVal;
1235 outInfo.nonLocalizedLabel = null;
1236 }
1237
1238 TypedValue v = sa.peekValue(labelRes);
1239 if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
1240 outInfo.nonLocalizedLabel = v.coerceToString();
1241 }
1242
1243 outInfo.packageName = owner.packageName;
1244
1245 return true;
1246 }
1247
1248 private boolean parseComponentInfo(Package owner, int flags,
1249 ComponentInfo outInfo, String[] outError, String tag, TypedArray sa,
1250 int nameRes, int labelRes, int iconRes, int processRes,
1251 int enabledRes) {
1252 if (!parsePackageItemInfo(owner, outInfo, outError, tag, sa,
1253 nameRes, labelRes, iconRes)) {
1254 return false;
1255 }
1256
1257 if (processRes != 0) {
1258 outInfo.processName = buildProcessName(owner.applicationInfo.packageName,
1259 owner.applicationInfo.processName, sa.getNonResourceString(processRes),
1260 flags, mSeparateProcesses, outError);
1261 }
1262 outInfo.enabled = sa.getBoolean(enabledRes, true);
1263
1264 return outError[0] == null;
1265 }
1266
1267 private Activity parseActivity(Package owner, Resources res,
1268 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError,
1269 boolean receiver) throws XmlPullParserException, IOException {
1270 TypedArray sa = res.obtainAttributes(attrs,
1271 com.android.internal.R.styleable.AndroidManifestActivity);
1272
1273 Activity a = new Activity(owner);
1274
1275 if (!parseComponentInfo(owner, flags, a.info, outError,
1276 receiver ? "<receiver>" : "<activity>", sa,
1277 com.android.internal.R.styleable.AndroidManifestActivity_name,
1278 com.android.internal.R.styleable.AndroidManifestActivity_label,
1279 com.android.internal.R.styleable.AndroidManifestActivity_icon,
1280 com.android.internal.R.styleable.AndroidManifestActivity_process,
1281 com.android.internal.R.styleable.AndroidManifestActivity_enabled)) {
1282 sa.recycle();
1283 return null;
1284 }
1285
1286 final boolean setExported = sa.hasValue(
1287 com.android.internal.R.styleable.AndroidManifestActivity_exported);
1288 if (setExported) {
1289 a.info.exported = sa.getBoolean(
1290 com.android.internal.R.styleable.AndroidManifestActivity_exported, false);
1291 }
1292
1293 a.component = new ComponentName(owner.applicationInfo.packageName,
1294 a.info.name);
1295
1296 a.info.theme = sa.getResourceId(
1297 com.android.internal.R.styleable.AndroidManifestActivity_theme, 0);
1298
1299 String str;
1300 str = sa.getNonResourceString(
1301 com.android.internal.R.styleable.AndroidManifestActivity_permission);
1302 if (str == null) {
1303 a.info.permission = owner.applicationInfo.permission;
1304 } else {
1305 a.info.permission = str.length() > 0 ? str.toString().intern() : null;
1306 }
1307
1308 str = sa.getNonResourceString(
1309 com.android.internal.R.styleable.AndroidManifestActivity_taskAffinity);
1310 a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName,
1311 owner.applicationInfo.taskAffinity, str, outError);
1312
1313 a.info.flags = 0;
1314 if (sa.getBoolean(
1315 com.android.internal.R.styleable.AndroidManifestActivity_multiprocess,
1316 false)) {
1317 a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS;
1318 }
1319
1320 if (sa.getBoolean(
1321 com.android.internal.R.styleable.AndroidManifestActivity_finishOnTaskLaunch,
1322 false)) {
1323 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH;
1324 }
1325
1326 if (sa.getBoolean(
1327 com.android.internal.R.styleable.AndroidManifestActivity_clearTaskOnLaunch,
1328 false)) {
1329 a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH;
1330 }
1331
1332 if (sa.getBoolean(
1333 com.android.internal.R.styleable.AndroidManifestActivity_noHistory,
1334 false)) {
1335 a.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
1336 }
1337
1338 if (sa.getBoolean(
1339 com.android.internal.R.styleable.AndroidManifestActivity_alwaysRetainTaskState,
1340 false)) {
1341 a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
1342 }
1343
1344 if (sa.getBoolean(
1345 com.android.internal.R.styleable.AndroidManifestActivity_stateNotNeeded,
1346 false)) {
1347 a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED;
1348 }
1349
1350 if (sa.getBoolean(
1351 com.android.internal.R.styleable.AndroidManifestActivity_excludeFromRecents,
1352 false)) {
1353 a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
1354 }
1355
1356 if (sa.getBoolean(
1357 com.android.internal.R.styleable.AndroidManifestActivity_allowTaskReparenting,
1358 (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) {
1359 a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
1360 }
1361
1362 if (!receiver) {
1363 a.info.launchMode = sa.getInt(
1364 com.android.internal.R.styleable.AndroidManifestActivity_launchMode,
1365 ActivityInfo.LAUNCH_MULTIPLE);
1366 a.info.screenOrientation = sa.getInt(
1367 com.android.internal.R.styleable.AndroidManifestActivity_screenOrientation,
1368 ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
1369 a.info.configChanges = sa.getInt(
1370 com.android.internal.R.styleable.AndroidManifestActivity_configChanges,
1371 0);
1372 a.info.softInputMode = sa.getInt(
1373 com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode,
1374 0);
1375 } else {
1376 a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
1377 a.info.configChanges = 0;
1378 }
1379
1380 sa.recycle();
1381
1382 if (outError[0] != null) {
1383 return null;
1384 }
1385
1386 int outerDepth = parser.getDepth();
1387 int type;
1388 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
1389 && (type != XmlPullParser.END_TAG
1390 || parser.getDepth() > outerDepth)) {
1391 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1392 continue;
1393 }
1394
1395 if (parser.getName().equals("intent-filter")) {
1396 ActivityIntentInfo intent = new ActivityIntentInfo(a);
1397 if (!parseIntent(res, parser, attrs, flags, intent, outError, !receiver)) {
1398 return null;
1399 }
1400 if (intent.countActions() == 0) {
1401 Log.w(TAG, "Intent filter for activity " + intent
1402 + " defines no actions");
1403 } else {
1404 a.intents.add(intent);
1405 }
1406 } else if (parser.getName().equals("meta-data")) {
1407 if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,
1408 outError)) == null) {
1409 return null;
1410 }
1411 } else {
1412 if (!RIGID_PARSER) {
1413 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
1414 if (receiver) {
1415 Log.w(TAG, "Unknown element under <receiver>: " + parser.getName());
1416 } else {
1417 Log.w(TAG, "Unknown element under <activity>: " + parser.getName());
1418 }
1419 XmlUtils.skipCurrentTag(parser);
1420 continue;
1421 }
1422 if (receiver) {
1423 outError[0] = "Bad element under <receiver>: " + parser.getName();
1424 } else {
1425 outError[0] = "Bad element under <activity>: " + parser.getName();
1426 }
1427 return null;
1428 }
1429 }
1430
1431 if (!setExported) {
1432 a.info.exported = a.intents.size() > 0;
1433 }
1434
1435 return a;
1436 }
1437
1438 private Activity parseActivityAlias(Package owner, Resources res,
1439 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError,
1440 boolean receiver) throws XmlPullParserException, IOException {
1441 TypedArray sa = res.obtainAttributes(attrs,
1442 com.android.internal.R.styleable.AndroidManifestActivityAlias);
1443
1444 String targetActivity = sa.getNonResourceString(
1445 com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity);
1446 if (targetActivity == null) {
1447 outError[0] = "<activity-alias> does not specify android:targetActivity";
1448 sa.recycle();
1449 return null;
1450 }
1451
1452 targetActivity = buildClassName(owner.applicationInfo.packageName,
1453 targetActivity, outError);
1454 if (targetActivity == null) {
1455 sa.recycle();
1456 return null;
1457 }
1458
1459 Activity a = new Activity(owner);
1460 Activity target = null;
1461
1462 final int NA = owner.activities.size();
1463 for (int i=0; i<NA; i++) {
1464 Activity t = owner.activities.get(i);
1465 if (targetActivity.equals(t.info.name)) {
1466 target = t;
1467 break;
1468 }
1469 }
1470
1471 if (target == null) {
1472 outError[0] = "<activity-alias> target activity " + targetActivity
1473 + " not found in manifest";
1474 sa.recycle();
1475 return null;
1476 }
1477
1478 a.info.targetActivity = targetActivity;
1479
1480 a.info.configChanges = target.info.configChanges;
1481 a.info.flags = target.info.flags;
1482 a.info.icon = target.info.icon;
1483 a.info.labelRes = target.info.labelRes;
1484 a.info.launchMode = target.info.launchMode;
1485 a.info.nonLocalizedLabel = target.info.nonLocalizedLabel;
1486 a.info.processName = target.info.processName;
1487 a.info.screenOrientation = target.info.screenOrientation;
1488 a.info.taskAffinity = target.info.taskAffinity;
1489 a.info.theme = target.info.theme;
1490
1491 if (!parseComponentInfo(owner, flags, a.info, outError,
1492 receiver ? "<receiver>" : "<activity>", sa,
1493 com.android.internal.R.styleable.AndroidManifestActivityAlias_name,
1494 com.android.internal.R.styleable.AndroidManifestActivityAlias_label,
1495 com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
1496 0,
1497 com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled)) {
1498 sa.recycle();
1499 return null;
1500 }
1501
1502 final boolean setExported = sa.hasValue(
1503 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported);
1504 if (setExported) {
1505 a.info.exported = sa.getBoolean(
1506 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported, false);
1507 }
1508
1509 a.component = new ComponentName(owner.applicationInfo.packageName,
1510 a.info.name);
1511
1512 String str;
1513 str = sa.getNonResourceString(
1514 com.android.internal.R.styleable.AndroidManifestActivityAlias_permission);
1515 if (str != null) {
1516 a.info.permission = str.length() > 0 ? str.toString().intern() : null;
1517 }
1518
1519 sa.recycle();
1520
1521 if (outError[0] != null) {
1522 return null;
1523 }
1524
1525 int outerDepth = parser.getDepth();
1526 int type;
1527 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
1528 && (type != XmlPullParser.END_TAG
1529 || parser.getDepth() > outerDepth)) {
1530 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1531 continue;
1532 }
1533
1534 if (parser.getName().equals("intent-filter")) {
1535 ActivityIntentInfo intent = new ActivityIntentInfo(a);
1536 if (!parseIntent(res, parser, attrs, flags, intent, outError, true)) {
1537 return null;
1538 }
1539 if (intent.countActions() == 0) {
1540 Log.w(TAG, "Intent filter for activity alias " + intent
1541 + " defines no actions");
1542 } else {
1543 a.intents.add(intent);
1544 }
1545 } else if (parser.getName().equals("meta-data")) {
1546 if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,
1547 outError)) == null) {
1548 return null;
1549 }
1550 } else {
1551 if (!RIGID_PARSER) {
1552 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
1553 Log.w(TAG, "Unknown element under <activity-alias>: " + parser.getName());
1554 XmlUtils.skipCurrentTag(parser);
1555 continue;
1556 }
1557 outError[0] = "Bad element under <activity-alias>: " + parser.getName();
1558 return null;
1559 }
1560 }
1561
1562 if (!setExported) {
1563 a.info.exported = a.intents.size() > 0;
1564 }
1565
1566 return a;
1567 }
1568
1569 private Provider parseProvider(Package owner, Resources res,
1570 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
1571 throws XmlPullParserException, IOException {
1572 TypedArray sa = res.obtainAttributes(attrs,
1573 com.android.internal.R.styleable.AndroidManifestProvider);
1574
1575 Provider p = new Provider(owner);
1576
1577 if (!parseComponentInfo(owner, flags, p.info, outError, "<provider>", sa,
1578 com.android.internal.R.styleable.AndroidManifestProvider_name,
1579 com.android.internal.R.styleable.AndroidManifestProvider_label,
1580 com.android.internal.R.styleable.AndroidManifestProvider_icon,
1581 com.android.internal.R.styleable.AndroidManifestProvider_process,
1582 com.android.internal.R.styleable.AndroidManifestProvider_enabled)) {
1583 sa.recycle();
1584 return null;
1585 }
1586
1587 p.info.exported = sa.getBoolean(
1588 com.android.internal.R.styleable.AndroidManifestProvider_exported, true);
1589
1590 p.component = new ComponentName(owner.applicationInfo.packageName,
1591 p.info.name);
1592
1593 String cpname = sa.getNonResourceString(
1594 com.android.internal.R.styleable.AndroidManifestProvider_authorities);
1595
1596 p.info.isSyncable = sa.getBoolean(
1597 com.android.internal.R.styleable.AndroidManifestProvider_syncable,
1598 false);
1599
1600 String permission = sa.getNonResourceString(
1601 com.android.internal.R.styleable.AndroidManifestProvider_permission);
1602 String str = sa.getNonResourceString(
1603 com.android.internal.R.styleable.AndroidManifestProvider_readPermission);
1604 if (str == null) {
1605 str = permission;
1606 }
1607 if (str == null) {
1608 p.info.readPermission = owner.applicationInfo.permission;
1609 } else {
1610 p.info.readPermission =
1611 str.length() > 0 ? str.toString().intern() : null;
1612 }
1613 str = sa.getNonResourceString(
1614 com.android.internal.R.styleable.AndroidManifestProvider_writePermission);
1615 if (str == null) {
1616 str = permission;
1617 }
1618 if (str == null) {
1619 p.info.writePermission = owner.applicationInfo.permission;
1620 } else {
1621 p.info.writePermission =
1622 str.length() > 0 ? str.toString().intern() : null;
1623 }
1624
1625 p.info.grantUriPermissions = sa.getBoolean(
1626 com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions,
1627 false);
1628
1629 p.info.multiprocess = sa.getBoolean(
1630 com.android.internal.R.styleable.AndroidManifestProvider_multiprocess,
1631 false);
1632
1633 p.info.initOrder = sa.getInt(
1634 com.android.internal.R.styleable.AndroidManifestProvider_initOrder,
1635 0);
1636
1637 sa.recycle();
1638
1639 if (cpname == null) {
1640 outError[0] = "<provider> does not incude authorities attribute";
1641 return null;
1642 }
1643 p.info.authority = cpname.intern();
1644
1645 if (!parseProviderTags(res, parser, attrs, p, outError)) {
1646 return null;
1647 }
1648
1649 return p;
1650 }
1651
1652 private boolean parseProviderTags(Resources res,
1653 XmlPullParser parser, AttributeSet attrs,
1654 Provider outInfo, String[] outError)
1655 throws XmlPullParserException, IOException {
1656 int outerDepth = parser.getDepth();
1657 int type;
1658 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
1659 && (type != XmlPullParser.END_TAG
1660 || parser.getDepth() > outerDepth)) {
1661 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1662 continue;
1663 }
1664
1665 if (parser.getName().equals("meta-data")) {
1666 if ((outInfo.metaData=parseMetaData(res, parser, attrs,
1667 outInfo.metaData, outError)) == null) {
1668 return false;
1669 }
1670 } else if (parser.getName().equals("grant-uri-permission")) {
1671 TypedArray sa = res.obtainAttributes(attrs,
1672 com.android.internal.R.styleable.AndroidManifestGrantUriPermission);
1673
1674 PatternMatcher pa = null;
1675
1676 String str = sa.getNonResourceString(
1677 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_path);
1678 if (str != null) {
1679 pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL);
1680 }
1681
1682 str = sa.getNonResourceString(
1683 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPrefix);
1684 if (str != null) {
1685 pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX);
1686 }
1687
1688 str = sa.getNonResourceString(
1689 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPattern);
1690 if (str != null) {
1691 pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
1692 }
1693
1694 sa.recycle();
1695
1696 if (pa != null) {
1697 if (outInfo.info.uriPermissionPatterns == null) {
1698 outInfo.info.uriPermissionPatterns = new PatternMatcher[1];
1699 outInfo.info.uriPermissionPatterns[0] = pa;
1700 } else {
1701 final int N = outInfo.info.uriPermissionPatterns.length;
1702 PatternMatcher[] newp = new PatternMatcher[N+1];
1703 System.arraycopy(outInfo.info.uriPermissionPatterns, 0, newp, 0, N);
1704 newp[N] = pa;
1705 outInfo.info.uriPermissionPatterns = newp;
1706 }
1707 outInfo.info.grantUriPermissions = true;
1708 }
1709 XmlUtils.skipCurrentTag(parser);
1710
1711 } else {
1712 if (!RIGID_PARSER) {
1713 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
1714 Log.w(TAG, "Unknown element under <provider>: "
1715 + parser.getName());
1716 XmlUtils.skipCurrentTag(parser);
1717 continue;
1718 }
1719 outError[0] = "Bad element under <provider>: "
1720 + parser.getName();
1721 return false;
1722 }
1723 }
1724 return true;
1725 }
1726
1727 private Service parseService(Package owner, Resources res,
1728 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
1729 throws XmlPullParserException, IOException {
1730 TypedArray sa = res.obtainAttributes(attrs,
1731 com.android.internal.R.styleable.AndroidManifestService);
1732
1733 Service s = new Service(owner);
1734
1735 if (!parseComponentInfo(owner, flags, s.info, outError, "<service>", sa,
1736 com.android.internal.R.styleable.AndroidManifestService_name,
1737 com.android.internal.R.styleable.AndroidManifestService_label,
1738 com.android.internal.R.styleable.AndroidManifestService_icon,
1739 com.android.internal.R.styleable.AndroidManifestService_process,
1740 com.android.internal.R.styleable.AndroidManifestService_enabled)) {
1741 sa.recycle();
1742 return null;
1743 }
1744
1745 final boolean setExported = sa.hasValue(
1746 com.android.internal.R.styleable.AndroidManifestService_exported);
1747 if (setExported) {
1748 s.info.exported = sa.getBoolean(
1749 com.android.internal.R.styleable.AndroidManifestService_exported, false);
1750 }
1751
1752 s.component = new ComponentName(owner.applicationInfo.packageName,
1753 s.info.name);
1754
1755 String str = sa.getNonResourceString(
1756 com.android.internal.R.styleable.AndroidManifestService_permission);
1757 if (str == null) {
1758 s.info.permission = owner.applicationInfo.permission;
1759 } else {
1760 s.info.permission = str.length() > 0 ? str.toString().intern() : null;
1761 }
1762
1763 sa.recycle();
1764
1765 int outerDepth = parser.getDepth();
1766 int type;
1767 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
1768 && (type != XmlPullParser.END_TAG
1769 || parser.getDepth() > outerDepth)) {
1770 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1771 continue;
1772 }
1773
1774 if (parser.getName().equals("intent-filter")) {
1775 ServiceIntentInfo intent = new ServiceIntentInfo(s);
1776 if (!parseIntent(res, parser, attrs, flags, intent, outError, false)) {
1777 return null;
1778 }
1779
1780 s.intents.add(intent);
1781 } else if (parser.getName().equals("meta-data")) {
1782 if ((s.metaData=parseMetaData(res, parser, attrs, s.metaData,
1783 outError)) == null) {
1784 return null;
1785 }
1786 } else {
1787 if (!RIGID_PARSER) {
1788 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
1789 Log.w(TAG, "Unknown element under <service>: "
1790 + parser.getName());
1791 XmlUtils.skipCurrentTag(parser);
1792 continue;
1793 }
1794 outError[0] = "Bad element under <service>: "
1795 + parser.getName();
1796 return null;
1797 }
1798 }
1799
1800 if (!setExported) {
1801 s.info.exported = s.intents.size() > 0;
1802 }
1803
1804 return s;
1805 }
1806
1807 private boolean parseAllMetaData(Resources res,
1808 XmlPullParser parser, AttributeSet attrs, String tag,
1809 Component outInfo, String[] outError)
1810 throws XmlPullParserException, IOException {
1811 int outerDepth = parser.getDepth();
1812 int type;
1813 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
1814 && (type != XmlPullParser.END_TAG
1815 || parser.getDepth() > outerDepth)) {
1816 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1817 continue;
1818 }
1819
1820 if (parser.getName().equals("meta-data")) {
1821 if ((outInfo.metaData=parseMetaData(res, parser, attrs,
1822 outInfo.metaData, outError)) == null) {
1823 return false;
1824 }
1825 } else {
1826 if (!RIGID_PARSER) {
1827 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
1828 Log.w(TAG, "Unknown element under " + tag + ": "
1829 + parser.getName());
1830 XmlUtils.skipCurrentTag(parser);
1831 continue;
1832 }
1833 outError[0] = "Bad element under " + tag + ": "
1834 + parser.getName();
1835 return false;
1836 }
1837 }
1838 return true;
1839 }
1840
1841 private Bundle parseMetaData(Resources res,
1842 XmlPullParser parser, AttributeSet attrs,
1843 Bundle data, String[] outError)
1844 throws XmlPullParserException, IOException {
1845
1846 TypedArray sa = res.obtainAttributes(attrs,
1847 com.android.internal.R.styleable.AndroidManifestMetaData);
1848
1849 if (data == null) {
1850 data = new Bundle();
1851 }
1852
1853 String name = sa.getNonResourceString(
1854 com.android.internal.R.styleable.AndroidManifestMetaData_name);
1855 if (name == null) {
1856 outError[0] = "<meta-data> requires an android:name attribute";
1857 sa.recycle();
1858 return null;
1859 }
1860
1861 boolean success = true;
1862
1863 TypedValue v = sa.peekValue(
1864 com.android.internal.R.styleable.AndroidManifestMetaData_resource);
1865 if (v != null && v.resourceId != 0) {
1866 //Log.i(TAG, "Meta data ref " + name + ": " + v);
1867 data.putInt(name, v.resourceId);
1868 } else {
1869 v = sa.peekValue(
1870 com.android.internal.R.styleable.AndroidManifestMetaData_value);
1871 //Log.i(TAG, "Meta data " + name + ": " + v);
1872 if (v != null) {
1873 if (v.type == TypedValue.TYPE_STRING) {
1874 CharSequence cs = v.coerceToString();
1875 data.putString(name, cs != null ? cs.toString() : null);
1876 } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
1877 data.putBoolean(name, v.data != 0);
1878 } else if (v.type >= TypedValue.TYPE_FIRST_INT
1879 && v.type <= TypedValue.TYPE_LAST_INT) {
1880 data.putInt(name, v.data);
1881 } else if (v.type == TypedValue.TYPE_FLOAT) {
1882 data.putFloat(name, v.getFloat());
1883 } else {
1884 if (!RIGID_PARSER) {
1885 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
1886 Log.w(TAG, "<meta-data> only supports string, integer, float, color, boolean, and resource reference types");
1887 } else {
1888 outError[0] = "<meta-data> only supports string, integer, float, color, boolean, and resource reference types";
1889 data = null;
1890 }
1891 }
1892 } else {
1893 outError[0] = "<meta-data> requires an android:value or android:resource attribute";
1894 data = null;
1895 }
1896 }
1897
1898 sa.recycle();
1899
1900 XmlUtils.skipCurrentTag(parser);
1901
1902 return data;
1903 }
1904
1905 private static final String ANDROID_RESOURCES
1906 = "http://schemas.android.com/apk/res/android";
1907
1908 private boolean parseIntent(Resources res,
1909 XmlPullParser parser, AttributeSet attrs, int flags,
1910 IntentInfo outInfo, String[] outError, boolean isActivity)
1911 throws XmlPullParserException, IOException {
1912
1913 TypedArray sa = res.obtainAttributes(attrs,
1914 com.android.internal.R.styleable.AndroidManifestIntentFilter);
1915
1916 int priority = sa.getInt(
1917 com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0);
1918 if (priority > 0 && isActivity && (flags&PARSE_IS_SYSTEM) == 0) {
1919 Log.w(TAG, "Activity with priority > 0, forcing to 0 at "
1920 + parser.getPositionDescription());
1921 priority = 0;
1922 }
1923 outInfo.setPriority(priority);
1924
1925 TypedValue v = sa.peekValue(
1926 com.android.internal.R.styleable.AndroidManifestIntentFilter_label);
1927 if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
1928 outInfo.nonLocalizedLabel = v.coerceToString();
1929 }
1930
1931 outInfo.icon = sa.getResourceId(
1932 com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0);
1933
1934 sa.recycle();
1935
1936 int outerDepth = parser.getDepth();
1937 int type;
1938 while ((type=parser.next()) != parser.END_DOCUMENT
1939 && (type != parser.END_TAG || parser.getDepth() > outerDepth)) {
1940 if (type == parser.END_TAG || type == parser.TEXT) {
1941 continue;
1942 }
1943
1944 String nodeName = parser.getName();
1945 if (nodeName.equals("action")) {
1946 String value = attrs.getAttributeValue(
1947 ANDROID_RESOURCES, "name");
1948 if (value == null || value == "") {
1949 outError[0] = "No value supplied for <android:name>";
1950 return false;
1951 }
1952 XmlUtils.skipCurrentTag(parser);
1953
1954 outInfo.addAction(value);
1955 } else if (nodeName.equals("category")) {
1956 String value = attrs.getAttributeValue(
1957 ANDROID_RESOURCES, "name");
1958 if (value == null || value == "") {
1959 outError[0] = "No value supplied for <android:name>";
1960 return false;
1961 }
1962 XmlUtils.skipCurrentTag(parser);
1963
1964 outInfo.addCategory(value);
1965
1966 } else if (nodeName.equals("data")) {
1967 sa = res.obtainAttributes(attrs,
1968 com.android.internal.R.styleable.AndroidManifestData);
1969
1970 String str = sa.getNonResourceString(
1971 com.android.internal.R.styleable.AndroidManifestData_mimeType);
1972 if (str != null) {
1973 try {
1974 outInfo.addDataType(str);
1975 } catch (IntentFilter.MalformedMimeTypeException e) {
1976 outError[0] = e.toString();
1977 sa.recycle();
1978 return false;
1979 }
1980 }
1981
1982 str = sa.getNonResourceString(
1983 com.android.internal.R.styleable.AndroidManifestData_scheme);
1984 if (str != null) {
1985 outInfo.addDataScheme(str);
1986 }
1987
1988 String host = sa.getNonResourceString(
1989 com.android.internal.R.styleable.AndroidManifestData_host);
1990 String port = sa.getNonResourceString(
1991 com.android.internal.R.styleable.AndroidManifestData_port);
1992 if (host != null) {
1993 outInfo.addDataAuthority(host, port);
1994 }
1995
1996 str = sa.getNonResourceString(
1997 com.android.internal.R.styleable.AndroidManifestData_path);
1998 if (str != null) {
1999 outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL);
2000 }
2001
2002 str = sa.getNonResourceString(
2003 com.android.internal.R.styleable.AndroidManifestData_pathPrefix);
2004 if (str != null) {
2005 outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX);
2006 }
2007
2008 str = sa.getNonResourceString(
2009 com.android.internal.R.styleable.AndroidManifestData_pathPattern);
2010 if (str != null) {
2011 outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
2012 }
2013
2014 sa.recycle();
2015 XmlUtils.skipCurrentTag(parser);
2016 } else if (!RIGID_PARSER) {
2017 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
2018 Log.w(TAG, "Unknown element under <intent-filter>: " + parser.getName());
2019 XmlUtils.skipCurrentTag(parser);
2020 } else {
2021 outError[0] = "Bad element under <intent-filter>: " + parser.getName();
2022 return false;
2023 }
2024 }
2025
2026 outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT);
2027 if (false) {
2028 String cats = "";
2029 Iterator<String> it = outInfo.categoriesIterator();
2030 while (it != null && it.hasNext()) {
2031 cats += " " + it.next();
2032 }
2033 System.out.println("Intent d=" +
2034 outInfo.hasDefault + ", cat=" + cats);
2035 }
2036
2037 return true;
2038 }
2039
2040 public final static class Package {
2041 public final String packageName;
2042
2043 // For now we only support one application per package.
2044 public final ApplicationInfo applicationInfo = new ApplicationInfo();
2045
2046 public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
2047 public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
2048 public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
2049 public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
2050 public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
2051 public final ArrayList<Service> services = new ArrayList<Service>(0);
2052 public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
2053
2054 public final ArrayList<String> requestedPermissions = new ArrayList<String>();
2055
2056 public final ArrayList<String> usesLibraries = new ArrayList<String>();
2057 public String[] usesLibraryFiles = null;
2058
2059 // We store the application meta-data independently to avoid multiple unwanted references
2060 public Bundle mAppMetaData = null;
2061
Mitsuru Oshima8d112672009-04-27 12:01:23 -07002062 public final ArrayList<Integer> supportsDensityList = new ArrayList<Integer>();
2063 public int[] supportsDensities = null;
2064
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002065 // If this is a 3rd party app, this is the path of the zip file.
2066 public String mPath;
2067
2068 // True if this package is part of the system image.
2069 public boolean mSystem;
2070
2071 // The version code declared for this package.
2072 public int mVersionCode;
2073
2074 // The version name declared for this package.
2075 public String mVersionName;
2076
2077 // The shared user id that this package wants to use.
2078 public String mSharedUserId;
2079
2080 // The shared user label that this package wants to use.
2081 public int mSharedUserLabel;
2082
2083 // Signatures that were read from the package.
2084 public Signature mSignatures[];
2085
2086 // For use by package manager service for quick lookup of
2087 // preferred up order.
2088 public int mPreferredOrder = 0;
2089
2090 // Additional data supplied by callers.
2091 public Object mExtras;
2092
2093 /*
2094 * Applications hardware preferences
2095 */
2096 public final ArrayList<ConfigurationInfo> configPreferences =
2097 new ArrayList<ConfigurationInfo>();
2098
2099 public Package(String _name) {
2100 packageName = _name;
2101 applicationInfo.packageName = _name;
2102 applicationInfo.uid = -1;
2103 }
2104
2105 public String toString() {
2106 return "Package{"
2107 + Integer.toHexString(System.identityHashCode(this))
2108 + " " + packageName + "}";
2109 }
2110 }
2111
2112 public static class Component<II extends IntentInfo> {
2113 public final Package owner;
2114 public final ArrayList<II> intents = new ArrayList<II>(0);
2115 public ComponentName component;
2116 public Bundle metaData;
2117
2118 public Component(Package _owner) {
2119 owner = _owner;
2120 }
2121
2122 public Component(Component<II> clone) {
2123 owner = clone.owner;
2124 metaData = clone.metaData;
2125 }
2126 }
2127
2128 public final static class Permission extends Component<IntentInfo> {
2129 public final PermissionInfo info;
2130 public boolean tree;
2131 public PermissionGroup group;
2132
2133 public Permission(Package _owner) {
2134 super(_owner);
2135 info = new PermissionInfo();
2136 }
2137
2138 public Permission(Package _owner, PermissionInfo _info) {
2139 super(_owner);
2140 info = _info;
2141 }
2142
2143 public String toString() {
2144 return "Permission{"
2145 + Integer.toHexString(System.identityHashCode(this))
2146 + " " + info.name + "}";
2147 }
2148 }
2149
2150 public final static class PermissionGroup extends Component<IntentInfo> {
2151 public final PermissionGroupInfo info;
2152
2153 public PermissionGroup(Package _owner) {
2154 super(_owner);
2155 info = new PermissionGroupInfo();
2156 }
2157
2158 public PermissionGroup(Package _owner, PermissionGroupInfo _info) {
2159 super(_owner);
2160 info = _info;
2161 }
2162
2163 public String toString() {
2164 return "PermissionGroup{"
2165 + Integer.toHexString(System.identityHashCode(this))
2166 + " " + info.name + "}";
2167 }
2168 }
2169
2170 private static boolean copyNeeded(int flags, Package p, Bundle metaData) {
2171 if ((flags & PackageManager.GET_META_DATA) != 0
2172 && (metaData != null || p.mAppMetaData != null)) {
2173 return true;
2174 }
2175 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0
2176 && p.usesLibraryFiles != null) {
2177 return true;
2178 }
Mitsuru Oshima8d112672009-04-27 12:01:23 -07002179 if ((flags & PackageManager.GET_SUPPORTS_DENSITIES) != 0
2180 && p.supportsDensities != null) {
2181 return true;
2182 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002183 return false;
2184 }
2185
2186 public static ApplicationInfo generateApplicationInfo(Package p, int flags) {
2187 if (p == null) return null;
2188 if (!copyNeeded(flags, p, null)) {
2189 return p.applicationInfo;
2190 }
2191
2192 // Make shallow copy so we can store the metadata/libraries safely
2193 ApplicationInfo ai = new ApplicationInfo(p.applicationInfo);
2194 if ((flags & PackageManager.GET_META_DATA) != 0) {
2195 ai.metaData = p.mAppMetaData;
2196 }
2197 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) {
2198 ai.sharedLibraryFiles = p.usesLibraryFiles;
2199 }
Mitsuru Oshima8d112672009-04-27 12:01:23 -07002200 if ((flags & PackageManager.GET_SUPPORTS_DENSITIES) != 0) {
2201 ai.supportsDensities = p.supportsDensities;
2202 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002203 return ai;
2204 }
2205
2206 public static final PermissionInfo generatePermissionInfo(
2207 Permission p, int flags) {
2208 if (p == null) return null;
2209 if ((flags&PackageManager.GET_META_DATA) == 0) {
2210 return p.info;
2211 }
2212 PermissionInfo pi = new PermissionInfo(p.info);
2213 pi.metaData = p.metaData;
2214 return pi;
2215 }
2216
2217 public static final PermissionGroupInfo generatePermissionGroupInfo(
2218 PermissionGroup pg, int flags) {
2219 if (pg == null) return null;
2220 if ((flags&PackageManager.GET_META_DATA) == 0) {
2221 return pg.info;
2222 }
2223 PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info);
2224 pgi.metaData = pg.metaData;
2225 return pgi;
2226 }
2227
2228 public final static class Activity extends Component<ActivityIntentInfo> {
2229 public final ActivityInfo info =
2230 new ActivityInfo();
2231
2232 public Activity(Package _owner) {
2233 super(_owner);
2234 info.applicationInfo = owner.applicationInfo;
2235 }
2236
2237 public String toString() {
2238 return "Activity{"
2239 + Integer.toHexString(System.identityHashCode(this))
2240 + " " + component.flattenToString() + "}";
2241 }
2242 }
2243
2244 public static final ActivityInfo generateActivityInfo(Activity a,
2245 int flags) {
2246 if (a == null) return null;
2247 if (!copyNeeded(flags, a.owner, a.metaData)) {
2248 return a.info;
2249 }
2250 // Make shallow copies so we can store the metadata safely
2251 ActivityInfo ai = new ActivityInfo(a.info);
2252 ai.metaData = a.metaData;
2253 ai.applicationInfo = generateApplicationInfo(a.owner, flags);
2254 return ai;
2255 }
2256
2257 public final static class Service extends Component<ServiceIntentInfo> {
2258 public final ServiceInfo info =
2259 new ServiceInfo();
2260
2261 public Service(Package _owner) {
2262 super(_owner);
2263 info.applicationInfo = owner.applicationInfo;
2264 }
2265
2266 public String toString() {
2267 return "Service{"
2268 + Integer.toHexString(System.identityHashCode(this))
2269 + " " + component.flattenToString() + "}";
2270 }
2271 }
2272
2273 public static final ServiceInfo generateServiceInfo(Service s, int flags) {
2274 if (s == null) return null;
2275 if (!copyNeeded(flags, s.owner, s.metaData)) {
2276 return s.info;
2277 }
2278 // Make shallow copies so we can store the metadata safely
2279 ServiceInfo si = new ServiceInfo(s.info);
2280 si.metaData = s.metaData;
2281 si.applicationInfo = generateApplicationInfo(s.owner, flags);
2282 return si;
2283 }
2284
2285 public final static class Provider extends Component {
2286 public final ProviderInfo info;
2287 public boolean syncable;
2288
2289 public Provider(Package _owner) {
2290 super(_owner);
2291 info = new ProviderInfo();
2292 info.applicationInfo = owner.applicationInfo;
2293 syncable = false;
2294 }
2295
2296 public Provider(Provider existingProvider) {
2297 super(existingProvider);
2298 this.info = existingProvider.info;
2299 this.syncable = existingProvider.syncable;
2300 }
2301
2302 public String toString() {
2303 return "Provider{"
2304 + Integer.toHexString(System.identityHashCode(this))
2305 + " " + info.name + "}";
2306 }
2307 }
2308
2309 public static final ProviderInfo generateProviderInfo(Provider p,
2310 int flags) {
2311 if (p == null) return null;
2312 if (!copyNeeded(flags, p.owner, p.metaData)
2313 && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0
2314 || p.info.uriPermissionPatterns == null)) {
2315 return p.info;
2316 }
2317 // Make shallow copies so we can store the metadata safely
2318 ProviderInfo pi = new ProviderInfo(p.info);
2319 pi.metaData = p.metaData;
2320 if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
2321 pi.uriPermissionPatterns = null;
2322 }
2323 pi.applicationInfo = generateApplicationInfo(p.owner, flags);
2324 return pi;
2325 }
2326
2327 public final static class Instrumentation extends Component {
2328 public final InstrumentationInfo info =
2329 new InstrumentationInfo();
2330
2331 public Instrumentation(Package _owner) {
2332 super(_owner);
2333 }
2334
2335 public String toString() {
2336 return "Instrumentation{"
2337 + Integer.toHexString(System.identityHashCode(this))
2338 + " " + component.flattenToString() + "}";
2339 }
2340 }
2341
2342 public static final InstrumentationInfo generateInstrumentationInfo(
2343 Instrumentation i, int flags) {
2344 if (i == null) return null;
2345 if ((flags&PackageManager.GET_META_DATA) == 0) {
2346 return i.info;
2347 }
2348 InstrumentationInfo ii = new InstrumentationInfo(i.info);
2349 ii.metaData = i.metaData;
2350 return ii;
2351 }
2352
2353 public static class IntentInfo extends IntentFilter {
2354 public boolean hasDefault;
2355 public int labelRes;
2356 public CharSequence nonLocalizedLabel;
2357 public int icon;
2358 }
2359
2360 public final static class ActivityIntentInfo extends IntentInfo {
2361 public final Activity activity;
2362
2363 public ActivityIntentInfo(Activity _activity) {
2364 activity = _activity;
2365 }
2366
2367 public String toString() {
2368 return "ActivityIntentInfo{"
2369 + Integer.toHexString(System.identityHashCode(this))
2370 + " " + activity.info.name + "}";
2371 }
2372 }
2373
2374 public final static class ServiceIntentInfo extends IntentInfo {
2375 public final Service service;
2376
2377 public ServiceIntentInfo(Service _service) {
2378 service = _service;
2379 }
2380
2381 public String toString() {
2382 return "ServiceIntentInfo{"
2383 + Integer.toHexString(System.identityHashCode(this))
2384 + " " + service.info.name + "}";
2385 }
2386 }
2387}