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