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