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