blob: 75ba26f7cad232e5e1b4fa9d0f0d35691b6b8e8f [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 */
Jaikumar Ganesh45515652009-04-23 15:20:21 -070077 public static final PackageParser.NewPermissionInfo NEW_PERMISSIONS[] =
78 new PackageParser.NewPermissionInfo[] {
San Mehat5a3a77d2009-06-01 09:25:28 -070079 new PackageParser.NewPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
Jaikumar Ganesh45515652009-04-23 15:20:21 -070080 android.os.Build.VERSION_CODES.DONUT, 0),
81 new PackageParser.NewPermissionInfo(android.Manifest.permission.READ_PHONE_STATE,
82 android.os.Build.VERSION_CODES.DONUT, 0)
Dianne Hackborna96cbb42009-05-13 15:06:13 -070083 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084
85 private String mArchiveSourcePath;
86 private String[] mSeparateProcesses;
87 private int mSdkVersion;
Dianne Hackborn851a5412009-05-08 12:06:44 -070088 private String mSdkCodename;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089
90 private int mParseError = PackageManager.INSTALL_SUCCEEDED;
91
92 private static final Object mSync = new Object();
93 private static WeakReference<byte[]> mReadBuffer;
94
Mitsuru Oshima69fff4a2009-07-21 09:51:05 -070095 private static boolean sCompatibilityModeEnabled = true;
96
Dianne Hackborn1d442e02009-04-20 18:14:05 -070097 static class ParsePackageItemArgs {
98 final Package owner;
99 final String[] outError;
100 final int nameRes;
101 final int labelRes;
102 final int iconRes;
103
104 String tag;
105 TypedArray sa;
106
107 ParsePackageItemArgs(Package _owner, String[] _outError,
108 int _nameRes, int _labelRes, int _iconRes) {
109 owner = _owner;
110 outError = _outError;
111 nameRes = _nameRes;
112 labelRes = _labelRes;
113 iconRes = _iconRes;
114 }
115 }
116
117 static class ParseComponentArgs extends ParsePackageItemArgs {
118 final String[] sepProcesses;
119 final int processRes;
120 final int enabledRes;
121 int flags;
122
123 ParseComponentArgs(Package _owner, String[] _outError,
124 int _nameRes, int _labelRes, int _iconRes,
125 String[] _sepProcesses, int _processRes,int _enabledRes) {
126 super(_owner, _outError, _nameRes, _labelRes, _iconRes);
127 sepProcesses = _sepProcesses;
128 processRes = _processRes;
129 enabledRes = _enabledRes;
130 }
131 }
132
133 private ParsePackageItemArgs mParseInstrumentationArgs;
134 private ParseComponentArgs mParseActivityArgs;
135 private ParseComponentArgs mParseActivityAliasArgs;
136 private ParseComponentArgs mParseServiceArgs;
137 private ParseComponentArgs mParseProviderArgs;
138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 /** If set to true, we will only allow package files that exactly match
140 * the DTD. Otherwise, we try to get as much from the package as we
141 * can without failing. This should normally be set to false, to
142 * support extensions to the DTD in future versions. */
143 private static final boolean RIGID_PARSER = false;
144
145 private static final String TAG = "PackageParser";
146
147 public PackageParser(String archiveSourcePath) {
148 mArchiveSourcePath = archiveSourcePath;
149 }
150
151 public void setSeparateProcesses(String[] procs) {
152 mSeparateProcesses = procs;
153 }
154
Dianne Hackborn851a5412009-05-08 12:06:44 -0700155 public void setSdkVersion(int sdkVersion, String codename) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 mSdkVersion = sdkVersion;
Dianne Hackborn851a5412009-05-08 12:06:44 -0700157 mSdkCodename = codename;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 }
159
160 private static final boolean isPackageFilename(String name) {
161 return name.endsWith(".apk");
162 }
163
164 /**
165 * Generate and return the {@link PackageInfo} for a parsed package.
166 *
167 * @param p the parsed package.
168 * @param flags indicating which optional information is included.
169 */
170 public static PackageInfo generatePackageInfo(PackageParser.Package p,
171 int gids[], int flags) {
172
173 PackageInfo pi = new PackageInfo();
174 pi.packageName = p.packageName;
175 pi.versionCode = p.mVersionCode;
176 pi.versionName = p.mVersionName;
177 pi.sharedUserId = p.mSharedUserId;
178 pi.sharedUserLabel = p.mSharedUserLabel;
179 pi.applicationInfo = p.applicationInfo;
180 if ((flags&PackageManager.GET_GIDS) != 0) {
181 pi.gids = gids;
182 }
183 if ((flags&PackageManager.GET_CONFIGURATIONS) != 0) {
184 int N = p.configPreferences.size();
185 if (N > 0) {
186 pi.configPreferences = new ConfigurationInfo[N];
Dianne Hackborn49237342009-08-27 20:08:01 -0700187 p.configPreferences.toArray(pi.configPreferences);
188 }
189 N = p.reqFeatures != null ? p.reqFeatures.size() : 0;
190 if (N > 0) {
191 pi.reqFeatures = new FeatureInfo[N];
192 p.reqFeatures.toArray(pi.reqFeatures);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 }
194 }
195 if ((flags&PackageManager.GET_ACTIVITIES) != 0) {
196 int N = p.activities.size();
197 if (N > 0) {
Dianne Hackborn7eca6872009-09-28 23:57:05 -0700198 if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
199 pi.activities = new ActivityInfo[N];
200 } else {
201 int num = 0;
202 for (int i=0; i<N; i++) {
203 if (p.activities.get(i).info.enabled) num++;
204 }
205 pi.activities = new ActivityInfo[num];
206 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 for (int i=0; i<N; i++) {
208 final Activity activity = p.activities.get(i);
209 if (activity.info.enabled
210 || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
211 pi.activities[i] = generateActivityInfo(p.activities.get(i), flags);
212 }
213 }
214 }
215 }
216 if ((flags&PackageManager.GET_RECEIVERS) != 0) {
217 int N = p.receivers.size();
218 if (N > 0) {
Dianne Hackborn7eca6872009-09-28 23:57:05 -0700219 if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
220 pi.receivers = new ActivityInfo[N];
221 } else {
222 int num = 0;
223 for (int i=0; i<N; i++) {
224 if (p.receivers.get(i).info.enabled) num++;
225 }
226 pi.receivers = new ActivityInfo[num];
227 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 for (int i=0; i<N; i++) {
229 final Activity activity = p.receivers.get(i);
230 if (activity.info.enabled
231 || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
232 pi.receivers[i] = generateActivityInfo(p.receivers.get(i), flags);
233 }
234 }
235 }
236 }
237 if ((flags&PackageManager.GET_SERVICES) != 0) {
238 int N = p.services.size();
239 if (N > 0) {
Dianne Hackborn7eca6872009-09-28 23:57:05 -0700240 if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
241 pi.services = new ServiceInfo[N];
242 } else {
243 int num = 0;
244 for (int i=0; i<N; i++) {
245 if (p.services.get(i).info.enabled) num++;
246 }
247 pi.services = new ServiceInfo[num];
248 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 for (int i=0; i<N; i++) {
250 final Service service = p.services.get(i);
251 if (service.info.enabled
252 || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
253 pi.services[i] = generateServiceInfo(p.services.get(i), flags);
254 }
255 }
256 }
257 }
258 if ((flags&PackageManager.GET_PROVIDERS) != 0) {
259 int N = p.providers.size();
260 if (N > 0) {
Dianne Hackborn7eca6872009-09-28 23:57:05 -0700261 if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
262 pi.providers = new ProviderInfo[N];
263 } else {
264 int num = 0;
265 for (int i=0; i<N; i++) {
266 if (p.providers.get(i).info.enabled) num++;
267 }
268 pi.providers = new ProviderInfo[num];
269 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 for (int i=0; i<N; i++) {
271 final Provider provider = p.providers.get(i);
272 if (provider.info.enabled
273 || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
274 pi.providers[i] = generateProviderInfo(p.providers.get(i), flags);
275 }
276 }
277 }
278 }
279 if ((flags&PackageManager.GET_INSTRUMENTATION) != 0) {
280 int N = p.instrumentation.size();
281 if (N > 0) {
282 pi.instrumentation = new InstrumentationInfo[N];
283 for (int i=0; i<N; i++) {
284 pi.instrumentation[i] = generateInstrumentationInfo(
285 p.instrumentation.get(i), flags);
286 }
287 }
288 }
289 if ((flags&PackageManager.GET_PERMISSIONS) != 0) {
290 int N = p.permissions.size();
291 if (N > 0) {
292 pi.permissions = new PermissionInfo[N];
293 for (int i=0; i<N; i++) {
294 pi.permissions[i] = generatePermissionInfo(p.permissions.get(i), flags);
295 }
296 }
297 N = p.requestedPermissions.size();
298 if (N > 0) {
299 pi.requestedPermissions = new String[N];
300 for (int i=0; i<N; i++) {
301 pi.requestedPermissions[i] = p.requestedPermissions.get(i);
302 }
303 }
304 }
305 if ((flags&PackageManager.GET_SIGNATURES) != 0) {
Suchi Amalapurapuc7485412009-08-27 12:28:09 -0700306 if (p.mSignatures != null) {
307 int N = p.mSignatures.length;
308 if (N > 0) {
309 pi.signatures = new Signature[N];
310 System.arraycopy(p.mSignatures, 0, pi.signatures, 0, N);
311 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312 }
313 }
314 return pi;
315 }
316
317 private Certificate[] loadCertificates(JarFile jarFile, JarEntry je,
318 byte[] readBuffer) {
319 try {
320 // We must read the stream for the JarEntry to retrieve
321 // its certificates.
322 InputStream is = jarFile.getInputStream(je);
323 while (is.read(readBuffer, 0, readBuffer.length) != -1) {
324 // not using
325 }
326 is.close();
327 return je != null ? je.getCertificates() : null;
328 } catch (IOException e) {
329 Log.w(TAG, "Exception reading " + je.getName() + " in "
330 + jarFile.getName(), e);
331 }
332 return null;
333 }
334
335 public final static int PARSE_IS_SYSTEM = 0x0001;
336 public final static int PARSE_CHATTY = 0x0002;
337 public final static int PARSE_MUST_BE_APK = 0x0004;
338 public final static int PARSE_IGNORE_PROCESSES = 0x0008;
339
340 public int getParseError() {
341 return mParseError;
342 }
343
344 public Package parsePackage(File sourceFile, String destFileName,
345 DisplayMetrics metrics, int flags) {
346 mParseError = PackageManager.INSTALL_SUCCEEDED;
347
348 mArchiveSourcePath = sourceFile.getPath();
349 if (!sourceFile.isFile()) {
350 Log.w(TAG, "Skipping dir: " + mArchiveSourcePath);
351 mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
352 return null;
353 }
354 if (!isPackageFilename(sourceFile.getName())
355 && (flags&PARSE_MUST_BE_APK) != 0) {
356 if ((flags&PARSE_IS_SYSTEM) == 0) {
357 // We expect to have non-.apk files in the system dir,
358 // so don't warn about them.
359 Log.w(TAG, "Skipping non-package file: " + mArchiveSourcePath);
360 }
361 mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
362 return null;
363 }
364
365 if ((flags&PARSE_CHATTY) != 0 && Config.LOGD) Log.d(
366 TAG, "Scanning package: " + mArchiveSourcePath);
367
368 XmlResourceParser parser = null;
369 AssetManager assmgr = null;
370 boolean assetError = true;
371 try {
372 assmgr = new AssetManager();
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -0700373 int cookie = assmgr.addAssetPath(mArchiveSourcePath);
374 if(cookie != 0) {
375 parser = assmgr.openXmlResourceParser(cookie, "AndroidManifest.xml");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 assetError = false;
377 } else {
378 Log.w(TAG, "Failed adding asset path:"+mArchiveSourcePath);
379 }
380 } catch (Exception e) {
381 Log.w(TAG, "Unable to read AndroidManifest.xml of "
382 + mArchiveSourcePath, e);
383 }
384 if(assetError) {
385 if (assmgr != null) assmgr.close();
386 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
387 return null;
388 }
389 String[] errorText = new String[1];
390 Package pkg = null;
391 Exception errorException = null;
392 try {
393 // XXXX todo: need to figure out correct configuration.
394 Resources res = new Resources(assmgr, metrics, null);
395 pkg = parsePackage(res, parser, flags, errorText);
396 } catch (Exception e) {
397 errorException = e;
398 mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
399 }
400
401
402 if (pkg == null) {
403 if (errorException != null) {
404 Log.w(TAG, mArchiveSourcePath, errorException);
405 } else {
406 Log.w(TAG, mArchiveSourcePath + " (at "
407 + parser.getPositionDescription()
408 + "): " + errorText[0]);
409 }
410 parser.close();
411 assmgr.close();
412 if (mParseError == PackageManager.INSTALL_SUCCEEDED) {
413 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
414 }
415 return null;
416 }
417
418 parser.close();
419 assmgr.close();
420
421 pkg.applicationInfo.sourceDir = destFileName;
422 pkg.applicationInfo.publicSourceDir = destFileName;
423 pkg.mSignatures = null;
424
425 return pkg;
426 }
427
428 public boolean collectCertificates(Package pkg, int flags) {
429 pkg.mSignatures = null;
430
431 WeakReference<byte[]> readBufferRef;
432 byte[] readBuffer = null;
433 synchronized (mSync) {
434 readBufferRef = mReadBuffer;
435 if (readBufferRef != null) {
436 mReadBuffer = null;
437 readBuffer = readBufferRef.get();
438 }
439 if (readBuffer == null) {
440 readBuffer = new byte[8192];
441 readBufferRef = new WeakReference<byte[]>(readBuffer);
442 }
443 }
444
445 try {
446 JarFile jarFile = new JarFile(mArchiveSourcePath);
447
448 Certificate[] certs = null;
449
450 if ((flags&PARSE_IS_SYSTEM) != 0) {
451 // If this package comes from the system image, then we
452 // can trust it... we'll just use the AndroidManifest.xml
453 // to retrieve its signatures, not validating all of the
454 // files.
455 JarEntry jarEntry = jarFile.getJarEntry("AndroidManifest.xml");
456 certs = loadCertificates(jarFile, jarEntry, readBuffer);
457 if (certs == null) {
458 Log.e(TAG, "Package " + pkg.packageName
459 + " has no certificates at entry "
460 + jarEntry.getName() + "; ignoring!");
461 jarFile.close();
462 mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
463 return false;
464 }
465 if (false) {
466 Log.i(TAG, "File " + mArchiveSourcePath + ": entry=" + jarEntry
467 + " certs=" + (certs != null ? certs.length : 0));
468 if (certs != null) {
469 final int N = certs.length;
470 for (int i=0; i<N; i++) {
471 Log.i(TAG, " Public key: "
472 + certs[i].getPublicKey().getEncoded()
473 + " " + certs[i].getPublicKey());
474 }
475 }
476 }
477
478 } else {
479 Enumeration entries = jarFile.entries();
480 while (entries.hasMoreElements()) {
481 JarEntry je = (JarEntry)entries.nextElement();
482 if (je.isDirectory()) continue;
483 if (je.getName().startsWith("META-INF/")) continue;
484 Certificate[] localCerts = loadCertificates(jarFile, je,
485 readBuffer);
486 if (false) {
487 Log.i(TAG, "File " + mArchiveSourcePath + " entry " + je.getName()
488 + ": certs=" + certs + " ("
489 + (certs != null ? certs.length : 0) + ")");
490 }
491 if (localCerts == null) {
492 Log.e(TAG, "Package " + pkg.packageName
493 + " has no certificates at entry "
494 + je.getName() + "; ignoring!");
495 jarFile.close();
496 mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
497 return false;
498 } else if (certs == null) {
499 certs = localCerts;
500 } else {
501 // Ensure all certificates match.
502 for (int i=0; i<certs.length; i++) {
503 boolean found = false;
504 for (int j=0; j<localCerts.length; j++) {
505 if (certs[i] != null &&
506 certs[i].equals(localCerts[j])) {
507 found = true;
508 break;
509 }
510 }
511 if (!found || certs.length != localCerts.length) {
512 Log.e(TAG, "Package " + pkg.packageName
513 + " has mismatched certificates at entry "
514 + je.getName() + "; ignoring!");
515 jarFile.close();
516 mParseError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
517 return false;
518 }
519 }
520 }
521 }
522 }
523 jarFile.close();
524
525 synchronized (mSync) {
526 mReadBuffer = readBufferRef;
527 }
528
529 if (certs != null && certs.length > 0) {
530 final int N = certs.length;
531 pkg.mSignatures = new Signature[certs.length];
532 for (int i=0; i<N; i++) {
533 pkg.mSignatures[i] = new Signature(
534 certs[i].getEncoded());
535 }
536 } else {
537 Log.e(TAG, "Package " + pkg.packageName
538 + " has no certificates; ignoring!");
539 mParseError = PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
540 return false;
541 }
542 } catch (CertificateEncodingException e) {
543 Log.w(TAG, "Exception reading " + mArchiveSourcePath, e);
544 mParseError = PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
545 return false;
546 } catch (IOException e) {
547 Log.w(TAG, "Exception reading " + mArchiveSourcePath, e);
548 mParseError = PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
549 return false;
550 } catch (RuntimeException e) {
551 Log.w(TAG, "Exception reading " + mArchiveSourcePath, e);
552 mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
553 return false;
554 }
555
556 return true;
557 }
558
559 public static String parsePackageName(String packageFilePath, int flags) {
560 XmlResourceParser parser = null;
561 AssetManager assmgr = null;
562 try {
563 assmgr = new AssetManager();
564 int cookie = assmgr.addAssetPath(packageFilePath);
565 parser = assmgr.openXmlResourceParser(cookie, "AndroidManifest.xml");
566 } catch (Exception e) {
567 if (assmgr != null) assmgr.close();
568 Log.w(TAG, "Unable to read AndroidManifest.xml of "
569 + packageFilePath, e);
570 return null;
571 }
572 AttributeSet attrs = parser;
573 String errors[] = new String[1];
574 String packageName = null;
575 try {
576 packageName = parsePackageName(parser, attrs, flags, errors);
577 } catch (IOException e) {
578 Log.w(TAG, packageFilePath, e);
579 } catch (XmlPullParserException e) {
580 Log.w(TAG, packageFilePath, e);
581 } finally {
582 if (parser != null) parser.close();
583 if (assmgr != null) assmgr.close();
584 }
585 if (packageName == null) {
586 Log.e(TAG, "parsePackageName error: " + errors[0]);
587 return null;
588 }
589 return packageName;
590 }
591
592 private static String validateName(String name, boolean requiresSeparator) {
593 final int N = name.length();
594 boolean hasSep = false;
595 boolean front = true;
596 for (int i=0; i<N; i++) {
597 final char c = name.charAt(i);
598 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
599 front = false;
600 continue;
601 }
602 if (!front) {
603 if ((c >= '0' && c <= '9') || c == '_') {
604 continue;
605 }
606 }
607 if (c == '.') {
608 hasSep = true;
609 front = true;
610 continue;
611 }
612 return "bad character '" + c + "'";
613 }
614 return hasSep || !requiresSeparator
615 ? null : "must have at least one '.' separator";
616 }
617
618 private static String parsePackageName(XmlPullParser parser,
619 AttributeSet attrs, int flags, String[] outError)
620 throws IOException, XmlPullParserException {
621
622 int type;
623 while ((type=parser.next()) != parser.START_TAG
624 && type != parser.END_DOCUMENT) {
625 ;
626 }
627
628 if (type != parser.START_TAG) {
629 outError[0] = "No start tag found";
630 return null;
631 }
632 if ((flags&PARSE_CHATTY) != 0 && Config.LOGV) Log.v(
633 TAG, "Root element name: '" + parser.getName() + "'");
634 if (!parser.getName().equals("manifest")) {
635 outError[0] = "No <manifest> tag";
636 return null;
637 }
638 String pkgName = attrs.getAttributeValue(null, "package");
639 if (pkgName == null || pkgName.length() == 0) {
640 outError[0] = "<manifest> does not specify package";
641 return null;
642 }
643 String nameError = validateName(pkgName, true);
644 if (nameError != null && !"android".equals(pkgName)) {
645 outError[0] = "<manifest> specifies bad package name \""
646 + pkgName + "\": " + nameError;
647 return null;
648 }
649
650 return pkgName.intern();
651 }
652
653 /**
654 * Temporary.
655 */
656 static public Signature stringToSignature(String str) {
657 final int N = str.length();
658 byte[] sig = new byte[N];
659 for (int i=0; i<N; i++) {
660 sig[i] = (byte)str.charAt(i);
661 }
662 return new Signature(sig);
663 }
664
665 private Package parsePackage(
666 Resources res, XmlResourceParser parser, int flags, String[] outError)
667 throws XmlPullParserException, IOException {
668 AttributeSet attrs = parser;
669
Dianne Hackborn1d442e02009-04-20 18:14:05 -0700670 mParseInstrumentationArgs = null;
671 mParseActivityArgs = null;
672 mParseServiceArgs = null;
673 mParseProviderArgs = null;
674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 String pkgName = parsePackageName(parser, attrs, flags, outError);
676 if (pkgName == null) {
677 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
678 return null;
679 }
680 int type;
681
682 final Package pkg = new Package(pkgName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 boolean foundApp = false;
Dianne Hackborn851a5412009-05-08 12:06:44 -0700684
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 TypedArray sa = res.obtainAttributes(attrs,
686 com.android.internal.R.styleable.AndroidManifest);
687 pkg.mVersionCode = sa.getInteger(
688 com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
689 pkg.mVersionName = sa.getNonResourceString(
690 com.android.internal.R.styleable.AndroidManifest_versionName);
691 if (pkg.mVersionName != null) {
692 pkg.mVersionName = pkg.mVersionName.intern();
693 }
694 String str = sa.getNonResourceString(
695 com.android.internal.R.styleable.AndroidManifest_sharedUserId);
696 if (str != null) {
697 String nameError = validateName(str, true);
698 if (nameError != null && !"android".equals(pkgName)) {
699 outError[0] = "<manifest> specifies bad sharedUserId name \""
700 + str + "\": " + nameError;
701 mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
702 return null;
703 }
704 pkg.mSharedUserId = str.intern();
705 pkg.mSharedUserLabel = sa.getResourceId(
706 com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
707 }
708 sa.recycle();
709
Dianne Hackborn723738c2009-06-25 19:48:04 -0700710 // Resource boolean are -1, so 1 means we don't know the value.
711 int supportsSmallScreens = 1;
712 int supportsNormalScreens = 1;
713 int supportsLargeScreens = 1;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700714 int resizeable = 1;
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700715 int anyDensity = 1;
Dianne Hackborn723738c2009-06-25 19:48:04 -0700716
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717 int outerDepth = parser.getDepth();
718 while ((type=parser.next()) != parser.END_DOCUMENT
719 && (type != parser.END_TAG || parser.getDepth() > outerDepth)) {
720 if (type == parser.END_TAG || type == parser.TEXT) {
721 continue;
722 }
723
724 String tagName = parser.getName();
725 if (tagName.equals("application")) {
726 if (foundApp) {
727 if (RIGID_PARSER) {
728 outError[0] = "<manifest> has more than one <application>";
729 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
730 return null;
731 } else {
732 Log.w(TAG, "<manifest> has more than one <application>");
733 XmlUtils.skipCurrentTag(parser);
734 continue;
735 }
736 }
737
738 foundApp = true;
739 if (!parseApplication(pkg, res, parser, attrs, flags, outError)) {
740 return null;
741 }
742 } else if (tagName.equals("permission-group")) {
743 if (parsePermissionGroup(pkg, res, parser, attrs, outError) == null) {
744 return null;
745 }
746 } else if (tagName.equals("permission")) {
747 if (parsePermission(pkg, res, parser, attrs, outError) == null) {
748 return null;
749 }
750 } else if (tagName.equals("permission-tree")) {
751 if (parsePermissionTree(pkg, res, parser, attrs, outError) == null) {
752 return null;
753 }
754 } else if (tagName.equals("uses-permission")) {
755 sa = res.obtainAttributes(attrs,
756 com.android.internal.R.styleable.AndroidManifestUsesPermission);
757
758 String name = sa.getNonResourceString(
759 com.android.internal.R.styleable.AndroidManifestUsesPermission_name);
760
761 sa.recycle();
762
763 if (name != null && !pkg.requestedPermissions.contains(name)) {
Dianne Hackborn854060a2009-07-09 18:14:31 -0700764 pkg.requestedPermissions.add(name.intern());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 }
766
767 XmlUtils.skipCurrentTag(parser);
768
769 } else if (tagName.equals("uses-configuration")) {
770 ConfigurationInfo cPref = new ConfigurationInfo();
771 sa = res.obtainAttributes(attrs,
772 com.android.internal.R.styleable.AndroidManifestUsesConfiguration);
773 cPref.reqTouchScreen = sa.getInt(
774 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen,
775 Configuration.TOUCHSCREEN_UNDEFINED);
776 cPref.reqKeyboardType = sa.getInt(
777 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType,
778 Configuration.KEYBOARD_UNDEFINED);
779 if (sa.getBoolean(
780 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard,
781 false)) {
782 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
783 }
784 cPref.reqNavigation = sa.getInt(
785 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqNavigation,
786 Configuration.NAVIGATION_UNDEFINED);
787 if (sa.getBoolean(
788 com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav,
789 false)) {
790 cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
791 }
792 sa.recycle();
793 pkg.configPreferences.add(cPref);
794
795 XmlUtils.skipCurrentTag(parser);
796
Suchi Amalapurapud299b812009-06-05 10:26:19 -0700797 } else if (tagName.equals("uses-feature")) {
Dianne Hackborn49237342009-08-27 20:08:01 -0700798 FeatureInfo fi = new FeatureInfo();
Suchi Amalapurapud299b812009-06-05 10:26:19 -0700799 sa = res.obtainAttributes(attrs,
800 com.android.internal.R.styleable.AndroidManifestUsesFeature);
Dianne Hackborn49237342009-08-27 20:08:01 -0700801 fi.name = sa.getNonResourceString(
802 com.android.internal.R.styleable.AndroidManifestUsesFeature_name);
803 if (fi.name == null) {
804 fi.reqGlEsVersion = sa.getInt(
805 com.android.internal.R.styleable.AndroidManifestUsesFeature_glEsVersion,
806 FeatureInfo.GL_ES_VERSION_UNDEFINED);
807 }
808 if (sa.getBoolean(
809 com.android.internal.R.styleable.AndroidManifestUsesFeature_required,
810 true)) {
811 fi.flags |= FeatureInfo.FLAG_REQUIRED;
812 }
Suchi Amalapurapud299b812009-06-05 10:26:19 -0700813 sa.recycle();
Dianne Hackborn49237342009-08-27 20:08:01 -0700814 if (pkg.reqFeatures == null) {
815 pkg.reqFeatures = new ArrayList<FeatureInfo>();
816 }
817 pkg.reqFeatures.add(fi);
818
819 if (fi.name == null) {
820 ConfigurationInfo cPref = new ConfigurationInfo();
821 cPref.reqGlEsVersion = fi.reqGlEsVersion;
822 pkg.configPreferences.add(cPref);
823 }
Suchi Amalapurapud299b812009-06-05 10:26:19 -0700824
825 XmlUtils.skipCurrentTag(parser);
826
Dianne Hackborn851a5412009-05-08 12:06:44 -0700827 } else if (tagName.equals("uses-sdk")) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828 if (mSdkVersion > 0) {
829 sa = res.obtainAttributes(attrs,
830 com.android.internal.R.styleable.AndroidManifestUsesSdk);
831
Dianne Hackborn851a5412009-05-08 12:06:44 -0700832 int minVers = 0;
833 String minCode = null;
834 int targetVers = 0;
835 String targetCode = null;
836
837 TypedValue val = sa.peekValue(
838 com.android.internal.R.styleable.AndroidManifestUsesSdk_minSdkVersion);
839 if (val != null) {
840 if (val.type == TypedValue.TYPE_STRING && val.string != null) {
841 targetCode = minCode = val.string.toString();
842 } else {
843 // If it's not a string, it's an integer.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700844 targetVers = minVers = val.data;
Dianne Hackborn851a5412009-05-08 12:06:44 -0700845 }
846 }
847
848 val = sa.peekValue(
849 com.android.internal.R.styleable.AndroidManifestUsesSdk_targetSdkVersion);
850 if (val != null) {
851 if (val.type == TypedValue.TYPE_STRING && val.string != null) {
852 targetCode = minCode = val.string.toString();
853 } else {
854 // If it's not a string, it's an integer.
855 targetVers = val.data;
856 }
857 }
858
859 int maxVers = sa.getInt(
860 com.android.internal.R.styleable.AndroidManifestUsesSdk_maxSdkVersion,
861 mSdkVersion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800862
863 sa.recycle();
864
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700865 if (minCode != null) {
866 if (!minCode.equals(mSdkCodename)) {
867 if (mSdkCodename != null) {
868 outError[0] = "Requires development platform " + minCode
869 + " (current platform is " + mSdkCodename + ")";
870 } else {
871 outError[0] = "Requires development platform " + minCode
872 + " but this is a release platform.";
873 }
874 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
875 return null;
876 }
877 } else if (minVers > mSdkVersion) {
878 outError[0] = "Requires newer sdk version #" + minVers
879 + " (current version is #" + mSdkVersion + ")";
880 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
881 return null;
882 }
883
Dianne Hackborn851a5412009-05-08 12:06:44 -0700884 if (targetCode != null) {
885 if (!targetCode.equals(mSdkCodename)) {
886 if (mSdkCodename != null) {
887 outError[0] = "Requires development platform " + targetCode
888 + " (current platform is " + mSdkCodename + ")";
889 } else {
890 outError[0] = "Requires development platform " + targetCode
891 + " but this is a release platform.";
892 }
893 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
894 return null;
895 }
896 // If the code matches, it definitely targets this SDK.
Dianne Hackborna96cbb42009-05-13 15:06:13 -0700897 pkg.applicationInfo.targetSdkVersion
898 = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
899 } else {
900 pkg.applicationInfo.targetSdkVersion = targetVers;
Dianne Hackborn851a5412009-05-08 12:06:44 -0700901 }
902
Dianne Hackborn851a5412009-05-08 12:06:44 -0700903 if (maxVers < mSdkVersion) {
904 outError[0] = "Requires older sdk version #" + maxVers
905 + " (current version is #" + mSdkVersion + ")";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800906 mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
907 return null;
908 }
909 }
910
911 XmlUtils.skipCurrentTag(parser);
912
Dianne Hackborn723738c2009-06-25 19:48:04 -0700913 } else if (tagName.equals("supports-screens")) {
914 sa = res.obtainAttributes(attrs,
915 com.android.internal.R.styleable.AndroidManifestSupportsScreens);
916
917 // This is a trick to get a boolean and still able to detect
918 // if a value was actually set.
919 supportsSmallScreens = sa.getInteger(
920 com.android.internal.R.styleable.AndroidManifestSupportsScreens_smallScreens,
921 supportsSmallScreens);
922 supportsNormalScreens = sa.getInteger(
923 com.android.internal.R.styleable.AndroidManifestSupportsScreens_normalScreens,
924 supportsNormalScreens);
925 supportsLargeScreens = sa.getInteger(
926 com.android.internal.R.styleable.AndroidManifestSupportsScreens_largeScreens,
927 supportsLargeScreens);
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700928 resizeable = sa.getInteger(
929 com.android.internal.R.styleable.AndroidManifestSupportsScreens_resizeable,
930 supportsLargeScreens);
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700931 anyDensity = sa.getInteger(
932 com.android.internal.R.styleable.AndroidManifestSupportsScreens_anyDensity,
933 anyDensity);
Dianne Hackborn723738c2009-06-25 19:48:04 -0700934
935 sa.recycle();
936
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700937 XmlUtils.skipCurrentTag(parser);
Dianne Hackborn854060a2009-07-09 18:14:31 -0700938
939 } else if (tagName.equals("protected-broadcast")) {
940 sa = res.obtainAttributes(attrs,
941 com.android.internal.R.styleable.AndroidManifestProtectedBroadcast);
942
943 String name = sa.getNonResourceString(
944 com.android.internal.R.styleable.AndroidManifestProtectedBroadcast_name);
945
946 sa.recycle();
947
948 if (name != null && (flags&PARSE_IS_SYSTEM) != 0) {
949 if (pkg.protectedBroadcasts == null) {
950 pkg.protectedBroadcasts = new ArrayList<String>();
951 }
952 if (!pkg.protectedBroadcasts.contains(name)) {
953 pkg.protectedBroadcasts.add(name.intern());
954 }
955 }
956
957 XmlUtils.skipCurrentTag(parser);
958
959 } else if (tagName.equals("instrumentation")) {
960 if (parseInstrumentation(pkg, res, parser, attrs, outError) == null) {
961 return null;
962 }
963
964 } else if (tagName.equals("eat-comment")) {
965 // Just skip this tag
966 XmlUtils.skipCurrentTag(parser);
967 continue;
968
969 } else if (RIGID_PARSER) {
970 outError[0] = "Bad element under <manifest>: "
971 + parser.getName();
972 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
973 return null;
974
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975 } else {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -0700976 Log.w(TAG, "Unknown element under <manifest>: " + parser.getName()
977 + " at " + mArchiveSourcePath + " "
978 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 XmlUtils.skipCurrentTag(parser);
980 continue;
981 }
982 }
983
984 if (!foundApp && pkg.instrumentation.size() == 0) {
985 outError[0] = "<manifest> does not contain an <application> or <instrumentation>";
986 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
987 }
988
Dianne Hackborna96cbb42009-05-13 15:06:13 -0700989 final int NP = PackageParser.NEW_PERMISSIONS.length;
Dianne Hackborna33e3f72009-09-29 17:28:24 -0700990 StringBuilder implicitPerms = null;
Dianne Hackborna96cbb42009-05-13 15:06:13 -0700991 for (int ip=0; ip<NP; ip++) {
992 final PackageParser.NewPermissionInfo npi
993 = PackageParser.NEW_PERMISSIONS[ip];
994 if (pkg.applicationInfo.targetSdkVersion >= npi.sdkVersion) {
995 break;
996 }
997 if (!pkg.requestedPermissions.contains(npi.name)) {
Dianne Hackborna33e3f72009-09-29 17:28:24 -0700998 if (implicitPerms == null) {
999 implicitPerms = new StringBuilder(128);
1000 implicitPerms.append(pkg.packageName);
1001 implicitPerms.append(": compat added ");
1002 } else {
1003 implicitPerms.append(' ');
1004 }
1005 implicitPerms.append(npi.name);
Dianne Hackborna96cbb42009-05-13 15:06:13 -07001006 pkg.requestedPermissions.add(npi.name);
1007 }
Dianne Hackborn851a5412009-05-08 12:06:44 -07001008 }
Dianne Hackborna33e3f72009-09-29 17:28:24 -07001009 if (implicitPerms != null) {
1010 Log.i(TAG, implicitPerms.toString());
1011 }
Dianne Hackborn851a5412009-05-08 12:06:44 -07001012
Dianne Hackborn723738c2009-06-25 19:48:04 -07001013 if (supportsSmallScreens < 0 || (supportsSmallScreens > 0
1014 && pkg.applicationInfo.targetSdkVersion
Dianne Hackborn11b822d2009-07-21 20:03:02 -07001015 >= android.os.Build.VERSION_CODES.DONUT)) {
Dianne Hackborn723738c2009-06-25 19:48:04 -07001016 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS;
1017 }
1018 if (supportsNormalScreens != 0) {
1019 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS;
1020 }
1021 if (supportsLargeScreens < 0 || (supportsLargeScreens > 0
1022 && pkg.applicationInfo.targetSdkVersion
Dianne Hackborn11b822d2009-07-21 20:03:02 -07001023 >= android.os.Build.VERSION_CODES.DONUT)) {
Dianne Hackborn723738c2009-06-25 19:48:04 -07001024 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
1025 }
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07001026 if (resizeable < 0 || (resizeable > 0
1027 && pkg.applicationInfo.targetSdkVersion
Dianne Hackborn11b822d2009-07-21 20:03:02 -07001028 >= android.os.Build.VERSION_CODES.DONUT)) {
Dianne Hackbornc4db95c2009-07-21 17:46:02 -07001029 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS;
1030 }
Dianne Hackborn11b822d2009-07-21 20:03:02 -07001031 if (anyDensity < 0 || (anyDensity > 0
1032 && pkg.applicationInfo.targetSdkVersion
1033 >= android.os.Build.VERSION_CODES.DONUT)) {
1034 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
Mitsuru Oshima8d112672009-04-27 12:01:23 -07001035 }
Mitsuru Oshima1ecf5d22009-07-06 17:20:38 -07001036
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 return pkg;
1038 }
1039
1040 private static String buildClassName(String pkg, CharSequence clsSeq,
1041 String[] outError) {
1042 if (clsSeq == null || clsSeq.length() <= 0) {
1043 outError[0] = "Empty class name in package " + pkg;
1044 return null;
1045 }
1046 String cls = clsSeq.toString();
1047 char c = cls.charAt(0);
1048 if (c == '.') {
1049 return (pkg + cls).intern();
1050 }
1051 if (cls.indexOf('.') < 0) {
1052 StringBuilder b = new StringBuilder(pkg);
1053 b.append('.');
1054 b.append(cls);
1055 return b.toString().intern();
1056 }
1057 if (c >= 'a' && c <= 'z') {
1058 return cls.intern();
1059 }
1060 outError[0] = "Bad class name " + cls + " in package " + pkg;
1061 return null;
1062 }
1063
1064 private static String buildCompoundName(String pkg,
1065 CharSequence procSeq, String type, String[] outError) {
1066 String proc = procSeq.toString();
1067 char c = proc.charAt(0);
1068 if (pkg != null && c == ':') {
1069 if (proc.length() < 2) {
1070 outError[0] = "Bad " + type + " name " + proc + " in package " + pkg
1071 + ": must be at least two characters";
1072 return null;
1073 }
1074 String subName = proc.substring(1);
1075 String nameError = validateName(subName, false);
1076 if (nameError != null) {
1077 outError[0] = "Invalid " + type + " name " + proc + " in package "
1078 + pkg + ": " + nameError;
1079 return null;
1080 }
1081 return (pkg + proc).intern();
1082 }
1083 String nameError = validateName(proc, true);
1084 if (nameError != null && !"system".equals(proc)) {
1085 outError[0] = "Invalid " + type + " name " + proc + " in package "
1086 + pkg + ": " + nameError;
1087 return null;
1088 }
1089 return proc.intern();
1090 }
1091
1092 private static String buildProcessName(String pkg, String defProc,
1093 CharSequence procSeq, int flags, String[] separateProcesses,
1094 String[] outError) {
1095 if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) {
1096 return defProc != null ? defProc : pkg;
1097 }
1098 if (separateProcesses != null) {
1099 for (int i=separateProcesses.length-1; i>=0; i--) {
1100 String sp = separateProcesses[i];
1101 if (sp.equals(pkg) || sp.equals(defProc) || sp.equals(procSeq)) {
1102 return pkg;
1103 }
1104 }
1105 }
1106 if (procSeq == null || procSeq.length() <= 0) {
1107 return defProc;
1108 }
1109 return buildCompoundName(pkg, procSeq, "package", outError);
1110 }
1111
1112 private static String buildTaskAffinityName(String pkg, String defProc,
1113 CharSequence procSeq, String[] outError) {
1114 if (procSeq == null) {
1115 return defProc;
1116 }
1117 if (procSeq.length() <= 0) {
1118 return null;
1119 }
1120 return buildCompoundName(pkg, procSeq, "taskAffinity", outError);
1121 }
1122
1123 private PermissionGroup parsePermissionGroup(Package owner, Resources res,
1124 XmlPullParser parser, AttributeSet attrs, String[] outError)
1125 throws XmlPullParserException, IOException {
1126 PermissionGroup perm = new PermissionGroup(owner);
1127
1128 TypedArray sa = res.obtainAttributes(attrs,
1129 com.android.internal.R.styleable.AndroidManifestPermissionGroup);
1130
1131 if (!parsePackageItemInfo(owner, perm.info, outError,
1132 "<permission-group>", sa,
1133 com.android.internal.R.styleable.AndroidManifestPermissionGroup_name,
1134 com.android.internal.R.styleable.AndroidManifestPermissionGroup_label,
1135 com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon)) {
1136 sa.recycle();
1137 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1138 return null;
1139 }
1140
1141 perm.info.descriptionRes = sa.getResourceId(
1142 com.android.internal.R.styleable.AndroidManifestPermissionGroup_description,
1143 0);
1144
1145 sa.recycle();
1146
1147 if (!parseAllMetaData(res, parser, attrs, "<permission-group>", perm,
1148 outError)) {
1149 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1150 return null;
1151 }
1152
1153 owner.permissionGroups.add(perm);
1154
1155 return perm;
1156 }
1157
1158 private Permission parsePermission(Package owner, Resources res,
1159 XmlPullParser parser, AttributeSet attrs, String[] outError)
1160 throws XmlPullParserException, IOException {
1161 Permission perm = new Permission(owner);
1162
1163 TypedArray sa = res.obtainAttributes(attrs,
1164 com.android.internal.R.styleable.AndroidManifestPermission);
1165
1166 if (!parsePackageItemInfo(owner, perm.info, outError,
1167 "<permission>", sa,
1168 com.android.internal.R.styleable.AndroidManifestPermission_name,
1169 com.android.internal.R.styleable.AndroidManifestPermission_label,
1170 com.android.internal.R.styleable.AndroidManifestPermission_icon)) {
1171 sa.recycle();
1172 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1173 return null;
1174 }
1175
1176 perm.info.group = sa.getNonResourceString(
1177 com.android.internal.R.styleable.AndroidManifestPermission_permissionGroup);
1178 if (perm.info.group != null) {
1179 perm.info.group = perm.info.group.intern();
1180 }
1181
1182 perm.info.descriptionRes = sa.getResourceId(
1183 com.android.internal.R.styleable.AndroidManifestPermission_description,
1184 0);
1185
1186 perm.info.protectionLevel = sa.getInt(
1187 com.android.internal.R.styleable.AndroidManifestPermission_protectionLevel,
1188 PermissionInfo.PROTECTION_NORMAL);
1189
1190 sa.recycle();
1191
1192 if (perm.info.protectionLevel == -1) {
1193 outError[0] = "<permission> does not specify protectionLevel";
1194 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1195 return null;
1196 }
1197
1198 if (!parseAllMetaData(res, parser, attrs, "<permission>", perm,
1199 outError)) {
1200 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1201 return null;
1202 }
1203
1204 owner.permissions.add(perm);
1205
1206 return perm;
1207 }
1208
1209 private Permission parsePermissionTree(Package owner, Resources res,
1210 XmlPullParser parser, AttributeSet attrs, String[] outError)
1211 throws XmlPullParserException, IOException {
1212 Permission perm = new Permission(owner);
1213
1214 TypedArray sa = res.obtainAttributes(attrs,
1215 com.android.internal.R.styleable.AndroidManifestPermissionTree);
1216
1217 if (!parsePackageItemInfo(owner, perm.info, outError,
1218 "<permission-tree>", sa,
1219 com.android.internal.R.styleable.AndroidManifestPermissionTree_name,
1220 com.android.internal.R.styleable.AndroidManifestPermissionTree_label,
1221 com.android.internal.R.styleable.AndroidManifestPermissionTree_icon)) {
1222 sa.recycle();
1223 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1224 return null;
1225 }
1226
1227 sa.recycle();
1228
1229 int index = perm.info.name.indexOf('.');
1230 if (index > 0) {
1231 index = perm.info.name.indexOf('.', index+1);
1232 }
1233 if (index < 0) {
1234 outError[0] = "<permission-tree> name has less than three segments: "
1235 + perm.info.name;
1236 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1237 return null;
1238 }
1239
1240 perm.info.descriptionRes = 0;
1241 perm.info.protectionLevel = PermissionInfo.PROTECTION_NORMAL;
1242 perm.tree = true;
1243
1244 if (!parseAllMetaData(res, parser, attrs, "<permission-tree>", perm,
1245 outError)) {
1246 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1247 return null;
1248 }
1249
1250 owner.permissions.add(perm);
1251
1252 return perm;
1253 }
1254
1255 private Instrumentation parseInstrumentation(Package owner, Resources res,
1256 XmlPullParser parser, AttributeSet attrs, String[] outError)
1257 throws XmlPullParserException, IOException {
1258 TypedArray sa = res.obtainAttributes(attrs,
1259 com.android.internal.R.styleable.AndroidManifestInstrumentation);
1260
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001261 if (mParseInstrumentationArgs == null) {
1262 mParseInstrumentationArgs = new ParsePackageItemArgs(owner, outError,
1263 com.android.internal.R.styleable.AndroidManifestInstrumentation_name,
1264 com.android.internal.R.styleable.AndroidManifestInstrumentation_label,
1265 com.android.internal.R.styleable.AndroidManifestInstrumentation_icon);
1266 mParseInstrumentationArgs.tag = "<instrumentation>";
1267 }
1268
1269 mParseInstrumentationArgs.sa = sa;
1270
1271 Instrumentation a = new Instrumentation(mParseInstrumentationArgs,
1272 new InstrumentationInfo());
1273 if (outError[0] != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001274 sa.recycle();
1275 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1276 return null;
1277 }
1278
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279 String str;
1280 str = sa.getNonResourceString(
1281 com.android.internal.R.styleable.AndroidManifestInstrumentation_targetPackage);
1282 a.info.targetPackage = str != null ? str.intern() : null;
1283
1284 a.info.handleProfiling = sa.getBoolean(
1285 com.android.internal.R.styleable.AndroidManifestInstrumentation_handleProfiling,
1286 false);
1287
1288 a.info.functionalTest = sa.getBoolean(
1289 com.android.internal.R.styleable.AndroidManifestInstrumentation_functionalTest,
1290 false);
1291
1292 sa.recycle();
1293
1294 if (a.info.targetPackage == null) {
1295 outError[0] = "<instrumentation> does not specify targetPackage";
1296 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1297 return null;
1298 }
1299
1300 if (!parseAllMetaData(res, parser, attrs, "<instrumentation>", a,
1301 outError)) {
1302 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1303 return null;
1304 }
1305
1306 owner.instrumentation.add(a);
1307
1308 return a;
1309 }
1310
1311 private boolean parseApplication(Package owner, Resources res,
1312 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
1313 throws XmlPullParserException, IOException {
1314 final ApplicationInfo ai = owner.applicationInfo;
1315 final String pkgName = owner.applicationInfo.packageName;
1316
1317 TypedArray sa = res.obtainAttributes(attrs,
1318 com.android.internal.R.styleable.AndroidManifestApplication);
1319
1320 String name = sa.getNonResourceString(
1321 com.android.internal.R.styleable.AndroidManifestApplication_name);
1322 if (name != null) {
1323 ai.className = buildClassName(pkgName, name, outError);
1324 if (ai.className == null) {
1325 sa.recycle();
1326 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1327 return false;
1328 }
1329 }
1330
1331 String manageSpaceActivity = sa.getNonResourceString(
1332 com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity);
1333 if (manageSpaceActivity != null) {
1334 ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity,
1335 outError);
1336 }
1337
Christopher Tate181fafa2009-05-14 11:12:14 -07001338 boolean allowBackup = sa.getBoolean(
1339 com.android.internal.R.styleable.AndroidManifestApplication_allowBackup, true);
1340 if (allowBackup) {
1341 ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
Christopher Tate5e1ab332009-09-01 20:32:49 -07001342
1343 // backupAgent, killAfterRestore, and restoreNeedsApplication are only relevant
1344 // if backup is possible for the given application.
Christopher Tate181fafa2009-05-14 11:12:14 -07001345 String backupAgent = sa.getNonResourceString(
1346 com.android.internal.R.styleable.AndroidManifestApplication_backupAgent);
1347 if (backupAgent != null) {
1348 ai.backupAgentName = buildClassName(pkgName, backupAgent, outError);
Dianne Hackborna33e3f72009-09-29 17:28:24 -07001349 if (false) {
1350 Log.v(TAG, "android:backupAgent = " + ai.backupAgentName
1351 + " from " + pkgName + "+" + backupAgent);
1352 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07001353
1354 if (sa.getBoolean(
1355 com.android.internal.R.styleable.AndroidManifestApplication_killAfterRestore,
1356 true)) {
1357 ai.flags |= ApplicationInfo.FLAG_KILL_AFTER_RESTORE;
1358 }
1359 if (sa.getBoolean(
1360 com.android.internal.R.styleable.AndroidManifestApplication_restoreNeedsApplication,
1361 false)) {
1362 ai.flags |= ApplicationInfo.FLAG_RESTORE_NEEDS_APPLICATION;
1363 }
Christopher Tate181fafa2009-05-14 11:12:14 -07001364 }
1365 }
1366
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001367 TypedValue v = sa.peekValue(
1368 com.android.internal.R.styleable.AndroidManifestApplication_label);
1369 if (v != null && (ai.labelRes=v.resourceId) == 0) {
1370 ai.nonLocalizedLabel = v.coerceToString();
1371 }
1372
1373 ai.icon = sa.getResourceId(
1374 com.android.internal.R.styleable.AndroidManifestApplication_icon, 0);
1375 ai.theme = sa.getResourceId(
1376 com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);
1377 ai.descriptionRes = sa.getResourceId(
1378 com.android.internal.R.styleable.AndroidManifestApplication_description, 0);
1379
1380 if ((flags&PARSE_IS_SYSTEM) != 0) {
1381 if (sa.getBoolean(
1382 com.android.internal.R.styleable.AndroidManifestApplication_persistent,
1383 false)) {
1384 ai.flags |= ApplicationInfo.FLAG_PERSISTENT;
1385 }
1386 }
1387
1388 if (sa.getBoolean(
1389 com.android.internal.R.styleable.AndroidManifestApplication_debuggable,
1390 false)) {
1391 ai.flags |= ApplicationInfo.FLAG_DEBUGGABLE;
1392 }
1393
1394 if (sa.getBoolean(
1395 com.android.internal.R.styleable.AndroidManifestApplication_hasCode,
1396 true)) {
1397 ai.flags |= ApplicationInfo.FLAG_HAS_CODE;
1398 }
1399
1400 if (sa.getBoolean(
1401 com.android.internal.R.styleable.AndroidManifestApplication_allowTaskReparenting,
1402 false)) {
1403 ai.flags |= ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING;
1404 }
1405
1406 if (sa.getBoolean(
1407 com.android.internal.R.styleable.AndroidManifestApplication_allowClearUserData,
1408 true)) {
1409 ai.flags |= ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA;
1410 }
1411
Dianne Hackbornade3eca2009-05-11 18:54:45 -07001412 if (sa.getBoolean(
1413 com.android.internal.R.styleable.AndroidManifestApplication_testOnly,
Dianne Hackborne7fe35b2009-05-13 10:53:41 -07001414 false)) {
Dianne Hackbornade3eca2009-05-11 18:54:45 -07001415 ai.flags |= ApplicationInfo.FLAG_TEST_ONLY;
1416 }
1417
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001418 String str;
1419 str = sa.getNonResourceString(
1420 com.android.internal.R.styleable.AndroidManifestApplication_permission);
1421 ai.permission = (str != null && str.length() > 0) ? str.intern() : null;
1422
1423 str = sa.getNonResourceString(
1424 com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity);
1425 ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName,
1426 str, outError);
1427
1428 if (outError[0] == null) {
1429 ai.processName = buildProcessName(ai.packageName, null, sa.getNonResourceString(
1430 com.android.internal.R.styleable.AndroidManifestApplication_process),
1431 flags, mSeparateProcesses, outError);
1432
1433 ai.enabled = sa.getBoolean(com.android.internal.R.styleable.AndroidManifestApplication_enabled, true);
1434 }
1435
1436 sa.recycle();
1437
1438 if (outError[0] != null) {
1439 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1440 return false;
1441 }
1442
1443 final int innerDepth = parser.getDepth();
1444
1445 int type;
1446 while ((type=parser.next()) != parser.END_DOCUMENT
1447 && (type != parser.END_TAG || parser.getDepth() > innerDepth)) {
1448 if (type == parser.END_TAG || type == parser.TEXT) {
1449 continue;
1450 }
1451
1452 String tagName = parser.getName();
1453 if (tagName.equals("activity")) {
1454 Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false);
1455 if (a == null) {
1456 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1457 return false;
1458 }
1459
1460 owner.activities.add(a);
1461
1462 } else if (tagName.equals("receiver")) {
1463 Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true);
1464 if (a == null) {
1465 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1466 return false;
1467 }
1468
1469 owner.receivers.add(a);
1470
1471 } else if (tagName.equals("service")) {
1472 Service s = parseService(owner, res, parser, attrs, flags, outError);
1473 if (s == null) {
1474 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1475 return false;
1476 }
1477
1478 owner.services.add(s);
1479
1480 } else if (tagName.equals("provider")) {
1481 Provider p = parseProvider(owner, res, parser, attrs, flags, outError);
1482 if (p == null) {
1483 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1484 return false;
1485 }
1486
1487 owner.providers.add(p);
1488
1489 } else if (tagName.equals("activity-alias")) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001490 Activity a = parseActivityAlias(owner, res, parser, attrs, flags, outError);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001491 if (a == null) {
1492 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1493 return false;
1494 }
1495
1496 owner.activities.add(a);
1497
1498 } else if (parser.getName().equals("meta-data")) {
1499 // note: application meta-data is stored off to the side, so it can
1500 // remain null in the primary copy (we like to avoid extra copies because
1501 // it can be large)
1502 if ((owner.mAppMetaData = parseMetaData(res, parser, attrs, owner.mAppMetaData,
1503 outError)) == null) {
1504 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1505 return false;
1506 }
1507
1508 } else if (tagName.equals("uses-library")) {
1509 sa = res.obtainAttributes(attrs,
1510 com.android.internal.R.styleable.AndroidManifestUsesLibrary);
1511
1512 String lname = sa.getNonResourceString(
1513 com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
Dianne Hackborn49237342009-08-27 20:08:01 -07001514 boolean req = sa.getBoolean(
1515 com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,
1516 true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001517
1518 sa.recycle();
1519
Dianne Hackborn49237342009-08-27 20:08:01 -07001520 if (lname != null) {
1521 if (req) {
1522 if (owner.usesLibraries == null) {
1523 owner.usesLibraries = new ArrayList<String>();
1524 }
1525 if (!owner.usesLibraries.contains(lname)) {
1526 owner.usesLibraries.add(lname.intern());
1527 }
1528 } else {
1529 if (owner.usesOptionalLibraries == null) {
1530 owner.usesOptionalLibraries = new ArrayList<String>();
1531 }
1532 if (!owner.usesOptionalLibraries.contains(lname)) {
1533 owner.usesOptionalLibraries.add(lname.intern());
1534 }
1535 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001536 }
1537
1538 XmlUtils.skipCurrentTag(parser);
1539
1540 } else {
1541 if (!RIGID_PARSER) {
Dianne Hackborna33e3f72009-09-29 17:28:24 -07001542 Log.w(TAG, "Unknown element under <application>: " + tagName
1543 + " at " + mArchiveSourcePath + " "
1544 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001545 XmlUtils.skipCurrentTag(parser);
1546 continue;
1547 } else {
1548 outError[0] = "Bad element under <application>: " + tagName;
1549 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
1550 return false;
1551 }
1552 }
1553 }
1554
1555 return true;
1556 }
1557
1558 private boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
1559 String[] outError, String tag, TypedArray sa,
1560 int nameRes, int labelRes, int iconRes) {
1561 String name = sa.getNonResourceString(nameRes);
1562 if (name == null) {
1563 outError[0] = tag + " does not specify android:name";
1564 return false;
1565 }
1566
1567 outInfo.name
1568 = buildClassName(owner.applicationInfo.packageName, name, outError);
1569 if (outInfo.name == null) {
1570 return false;
1571 }
1572
1573 int iconVal = sa.getResourceId(iconRes, 0);
1574 if (iconVal != 0) {
1575 outInfo.icon = iconVal;
1576 outInfo.nonLocalizedLabel = null;
1577 }
1578
1579 TypedValue v = sa.peekValue(labelRes);
1580 if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
1581 outInfo.nonLocalizedLabel = v.coerceToString();
1582 }
1583
1584 outInfo.packageName = owner.packageName;
1585
1586 return true;
1587 }
1588
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001589 private Activity parseActivity(Package owner, Resources res,
1590 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError,
1591 boolean receiver) throws XmlPullParserException, IOException {
1592 TypedArray sa = res.obtainAttributes(attrs,
1593 com.android.internal.R.styleable.AndroidManifestActivity);
1594
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001595 if (mParseActivityArgs == null) {
1596 mParseActivityArgs = new ParseComponentArgs(owner, outError,
1597 com.android.internal.R.styleable.AndroidManifestActivity_name,
1598 com.android.internal.R.styleable.AndroidManifestActivity_label,
1599 com.android.internal.R.styleable.AndroidManifestActivity_icon,
1600 mSeparateProcesses,
1601 com.android.internal.R.styleable.AndroidManifestActivity_process,
1602 com.android.internal.R.styleable.AndroidManifestActivity_enabled);
1603 }
1604
1605 mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
1606 mParseActivityArgs.sa = sa;
1607 mParseActivityArgs.flags = flags;
1608
1609 Activity a = new Activity(mParseActivityArgs, new ActivityInfo());
1610 if (outError[0] != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001611 sa.recycle();
1612 return null;
1613 }
1614
1615 final boolean setExported = sa.hasValue(
1616 com.android.internal.R.styleable.AndroidManifestActivity_exported);
1617 if (setExported) {
1618 a.info.exported = sa.getBoolean(
1619 com.android.internal.R.styleable.AndroidManifestActivity_exported, false);
1620 }
1621
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001622 a.info.theme = sa.getResourceId(
1623 com.android.internal.R.styleable.AndroidManifestActivity_theme, 0);
1624
1625 String str;
1626 str = sa.getNonResourceString(
1627 com.android.internal.R.styleable.AndroidManifestActivity_permission);
1628 if (str == null) {
1629 a.info.permission = owner.applicationInfo.permission;
1630 } else {
1631 a.info.permission = str.length() > 0 ? str.toString().intern() : null;
1632 }
1633
1634 str = sa.getNonResourceString(
1635 com.android.internal.R.styleable.AndroidManifestActivity_taskAffinity);
1636 a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName,
1637 owner.applicationInfo.taskAffinity, str, outError);
1638
1639 a.info.flags = 0;
1640 if (sa.getBoolean(
1641 com.android.internal.R.styleable.AndroidManifestActivity_multiprocess,
1642 false)) {
1643 a.info.flags |= ActivityInfo.FLAG_MULTIPROCESS;
1644 }
1645
1646 if (sa.getBoolean(
1647 com.android.internal.R.styleable.AndroidManifestActivity_finishOnTaskLaunch,
1648 false)) {
1649 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH;
1650 }
1651
1652 if (sa.getBoolean(
1653 com.android.internal.R.styleable.AndroidManifestActivity_clearTaskOnLaunch,
1654 false)) {
1655 a.info.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH;
1656 }
1657
1658 if (sa.getBoolean(
1659 com.android.internal.R.styleable.AndroidManifestActivity_noHistory,
1660 false)) {
1661 a.info.flags |= ActivityInfo.FLAG_NO_HISTORY;
1662 }
1663
1664 if (sa.getBoolean(
1665 com.android.internal.R.styleable.AndroidManifestActivity_alwaysRetainTaskState,
1666 false)) {
1667 a.info.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
1668 }
1669
1670 if (sa.getBoolean(
1671 com.android.internal.R.styleable.AndroidManifestActivity_stateNotNeeded,
1672 false)) {
1673 a.info.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED;
1674 }
1675
1676 if (sa.getBoolean(
1677 com.android.internal.R.styleable.AndroidManifestActivity_excludeFromRecents,
1678 false)) {
1679 a.info.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
1680 }
1681
1682 if (sa.getBoolean(
1683 com.android.internal.R.styleable.AndroidManifestActivity_allowTaskReparenting,
1684 (owner.applicationInfo.flags&ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)) {
1685 a.info.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
1686 }
1687
Dianne Hackbornffa42482009-09-23 22:20:11 -07001688 if (sa.getBoolean(
1689 com.android.internal.R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs,
1690 false)) {
1691 a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
1692 }
1693
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001694 if (!receiver) {
1695 a.info.launchMode = sa.getInt(
1696 com.android.internal.R.styleable.AndroidManifestActivity_launchMode,
1697 ActivityInfo.LAUNCH_MULTIPLE);
1698 a.info.screenOrientation = sa.getInt(
1699 com.android.internal.R.styleable.AndroidManifestActivity_screenOrientation,
1700 ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
1701 a.info.configChanges = sa.getInt(
1702 com.android.internal.R.styleable.AndroidManifestActivity_configChanges,
1703 0);
1704 a.info.softInputMode = sa.getInt(
1705 com.android.internal.R.styleable.AndroidManifestActivity_windowSoftInputMode,
1706 0);
1707 } else {
1708 a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
1709 a.info.configChanges = 0;
1710 }
1711
1712 sa.recycle();
1713
1714 if (outError[0] != null) {
1715 return null;
1716 }
1717
1718 int outerDepth = parser.getDepth();
1719 int type;
1720 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
1721 && (type != XmlPullParser.END_TAG
1722 || parser.getDepth() > outerDepth)) {
1723 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1724 continue;
1725 }
1726
1727 if (parser.getName().equals("intent-filter")) {
1728 ActivityIntentInfo intent = new ActivityIntentInfo(a);
1729 if (!parseIntent(res, parser, attrs, flags, intent, outError, !receiver)) {
1730 return null;
1731 }
1732 if (intent.countActions() == 0) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -07001733 Log.w(TAG, "No actions in intent filter at "
1734 + mArchiveSourcePath + " "
1735 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001736 } else {
1737 a.intents.add(intent);
1738 }
1739 } else if (parser.getName().equals("meta-data")) {
1740 if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,
1741 outError)) == null) {
1742 return null;
1743 }
1744 } else {
1745 if (!RIGID_PARSER) {
1746 Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
1747 if (receiver) {
Dianne Hackborna33e3f72009-09-29 17:28:24 -07001748 Log.w(TAG, "Unknown element under <receiver>: " + parser.getName()
1749 + " at " + mArchiveSourcePath + " "
1750 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001751 } else {
Dianne Hackborna33e3f72009-09-29 17:28:24 -07001752 Log.w(TAG, "Unknown element under <activity>: " + parser.getName()
1753 + " at " + mArchiveSourcePath + " "
1754 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 }
1756 XmlUtils.skipCurrentTag(parser);
1757 continue;
1758 }
1759 if (receiver) {
1760 outError[0] = "Bad element under <receiver>: " + parser.getName();
1761 } else {
1762 outError[0] = "Bad element under <activity>: " + parser.getName();
1763 }
1764 return null;
1765 }
1766 }
1767
1768 if (!setExported) {
1769 a.info.exported = a.intents.size() > 0;
1770 }
1771
1772 return a;
1773 }
1774
1775 private Activity parseActivityAlias(Package owner, Resources res,
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001776 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
1777 throws XmlPullParserException, IOException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001778 TypedArray sa = res.obtainAttributes(attrs,
1779 com.android.internal.R.styleable.AndroidManifestActivityAlias);
1780
1781 String targetActivity = sa.getNonResourceString(
1782 com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity);
1783 if (targetActivity == null) {
1784 outError[0] = "<activity-alias> does not specify android:targetActivity";
1785 sa.recycle();
1786 return null;
1787 }
1788
1789 targetActivity = buildClassName(owner.applicationInfo.packageName,
1790 targetActivity, outError);
1791 if (targetActivity == null) {
1792 sa.recycle();
1793 return null;
1794 }
1795
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001796 if (mParseActivityAliasArgs == null) {
1797 mParseActivityAliasArgs = new ParseComponentArgs(owner, outError,
1798 com.android.internal.R.styleable.AndroidManifestActivityAlias_name,
1799 com.android.internal.R.styleable.AndroidManifestActivityAlias_label,
1800 com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
1801 mSeparateProcesses,
1802 0,
1803 com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled);
1804 mParseActivityAliasArgs.tag = "<activity-alias>";
1805 }
1806
1807 mParseActivityAliasArgs.sa = sa;
1808 mParseActivityAliasArgs.flags = flags;
1809
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001810 Activity target = null;
1811
1812 final int NA = owner.activities.size();
1813 for (int i=0; i<NA; i++) {
1814 Activity t = owner.activities.get(i);
1815 if (targetActivity.equals(t.info.name)) {
1816 target = t;
1817 break;
1818 }
1819 }
1820
1821 if (target == null) {
1822 outError[0] = "<activity-alias> target activity " + targetActivity
1823 + " not found in manifest";
1824 sa.recycle();
1825 return null;
1826 }
1827
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001828 ActivityInfo info = new ActivityInfo();
1829 info.targetActivity = targetActivity;
1830 info.configChanges = target.info.configChanges;
1831 info.flags = target.info.flags;
1832 info.icon = target.info.icon;
1833 info.labelRes = target.info.labelRes;
1834 info.nonLocalizedLabel = target.info.nonLocalizedLabel;
1835 info.launchMode = target.info.launchMode;
1836 info.processName = target.info.processName;
1837 info.screenOrientation = target.info.screenOrientation;
1838 info.taskAffinity = target.info.taskAffinity;
1839 info.theme = target.info.theme;
1840
1841 Activity a = new Activity(mParseActivityAliasArgs, info);
1842 if (outError[0] != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843 sa.recycle();
1844 return null;
1845 }
1846
1847 final boolean setExported = sa.hasValue(
1848 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported);
1849 if (setExported) {
1850 a.info.exported = sa.getBoolean(
1851 com.android.internal.R.styleable.AndroidManifestActivityAlias_exported, false);
1852 }
1853
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001854 String str;
1855 str = sa.getNonResourceString(
1856 com.android.internal.R.styleable.AndroidManifestActivityAlias_permission);
1857 if (str != null) {
1858 a.info.permission = str.length() > 0 ? str.toString().intern() : null;
1859 }
1860
1861 sa.recycle();
1862
1863 if (outError[0] != null) {
1864 return null;
1865 }
1866
1867 int outerDepth = parser.getDepth();
1868 int type;
1869 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
1870 && (type != XmlPullParser.END_TAG
1871 || parser.getDepth() > outerDepth)) {
1872 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1873 continue;
1874 }
1875
1876 if (parser.getName().equals("intent-filter")) {
1877 ActivityIntentInfo intent = new ActivityIntentInfo(a);
1878 if (!parseIntent(res, parser, attrs, flags, intent, outError, true)) {
1879 return null;
1880 }
1881 if (intent.countActions() == 0) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -07001882 Log.w(TAG, "No actions in intent filter at "
1883 + mArchiveSourcePath + " "
1884 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001885 } else {
1886 a.intents.add(intent);
1887 }
1888 } else if (parser.getName().equals("meta-data")) {
1889 if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,
1890 outError)) == null) {
1891 return null;
1892 }
1893 } else {
1894 if (!RIGID_PARSER) {
Dianne Hackborna33e3f72009-09-29 17:28:24 -07001895 Log.w(TAG, "Unknown element under <activity-alias>: " + parser.getName()
1896 + " at " + mArchiveSourcePath + " "
1897 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001898 XmlUtils.skipCurrentTag(parser);
1899 continue;
1900 }
1901 outError[0] = "Bad element under <activity-alias>: " + parser.getName();
1902 return null;
1903 }
1904 }
1905
1906 if (!setExported) {
1907 a.info.exported = a.intents.size() > 0;
1908 }
1909
1910 return a;
1911 }
1912
1913 private Provider parseProvider(Package owner, Resources res,
1914 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
1915 throws XmlPullParserException, IOException {
1916 TypedArray sa = res.obtainAttributes(attrs,
1917 com.android.internal.R.styleable.AndroidManifestProvider);
1918
Dianne Hackborn1d442e02009-04-20 18:14:05 -07001919 if (mParseProviderArgs == null) {
1920 mParseProviderArgs = new ParseComponentArgs(owner, outError,
1921 com.android.internal.R.styleable.AndroidManifestProvider_name,
1922 com.android.internal.R.styleable.AndroidManifestProvider_label,
1923 com.android.internal.R.styleable.AndroidManifestProvider_icon,
1924 mSeparateProcesses,
1925 com.android.internal.R.styleable.AndroidManifestProvider_process,
1926 com.android.internal.R.styleable.AndroidManifestProvider_enabled);
1927 mParseProviderArgs.tag = "<provider>";
1928 }
1929
1930 mParseProviderArgs.sa = sa;
1931 mParseProviderArgs.flags = flags;
1932
1933 Provider p = new Provider(mParseProviderArgs, new ProviderInfo());
1934 if (outError[0] != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001935 sa.recycle();
1936 return null;
1937 }
1938
1939 p.info.exported = sa.getBoolean(
1940 com.android.internal.R.styleable.AndroidManifestProvider_exported, true);
1941
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001942 String cpname = sa.getNonResourceString(
1943 com.android.internal.R.styleable.AndroidManifestProvider_authorities);
1944
1945 p.info.isSyncable = sa.getBoolean(
1946 com.android.internal.R.styleable.AndroidManifestProvider_syncable,
1947 false);
1948
1949 String permission = sa.getNonResourceString(
1950 com.android.internal.R.styleable.AndroidManifestProvider_permission);
1951 String str = sa.getNonResourceString(
1952 com.android.internal.R.styleable.AndroidManifestProvider_readPermission);
1953 if (str == null) {
1954 str = permission;
1955 }
1956 if (str == null) {
1957 p.info.readPermission = owner.applicationInfo.permission;
1958 } else {
1959 p.info.readPermission =
1960 str.length() > 0 ? str.toString().intern() : null;
1961 }
1962 str = sa.getNonResourceString(
1963 com.android.internal.R.styleable.AndroidManifestProvider_writePermission);
1964 if (str == null) {
1965 str = permission;
1966 }
1967 if (str == null) {
1968 p.info.writePermission = owner.applicationInfo.permission;
1969 } else {
1970 p.info.writePermission =
1971 str.length() > 0 ? str.toString().intern() : null;
1972 }
1973
1974 p.info.grantUriPermissions = sa.getBoolean(
1975 com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions,
1976 false);
1977
1978 p.info.multiprocess = sa.getBoolean(
1979 com.android.internal.R.styleable.AndroidManifestProvider_multiprocess,
1980 false);
1981
1982 p.info.initOrder = sa.getInt(
1983 com.android.internal.R.styleable.AndroidManifestProvider_initOrder,
1984 0);
1985
1986 sa.recycle();
1987
1988 if (cpname == null) {
1989 outError[0] = "<provider> does not incude authorities attribute";
1990 return null;
1991 }
1992 p.info.authority = cpname.intern();
1993
1994 if (!parseProviderTags(res, parser, attrs, p, outError)) {
1995 return null;
1996 }
1997
1998 return p;
1999 }
2000
2001 private boolean parseProviderTags(Resources res,
2002 XmlPullParser parser, AttributeSet attrs,
2003 Provider outInfo, String[] outError)
2004 throws XmlPullParserException, IOException {
2005 int outerDepth = parser.getDepth();
2006 int type;
2007 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
2008 && (type != XmlPullParser.END_TAG
2009 || parser.getDepth() > outerDepth)) {
2010 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2011 continue;
2012 }
2013
2014 if (parser.getName().equals("meta-data")) {
2015 if ((outInfo.metaData=parseMetaData(res, parser, attrs,
2016 outInfo.metaData, outError)) == null) {
2017 return false;
2018 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07002019
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002020 } else if (parser.getName().equals("grant-uri-permission")) {
2021 TypedArray sa = res.obtainAttributes(attrs,
2022 com.android.internal.R.styleable.AndroidManifestGrantUriPermission);
2023
2024 PatternMatcher pa = null;
2025
2026 String str = sa.getNonResourceString(
2027 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_path);
2028 if (str != null) {
2029 pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL);
2030 }
2031
2032 str = sa.getNonResourceString(
2033 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPrefix);
2034 if (str != null) {
2035 pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX);
2036 }
2037
2038 str = sa.getNonResourceString(
2039 com.android.internal.R.styleable.AndroidManifestGrantUriPermission_pathPattern);
2040 if (str != null) {
2041 pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
2042 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07002043
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002044 sa.recycle();
2045
2046 if (pa != null) {
2047 if (outInfo.info.uriPermissionPatterns == null) {
2048 outInfo.info.uriPermissionPatterns = new PatternMatcher[1];
2049 outInfo.info.uriPermissionPatterns[0] = pa;
2050 } else {
2051 final int N = outInfo.info.uriPermissionPatterns.length;
2052 PatternMatcher[] newp = new PatternMatcher[N+1];
2053 System.arraycopy(outInfo.info.uriPermissionPatterns, 0, newp, 0, N);
2054 newp[N] = pa;
2055 outInfo.info.uriPermissionPatterns = newp;
2056 }
2057 outInfo.info.grantUriPermissions = true;
Dianne Hackborn2af632f2009-07-08 14:56:37 -07002058 } else {
2059 if (!RIGID_PARSER) {
Dianne Hackborna33e3f72009-09-29 17:28:24 -07002060 Log.w(TAG, "Unknown element under <path-permission>: "
2061 + parser.getName() + " at " + mArchiveSourcePath + " "
2062 + parser.getPositionDescription());
Dianne Hackborn2af632f2009-07-08 14:56:37 -07002063 XmlUtils.skipCurrentTag(parser);
2064 continue;
2065 }
2066 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
2067 return false;
2068 }
2069 XmlUtils.skipCurrentTag(parser);
2070
2071 } else if (parser.getName().equals("path-permission")) {
2072 TypedArray sa = res.obtainAttributes(attrs,
2073 com.android.internal.R.styleable.AndroidManifestPathPermission);
2074
2075 PathPermission pa = null;
2076
2077 String permission = sa.getNonResourceString(
2078 com.android.internal.R.styleable.AndroidManifestPathPermission_permission);
2079 String readPermission = sa.getNonResourceString(
2080 com.android.internal.R.styleable.AndroidManifestPathPermission_readPermission);
2081 if (readPermission == null) {
2082 readPermission = permission;
2083 }
2084 String writePermission = sa.getNonResourceString(
2085 com.android.internal.R.styleable.AndroidManifestPathPermission_writePermission);
2086 if (writePermission == null) {
2087 writePermission = permission;
2088 }
2089
2090 boolean havePerm = false;
2091 if (readPermission != null) {
2092 readPermission = readPermission.intern();
2093 havePerm = true;
2094 }
2095 if (writePermission != null) {
2096 writePermission = readPermission.intern();
2097 havePerm = true;
2098 }
2099
2100 if (!havePerm) {
2101 if (!RIGID_PARSER) {
Dianne Hackborna33e3f72009-09-29 17:28:24 -07002102 Log.w(TAG, "No readPermission or writePermssion for <path-permission>: "
2103 + parser.getName() + " at " + mArchiveSourcePath + " "
2104 + parser.getPositionDescription());
Dianne Hackborn2af632f2009-07-08 14:56:37 -07002105 XmlUtils.skipCurrentTag(parser);
2106 continue;
2107 }
2108 outError[0] = "No readPermission or writePermssion for <path-permission>";
2109 return false;
2110 }
2111
2112 String path = sa.getNonResourceString(
2113 com.android.internal.R.styleable.AndroidManifestPathPermission_path);
2114 if (path != null) {
2115 pa = new PathPermission(path,
2116 PatternMatcher.PATTERN_LITERAL, readPermission, writePermission);
2117 }
2118
2119 path = sa.getNonResourceString(
2120 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPrefix);
2121 if (path != null) {
2122 pa = new PathPermission(path,
2123 PatternMatcher.PATTERN_PREFIX, readPermission, writePermission);
2124 }
2125
2126 path = sa.getNonResourceString(
2127 com.android.internal.R.styleable.AndroidManifestPathPermission_pathPattern);
2128 if (path != null) {
2129 pa = new PathPermission(path,
2130 PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission);
2131 }
2132
2133 sa.recycle();
2134
2135 if (pa != null) {
2136 if (outInfo.info.pathPermissions == null) {
2137 outInfo.info.pathPermissions = new PathPermission[1];
2138 outInfo.info.pathPermissions[0] = pa;
2139 } else {
2140 final int N = outInfo.info.pathPermissions.length;
2141 PathPermission[] newp = new PathPermission[N+1];
2142 System.arraycopy(outInfo.info.pathPermissions, 0, newp, 0, N);
2143 newp[N] = pa;
2144 outInfo.info.pathPermissions = newp;
2145 }
2146 } else {
2147 if (!RIGID_PARSER) {
Dianne Hackborna33e3f72009-09-29 17:28:24 -07002148 Log.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: "
2149 + parser.getName() + " at " + mArchiveSourcePath + " "
2150 + parser.getPositionDescription());
Dianne Hackborn2af632f2009-07-08 14:56:37 -07002151 XmlUtils.skipCurrentTag(parser);
2152 continue;
2153 }
2154 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
2155 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002156 }
2157 XmlUtils.skipCurrentTag(parser);
2158
2159 } else {
2160 if (!RIGID_PARSER) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002161 Log.w(TAG, "Unknown element under <provider>: "
Dianne Hackborna33e3f72009-09-29 17:28:24 -07002162 + parser.getName() + " at " + mArchiveSourcePath + " "
2163 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002164 XmlUtils.skipCurrentTag(parser);
2165 continue;
2166 }
2167 outError[0] = "Bad element under <provider>: "
2168 + parser.getName();
2169 return false;
2170 }
2171 }
2172 return true;
2173 }
2174
2175 private Service parseService(Package owner, Resources res,
2176 XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
2177 throws XmlPullParserException, IOException {
2178 TypedArray sa = res.obtainAttributes(attrs,
2179 com.android.internal.R.styleable.AndroidManifestService);
2180
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002181 if (mParseServiceArgs == null) {
2182 mParseServiceArgs = new ParseComponentArgs(owner, outError,
2183 com.android.internal.R.styleable.AndroidManifestService_name,
2184 com.android.internal.R.styleable.AndroidManifestService_label,
2185 com.android.internal.R.styleable.AndroidManifestService_icon,
2186 mSeparateProcesses,
2187 com.android.internal.R.styleable.AndroidManifestService_process,
2188 com.android.internal.R.styleable.AndroidManifestService_enabled);
2189 mParseServiceArgs.tag = "<service>";
2190 }
2191
2192 mParseServiceArgs.sa = sa;
2193 mParseServiceArgs.flags = flags;
2194
2195 Service s = new Service(mParseServiceArgs, new ServiceInfo());
2196 if (outError[0] != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002197 sa.recycle();
2198 return null;
2199 }
2200
2201 final boolean setExported = sa.hasValue(
2202 com.android.internal.R.styleable.AndroidManifestService_exported);
2203 if (setExported) {
2204 s.info.exported = sa.getBoolean(
2205 com.android.internal.R.styleable.AndroidManifestService_exported, false);
2206 }
2207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002208 String str = sa.getNonResourceString(
2209 com.android.internal.R.styleable.AndroidManifestService_permission);
2210 if (str == null) {
2211 s.info.permission = owner.applicationInfo.permission;
2212 } else {
2213 s.info.permission = str.length() > 0 ? str.toString().intern() : null;
2214 }
2215
2216 sa.recycle();
2217
2218 int outerDepth = parser.getDepth();
2219 int type;
2220 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
2221 && (type != XmlPullParser.END_TAG
2222 || parser.getDepth() > outerDepth)) {
2223 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2224 continue;
2225 }
2226
2227 if (parser.getName().equals("intent-filter")) {
2228 ServiceIntentInfo intent = new ServiceIntentInfo(s);
2229 if (!parseIntent(res, parser, attrs, flags, intent, outError, false)) {
2230 return null;
2231 }
2232
2233 s.intents.add(intent);
2234 } else if (parser.getName().equals("meta-data")) {
2235 if ((s.metaData=parseMetaData(res, parser, attrs, s.metaData,
2236 outError)) == null) {
2237 return null;
2238 }
2239 } else {
2240 if (!RIGID_PARSER) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002241 Log.w(TAG, "Unknown element under <service>: "
Dianne Hackborna33e3f72009-09-29 17:28:24 -07002242 + parser.getName() + " at " + mArchiveSourcePath + " "
2243 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002244 XmlUtils.skipCurrentTag(parser);
2245 continue;
2246 }
2247 outError[0] = "Bad element under <service>: "
2248 + parser.getName();
2249 return null;
2250 }
2251 }
2252
2253 if (!setExported) {
2254 s.info.exported = s.intents.size() > 0;
2255 }
2256
2257 return s;
2258 }
2259
2260 private boolean parseAllMetaData(Resources res,
2261 XmlPullParser parser, AttributeSet attrs, String tag,
2262 Component outInfo, String[] outError)
2263 throws XmlPullParserException, IOException {
2264 int outerDepth = parser.getDepth();
2265 int type;
2266 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
2267 && (type != XmlPullParser.END_TAG
2268 || parser.getDepth() > outerDepth)) {
2269 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2270 continue;
2271 }
2272
2273 if (parser.getName().equals("meta-data")) {
2274 if ((outInfo.metaData=parseMetaData(res, parser, attrs,
2275 outInfo.metaData, outError)) == null) {
2276 return false;
2277 }
2278 } else {
2279 if (!RIGID_PARSER) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002280 Log.w(TAG, "Unknown element under " + tag + ": "
Dianne Hackborna33e3f72009-09-29 17:28:24 -07002281 + parser.getName() + " at " + mArchiveSourcePath + " "
2282 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002283 XmlUtils.skipCurrentTag(parser);
2284 continue;
2285 }
2286 outError[0] = "Bad element under " + tag + ": "
2287 + parser.getName();
2288 return false;
2289 }
2290 }
2291 return true;
2292 }
2293
2294 private Bundle parseMetaData(Resources res,
2295 XmlPullParser parser, AttributeSet attrs,
2296 Bundle data, String[] outError)
2297 throws XmlPullParserException, IOException {
2298
2299 TypedArray sa = res.obtainAttributes(attrs,
2300 com.android.internal.R.styleable.AndroidManifestMetaData);
2301
2302 if (data == null) {
2303 data = new Bundle();
2304 }
2305
2306 String name = sa.getNonResourceString(
2307 com.android.internal.R.styleable.AndroidManifestMetaData_name);
2308 if (name == null) {
2309 outError[0] = "<meta-data> requires an android:name attribute";
2310 sa.recycle();
2311 return null;
2312 }
2313
Dianne Hackborn854060a2009-07-09 18:14:31 -07002314 name = name.intern();
2315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002316 TypedValue v = sa.peekValue(
2317 com.android.internal.R.styleable.AndroidManifestMetaData_resource);
2318 if (v != null && v.resourceId != 0) {
2319 //Log.i(TAG, "Meta data ref " + name + ": " + v);
2320 data.putInt(name, v.resourceId);
2321 } else {
2322 v = sa.peekValue(
2323 com.android.internal.R.styleable.AndroidManifestMetaData_value);
2324 //Log.i(TAG, "Meta data " + name + ": " + v);
2325 if (v != null) {
2326 if (v.type == TypedValue.TYPE_STRING) {
2327 CharSequence cs = v.coerceToString();
Dianne Hackborn854060a2009-07-09 18:14:31 -07002328 data.putString(name, cs != null ? cs.toString().intern() : null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002329 } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
2330 data.putBoolean(name, v.data != 0);
2331 } else if (v.type >= TypedValue.TYPE_FIRST_INT
2332 && v.type <= TypedValue.TYPE_LAST_INT) {
2333 data.putInt(name, v.data);
2334 } else if (v.type == TypedValue.TYPE_FLOAT) {
2335 data.putFloat(name, v.getFloat());
2336 } else {
2337 if (!RIGID_PARSER) {
Dianne Hackborna33e3f72009-09-29 17:28:24 -07002338 Log.w(TAG, "<meta-data> only supports string, integer, float, color, boolean, and resource reference types: "
2339 + parser.getName() + " at " + mArchiveSourcePath + " "
2340 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002341 } else {
2342 outError[0] = "<meta-data> only supports string, integer, float, color, boolean, and resource reference types";
2343 data = null;
2344 }
2345 }
2346 } else {
2347 outError[0] = "<meta-data> requires an android:value or android:resource attribute";
2348 data = null;
2349 }
2350 }
2351
2352 sa.recycle();
2353
2354 XmlUtils.skipCurrentTag(parser);
2355
2356 return data;
2357 }
2358
2359 private static final String ANDROID_RESOURCES
2360 = "http://schemas.android.com/apk/res/android";
2361
2362 private boolean parseIntent(Resources res,
2363 XmlPullParser parser, AttributeSet attrs, int flags,
2364 IntentInfo outInfo, String[] outError, boolean isActivity)
2365 throws XmlPullParserException, IOException {
2366
2367 TypedArray sa = res.obtainAttributes(attrs,
2368 com.android.internal.R.styleable.AndroidManifestIntentFilter);
2369
2370 int priority = sa.getInt(
2371 com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0);
2372 if (priority > 0 && isActivity && (flags&PARSE_IS_SYSTEM) == 0) {
2373 Log.w(TAG, "Activity with priority > 0, forcing to 0 at "
Dianne Hackborna33e3f72009-09-29 17:28:24 -07002374 + mArchiveSourcePath + " "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002375 + parser.getPositionDescription());
2376 priority = 0;
2377 }
2378 outInfo.setPriority(priority);
2379
2380 TypedValue v = sa.peekValue(
2381 com.android.internal.R.styleable.AndroidManifestIntentFilter_label);
2382 if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
2383 outInfo.nonLocalizedLabel = v.coerceToString();
2384 }
2385
2386 outInfo.icon = sa.getResourceId(
2387 com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0);
2388
2389 sa.recycle();
2390
2391 int outerDepth = parser.getDepth();
2392 int type;
2393 while ((type=parser.next()) != parser.END_DOCUMENT
2394 && (type != parser.END_TAG || parser.getDepth() > outerDepth)) {
2395 if (type == parser.END_TAG || type == parser.TEXT) {
2396 continue;
2397 }
2398
2399 String nodeName = parser.getName();
2400 if (nodeName.equals("action")) {
2401 String value = attrs.getAttributeValue(
2402 ANDROID_RESOURCES, "name");
2403 if (value == null || value == "") {
2404 outError[0] = "No value supplied for <android:name>";
2405 return false;
2406 }
2407 XmlUtils.skipCurrentTag(parser);
2408
2409 outInfo.addAction(value);
2410 } else if (nodeName.equals("category")) {
2411 String value = attrs.getAttributeValue(
2412 ANDROID_RESOURCES, "name");
2413 if (value == null || value == "") {
2414 outError[0] = "No value supplied for <android:name>";
2415 return false;
2416 }
2417 XmlUtils.skipCurrentTag(parser);
2418
2419 outInfo.addCategory(value);
2420
2421 } else if (nodeName.equals("data")) {
2422 sa = res.obtainAttributes(attrs,
2423 com.android.internal.R.styleable.AndroidManifestData);
2424
2425 String str = sa.getNonResourceString(
2426 com.android.internal.R.styleable.AndroidManifestData_mimeType);
2427 if (str != null) {
2428 try {
2429 outInfo.addDataType(str);
2430 } catch (IntentFilter.MalformedMimeTypeException e) {
2431 outError[0] = e.toString();
2432 sa.recycle();
2433 return false;
2434 }
2435 }
2436
2437 str = sa.getNonResourceString(
2438 com.android.internal.R.styleable.AndroidManifestData_scheme);
2439 if (str != null) {
2440 outInfo.addDataScheme(str);
2441 }
2442
2443 String host = sa.getNonResourceString(
2444 com.android.internal.R.styleable.AndroidManifestData_host);
2445 String port = sa.getNonResourceString(
2446 com.android.internal.R.styleable.AndroidManifestData_port);
2447 if (host != null) {
2448 outInfo.addDataAuthority(host, port);
2449 }
2450
2451 str = sa.getNonResourceString(
2452 com.android.internal.R.styleable.AndroidManifestData_path);
2453 if (str != null) {
2454 outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL);
2455 }
2456
2457 str = sa.getNonResourceString(
2458 com.android.internal.R.styleable.AndroidManifestData_pathPrefix);
2459 if (str != null) {
2460 outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX);
2461 }
2462
2463 str = sa.getNonResourceString(
2464 com.android.internal.R.styleable.AndroidManifestData_pathPattern);
2465 if (str != null) {
2466 outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
2467 }
2468
2469 sa.recycle();
2470 XmlUtils.skipCurrentTag(parser);
2471 } else if (!RIGID_PARSER) {
Dianne Hackborna33e3f72009-09-29 17:28:24 -07002472 Log.w(TAG, "Unknown element under <intent-filter>: "
2473 + parser.getName() + " at " + mArchiveSourcePath + " "
2474 + parser.getPositionDescription());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002475 XmlUtils.skipCurrentTag(parser);
2476 } else {
2477 outError[0] = "Bad element under <intent-filter>: " + parser.getName();
2478 return false;
2479 }
2480 }
2481
2482 outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT);
2483 if (false) {
2484 String cats = "";
2485 Iterator<String> it = outInfo.categoriesIterator();
2486 while (it != null && it.hasNext()) {
2487 cats += " " + it.next();
2488 }
2489 System.out.println("Intent d=" +
2490 outInfo.hasDefault + ", cat=" + cats);
2491 }
2492
2493 return true;
2494 }
2495
2496 public final static class Package {
2497 public final String packageName;
2498
2499 // For now we only support one application per package.
2500 public final ApplicationInfo applicationInfo = new ApplicationInfo();
2501
2502 public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
2503 public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
2504 public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
2505 public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
2506 public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
2507 public final ArrayList<Service> services = new ArrayList<Service>(0);
2508 public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
2509
2510 public final ArrayList<String> requestedPermissions = new ArrayList<String>();
2511
Dianne Hackborn854060a2009-07-09 18:14:31 -07002512 public ArrayList<String> protectedBroadcasts;
2513
Dianne Hackborn49237342009-08-27 20:08:01 -07002514 public ArrayList<String> usesLibraries = null;
2515 public ArrayList<String> usesOptionalLibraries = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002516 public String[] usesLibraryFiles = null;
2517
2518 // We store the application meta-data independently to avoid multiple unwanted references
2519 public Bundle mAppMetaData = null;
2520
2521 // If this is a 3rd party app, this is the path of the zip file.
2522 public String mPath;
2523
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002524 // The version code declared for this package.
2525 public int mVersionCode;
2526
2527 // The version name declared for this package.
2528 public String mVersionName;
2529
2530 // The shared user id that this package wants to use.
2531 public String mSharedUserId;
2532
2533 // The shared user label that this package wants to use.
2534 public int mSharedUserLabel;
2535
2536 // Signatures that were read from the package.
2537 public Signature mSignatures[];
2538
2539 // For use by package manager service for quick lookup of
2540 // preferred up order.
2541 public int mPreferredOrder = 0;
2542
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07002543 // For use by package manager service to keep track of which apps
2544 // have been installed with forward locking.
2545 public boolean mForwardLocked;
2546
2547 // For use by the package manager to keep track of the path to the
2548 // file an app came from.
2549 public String mScanPath;
2550
2551 // For use by package manager to keep track of where it has done dexopt.
2552 public boolean mDidDexOpt;
2553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002554 // Additional data supplied by callers.
2555 public Object mExtras;
2556
2557 /*
2558 * Applications hardware preferences
2559 */
2560 public final ArrayList<ConfigurationInfo> configPreferences =
2561 new ArrayList<ConfigurationInfo>();
2562
Dianne Hackborn49237342009-08-27 20:08:01 -07002563 /*
2564 * Applications requested features
2565 */
2566 public ArrayList<FeatureInfo> reqFeatures = null;
2567
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002568 public Package(String _name) {
2569 packageName = _name;
2570 applicationInfo.packageName = _name;
2571 applicationInfo.uid = -1;
2572 }
2573
2574 public String toString() {
2575 return "Package{"
2576 + Integer.toHexString(System.identityHashCode(this))
2577 + " " + packageName + "}";
2578 }
2579 }
2580
2581 public static class Component<II extends IntentInfo> {
2582 public final Package owner;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002583 public final ArrayList<II> intents;
2584 public final ComponentName component;
2585 public final String componentShortName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002586 public Bundle metaData;
2587
2588 public Component(Package _owner) {
2589 owner = _owner;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002590 intents = null;
2591 component = null;
2592 componentShortName = null;
2593 }
2594
2595 public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) {
2596 owner = args.owner;
2597 intents = new ArrayList<II>(0);
2598 String name = args.sa.getNonResourceString(args.nameRes);
2599 if (name == null) {
2600 component = null;
2601 componentShortName = null;
2602 args.outError[0] = args.tag + " does not specify android:name";
2603 return;
2604 }
2605
2606 outInfo.name
2607 = buildClassName(owner.applicationInfo.packageName, name, args.outError);
2608 if (outInfo.name == null) {
2609 component = null;
2610 componentShortName = null;
2611 args.outError[0] = args.tag + " does not have valid android:name";
2612 return;
2613 }
2614
2615 component = new ComponentName(owner.applicationInfo.packageName,
2616 outInfo.name);
2617 componentShortName = component.flattenToShortString();
2618
2619 int iconVal = args.sa.getResourceId(args.iconRes, 0);
2620 if (iconVal != 0) {
2621 outInfo.icon = iconVal;
2622 outInfo.nonLocalizedLabel = null;
2623 }
2624
2625 TypedValue v = args.sa.peekValue(args.labelRes);
2626 if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
2627 outInfo.nonLocalizedLabel = v.coerceToString();
2628 }
2629
2630 outInfo.packageName = owner.packageName;
2631 }
2632
2633 public Component(final ParseComponentArgs args, final ComponentInfo outInfo) {
2634 this(args, (PackageItemInfo)outInfo);
2635 if (args.outError[0] != null) {
2636 return;
2637 }
2638
2639 if (args.processRes != 0) {
2640 outInfo.processName = buildProcessName(owner.applicationInfo.packageName,
2641 owner.applicationInfo.processName, args.sa.getNonResourceString(args.processRes),
2642 args.flags, args.sepProcesses, args.outError);
2643 }
2644 outInfo.enabled = args.sa.getBoolean(args.enabledRes, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002645 }
2646
2647 public Component(Component<II> clone) {
2648 owner = clone.owner;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002649 intents = clone.intents;
2650 component = clone.component;
2651 componentShortName = clone.componentShortName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002652 metaData = clone.metaData;
2653 }
2654 }
2655
2656 public final static class Permission extends Component<IntentInfo> {
2657 public final PermissionInfo info;
2658 public boolean tree;
2659 public PermissionGroup group;
2660
2661 public Permission(Package _owner) {
2662 super(_owner);
2663 info = new PermissionInfo();
2664 }
2665
2666 public Permission(Package _owner, PermissionInfo _info) {
2667 super(_owner);
2668 info = _info;
2669 }
2670
2671 public String toString() {
2672 return "Permission{"
2673 + Integer.toHexString(System.identityHashCode(this))
2674 + " " + info.name + "}";
2675 }
2676 }
2677
2678 public final static class PermissionGroup extends Component<IntentInfo> {
2679 public final PermissionGroupInfo info;
2680
2681 public PermissionGroup(Package _owner) {
2682 super(_owner);
2683 info = new PermissionGroupInfo();
2684 }
2685
2686 public PermissionGroup(Package _owner, PermissionGroupInfo _info) {
2687 super(_owner);
2688 info = _info;
2689 }
2690
2691 public String toString() {
2692 return "PermissionGroup{"
2693 + Integer.toHexString(System.identityHashCode(this))
2694 + " " + info.name + "}";
2695 }
2696 }
2697
2698 private static boolean copyNeeded(int flags, Package p, Bundle metaData) {
2699 if ((flags & PackageManager.GET_META_DATA) != 0
2700 && (metaData != null || p.mAppMetaData != null)) {
2701 return true;
2702 }
2703 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0
2704 && p.usesLibraryFiles != null) {
2705 return true;
2706 }
2707 return false;
2708 }
2709
2710 public static ApplicationInfo generateApplicationInfo(Package p, int flags) {
2711 if (p == null) return null;
2712 if (!copyNeeded(flags, p, null)) {
Mitsuru Oshima69fff4a2009-07-21 09:51:05 -07002713 // CompatibilityMode is global state. It's safe to modify the instance
2714 // of the package.
2715 if (!sCompatibilityModeEnabled) {
2716 p.applicationInfo.disableCompatibilityMode();
2717 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002718 return p.applicationInfo;
2719 }
2720
2721 // Make shallow copy so we can store the metadata/libraries safely
2722 ApplicationInfo ai = new ApplicationInfo(p.applicationInfo);
2723 if ((flags & PackageManager.GET_META_DATA) != 0) {
2724 ai.metaData = p.mAppMetaData;
2725 }
2726 if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) {
2727 ai.sharedLibraryFiles = p.usesLibraryFiles;
2728 }
Mitsuru Oshima69fff4a2009-07-21 09:51:05 -07002729 if (!sCompatibilityModeEnabled) {
2730 ai.disableCompatibilityMode();
2731 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002732 return ai;
2733 }
2734
2735 public static final PermissionInfo generatePermissionInfo(
2736 Permission p, int flags) {
2737 if (p == null) return null;
2738 if ((flags&PackageManager.GET_META_DATA) == 0) {
2739 return p.info;
2740 }
2741 PermissionInfo pi = new PermissionInfo(p.info);
2742 pi.metaData = p.metaData;
2743 return pi;
2744 }
2745
2746 public static final PermissionGroupInfo generatePermissionGroupInfo(
2747 PermissionGroup pg, int flags) {
2748 if (pg == null) return null;
2749 if ((flags&PackageManager.GET_META_DATA) == 0) {
2750 return pg.info;
2751 }
2752 PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info);
2753 pgi.metaData = pg.metaData;
2754 return pgi;
2755 }
2756
2757 public final static class Activity extends Component<ActivityIntentInfo> {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002758 public final ActivityInfo info;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002759
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002760 public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
2761 super(args, _info);
2762 info = _info;
2763 info.applicationInfo = args.owner.applicationInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002764 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002765
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002766 public String toString() {
2767 return "Activity{"
2768 + Integer.toHexString(System.identityHashCode(this))
2769 + " " + component.flattenToString() + "}";
2770 }
2771 }
2772
2773 public static final ActivityInfo generateActivityInfo(Activity a,
2774 int flags) {
2775 if (a == null) return null;
2776 if (!copyNeeded(flags, a.owner, a.metaData)) {
2777 return a.info;
2778 }
2779 // Make shallow copies so we can store the metadata safely
2780 ActivityInfo ai = new ActivityInfo(a.info);
2781 ai.metaData = a.metaData;
2782 ai.applicationInfo = generateApplicationInfo(a.owner, flags);
2783 return ai;
2784 }
2785
2786 public final static class Service extends Component<ServiceIntentInfo> {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002787 public final ServiceInfo info;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002788
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002789 public Service(final ParseComponentArgs args, final ServiceInfo _info) {
2790 super(args, _info);
2791 info = _info;
2792 info.applicationInfo = args.owner.applicationInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002793 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002794
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002795 public String toString() {
2796 return "Service{"
2797 + Integer.toHexString(System.identityHashCode(this))
2798 + " " + component.flattenToString() + "}";
2799 }
2800 }
2801
2802 public static final ServiceInfo generateServiceInfo(Service s, int flags) {
2803 if (s == null) return null;
2804 if (!copyNeeded(flags, s.owner, s.metaData)) {
2805 return s.info;
2806 }
2807 // Make shallow copies so we can store the metadata safely
2808 ServiceInfo si = new ServiceInfo(s.info);
2809 si.metaData = s.metaData;
2810 si.applicationInfo = generateApplicationInfo(s.owner, flags);
2811 return si;
2812 }
2813
2814 public final static class Provider extends Component {
2815 public final ProviderInfo info;
2816 public boolean syncable;
2817
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002818 public Provider(final ParseComponentArgs args, final ProviderInfo _info) {
2819 super(args, _info);
2820 info = _info;
2821 info.applicationInfo = args.owner.applicationInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002822 syncable = false;
2823 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002824
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002825 public Provider(Provider existingProvider) {
2826 super(existingProvider);
2827 this.info = existingProvider.info;
2828 this.syncable = existingProvider.syncable;
2829 }
2830
2831 public String toString() {
2832 return "Provider{"
2833 + Integer.toHexString(System.identityHashCode(this))
2834 + " " + info.name + "}";
2835 }
2836 }
2837
2838 public static final ProviderInfo generateProviderInfo(Provider p,
2839 int flags) {
2840 if (p == null) return null;
2841 if (!copyNeeded(flags, p.owner, p.metaData)
2842 && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0
2843 || p.info.uriPermissionPatterns == null)) {
2844 return p.info;
2845 }
2846 // Make shallow copies so we can store the metadata safely
2847 ProviderInfo pi = new ProviderInfo(p.info);
2848 pi.metaData = p.metaData;
2849 if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
2850 pi.uriPermissionPatterns = null;
2851 }
2852 pi.applicationInfo = generateApplicationInfo(p.owner, flags);
2853 return pi;
2854 }
2855
2856 public final static class Instrumentation extends Component {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002857 public final InstrumentationInfo info;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002858
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002859 public Instrumentation(final ParsePackageItemArgs args, final InstrumentationInfo _info) {
2860 super(args, _info);
2861 info = _info;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002862 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07002863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002864 public String toString() {
2865 return "Instrumentation{"
2866 + Integer.toHexString(System.identityHashCode(this))
2867 + " " + component.flattenToString() + "}";
2868 }
2869 }
2870
2871 public static final InstrumentationInfo generateInstrumentationInfo(
2872 Instrumentation i, int flags) {
2873 if (i == null) return null;
2874 if ((flags&PackageManager.GET_META_DATA) == 0) {
2875 return i.info;
2876 }
2877 InstrumentationInfo ii = new InstrumentationInfo(i.info);
2878 ii.metaData = i.metaData;
2879 return ii;
2880 }
2881
2882 public static class IntentInfo extends IntentFilter {
2883 public boolean hasDefault;
2884 public int labelRes;
2885 public CharSequence nonLocalizedLabel;
2886 public int icon;
2887 }
2888
2889 public final static class ActivityIntentInfo extends IntentInfo {
2890 public final Activity activity;
2891
2892 public ActivityIntentInfo(Activity _activity) {
2893 activity = _activity;
2894 }
2895
2896 public String toString() {
2897 return "ActivityIntentInfo{"
2898 + Integer.toHexString(System.identityHashCode(this))
2899 + " " + activity.info.name + "}";
2900 }
2901 }
2902
2903 public final static class ServiceIntentInfo extends IntentInfo {
2904 public final Service service;
2905
2906 public ServiceIntentInfo(Service _service) {
2907 service = _service;
2908 }
2909
2910 public String toString() {
2911 return "ServiceIntentInfo{"
2912 + Integer.toHexString(System.identityHashCode(this))
2913 + " " + service.info.name + "}";
2914 }
2915 }
Mitsuru Oshima69fff4a2009-07-21 09:51:05 -07002916
2917 /**
2918 * @hide
2919 */
2920 public static void setCompatibilityModeEnabled(boolean compatibilityModeEnabled) {
2921 sCompatibilityModeEnabled = compatibilityModeEnabled;
2922 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002923}