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