diff options
author | Dianne Hackborn <hackbod@google.com> | 2009-05-13 15:06:13 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-05-15 18:23:56 -0700 |
commit | 62da8461ed5317fe78ae5e3793662694e7fc99a3 (patch) | |
tree | e82ca35be1ad67465407f6992e5e0f47fef73c39 | |
parent | 53071d6d159f6dfd6fe0328a39bcf967ef308a64 (diff) |
Implement compatibility support for WRITE_SDCARD permission.
Now old applications will automatically be granted it. Also renamed it from
SDCARD_WRITE to WRITE_SDCARD to be consistent with our other permissions,
and re-arranged how we do targetSdkVersion to actually be usuable for this
kind of stuff.
Note that right now this results in basically all apps being given the
WRITE_SDCARD permission, because their targetSdkVersion is not set. I will
be dealing with that in a future change.
-rw-r--r-- | api/current.xml | 78 | ||||
-rw-r--r-- | core/java/android/content/pm/ApplicationInfo.java | 24 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageParser.java | 48 | ||||
-rw-r--r-- | core/java/android/os/Build.java | 19 | ||||
-rw-r--r-- | core/res/AndroidManifest.xml | 4 | ||||
-rw-r--r-- | core/res/res/values/strings.xml | 2 | ||||
-rw-r--r-- | data/etc/platform.xml | 22 | ||||
-rw-r--r-- | services/java/com/android/server/PackageManagerService.java | 19 | ||||
-rw-r--r-- | tools/aapt/Bundle.h | 17 | ||||
-rw-r--r-- | tools/aapt/Main.cpp | 72 | ||||
-rw-r--r-- | tools/aapt/Resource.cpp | 62 | ||||
-rw-r--r-- | tools/aapt/ResourceTable.cpp | 12 | ||||
-rw-r--r-- | tools/aapt/ResourceTable.h | 7 | ||||
-rw-r--r-- | tools/aapt/XMLNode.cpp | 61 | ||||
-rw-r--r-- | tools/aapt/XMLNode.h | 10 |
15 files changed, 407 insertions, 50 deletions
diff --git a/api/current.xml b/api/current.xml index 1ad643fd77d2..8c56f6974bda 100644 --- a/api/current.xml +++ b/api/current.xml @@ -870,17 +870,6 @@ visibility="public" > </field> -<field name="SDCARD_WRITE" - type="java.lang.String" - transient="false" - volatile="false" - value=""android.permission.SDCARD_WRITE"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> <field name="SEND_SMS" type="java.lang.String" transient="false" @@ -1167,6 +1156,17 @@ visibility="public" > </field> +<field name="WRITE_SDCARD" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.permission.WRITE_SDCARD"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="WRITE_SECURE_SETTINGS" type="java.lang.String" transient="false" @@ -34938,6 +34938,16 @@ visibility="public" > </field> +<field name="targetSdkVersion" + type="int" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="taskAffinity" type="java.lang.String" transient="false" @@ -35113,22 +35123,11 @@ visibility="public" > </field> -<field name="FLAG_TARGETS_SDK" - type="int" - transient="false" - volatile="false" - value="256" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> <field name="FLAG_TEST_ONLY" type="int" transient="false" volatile="false" - value="512" + value="256" static="true" final="true" deprecated="not deprecated" @@ -89129,6 +89128,28 @@ visibility="public" > </field> +<field name="CUR_DEVELOPMENT" + type="int" + transient="false" + volatile="false" + value="10000" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="DONUT" + type="int" + transient="false" + volatile="false" + value="10000" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> </class> <class name="Bundle" extends="java.lang.Object" @@ -142794,6 +142815,17 @@ <implements name="java.lang.annotation.Annotation"> </implements> </class> +<class name="ViewDebug.FlagToString" + extends="java.lang.Object" + abstract="true" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<implements name="java.lang.annotation.Annotation"> +</implements> +</class> <class name="ViewDebug.HierarchyTraceType" extends="java.lang.Enum" abstract="false" diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 88ac04c24e6d..ad022e760d3b 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -123,13 +123,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * Value for {@link #flags}: this is set of the application has set * its android:targetSdkVersion to something >= the current SDK version. */ - public static final int FLAG_TARGETS_SDK = 1<<8; - - /** - * Value for {@link #flags}: this is set of the application has set - * its android:targetSdkVersion to something >= the current SDK version. - */ - public static final int FLAG_TEST_ONLY = 1<<9; + public static final int FLAG_TEST_ONLY = 1<<8; /** * Flags associated with the application. Any combination of @@ -137,7 +131,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * {@link #FLAG_PERSISTENT}, {@link #FLAG_FACTORY_TEST}, and * {@link #FLAG_ALLOW_TASK_REPARENTING} * {@link #FLAG_ALLOW_CLEAR_USER_DATA}, {@link #FLAG_UPDATED_SYSTEM_APP}, - * {@link #FLAG_TARGETS_SDK}. + * {@link #FLAG_TEST_ONLY}. */ public int flags = 0; @@ -182,6 +176,16 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public int[] supportsDensities; /** + * The minimum SDK version this application targets. It may run on earilier + * versions, but it knows how to work with any new behavior added at this + * version. Will be {@link android.os.Build.VERSION_CODES#CUR_DEVELOPMENT} + * if this is a development build and the app is targeting that. You should + * compare that this number is >= the SDK version number at which your + * behavior was introduced. + */ + public int targetSdkVersion; + + /** * When false, indicates that all components within this application are * considered disabled, regardless of their individually set enabled status. */ @@ -200,6 +204,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { pw.println(prefix + "publicSourceDir=" + publicSourceDir); pw.println(prefix + "sharedLibraryFiles=" + sharedLibraryFiles); pw.println(prefix + "dataDir=" + dataDir); + pw.println(prefix + "targetSdkVersion=" + targetSdkVersion); pw.println(prefix + "enabled=" + enabled); pw.println(prefix + "manageSpaceActivityName="+manageSpaceActivityName); pw.println(prefix + "description=0x"+Integer.toHexString(descriptionRes)); @@ -246,6 +251,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { sharedLibraryFiles = orig.sharedLibraryFiles; dataDir = orig.dataDir; uid = orig.uid; + targetSdkVersion = orig.targetSdkVersion; enabled = orig.enabled; manageSpaceActivityName = orig.manageSpaceActivityName; descriptionRes = orig.descriptionRes; @@ -276,6 +282,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeStringArray(sharedLibraryFiles); dest.writeString(dataDir); dest.writeInt(uid); + dest.writeInt(targetSdkVersion); dest.writeInt(enabled ? 1 : 0); dest.writeString(manageSpaceActivityName); dest.writeInt(descriptionRes); @@ -305,6 +312,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { sharedLibraryFiles = source.readStringArray(); dataDir = source.readString(); uid = source.readInt(); + targetSdkVersion = source.readInt(); enabled = source.readInt() != 0; manageSpaceActivityName = source.readString(); descriptionRes = source.readInt(); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 88907c180117..78462f1a25d0 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -55,6 +55,30 @@ import java.util.jar.JarFile; * {@hide} */ public class PackageParser { + /** @hide */ + public static class NewPermissionInfo { + public final String name; + public final int sdkVersion; + public final int fileVersion; + + public NewPermissionInfo(String name, int sdkVersion, int fileVersion) { + this.name = name; + this.sdkVersion = sdkVersion; + this.fileVersion = fileVersion; + } + } + + /** + * List of new permissions that have been added since 1.0. + * NOTE: These must be declared in SDK version order, with permissions + * added to older SDKs appearing before those added to newer SDKs. + * @hide + */ + public static final PackageParser.NewPermissionInfo NEW_PERMISSIONS[] = new PackageParser.NewPermissionInfo[] { + new PackageParser.NewPermissionInfo(android.Manifest.permission.WRITE_SDCARD, + android.os.Build.VERSION_CODES.DONUT, + 0) + }; private String mArchiveSourcePath; private String[] mSeparateProcesses; @@ -616,7 +640,6 @@ public class PackageParser { final Package pkg = new Package(pkgName); boolean foundApp = false; - boolean targetsSdk = false; TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifest); @@ -774,11 +797,10 @@ public class PackageParser { return null; } // If the code matches, it definitely targets this SDK. - targetsSdk = true; - } else if (targetVers >= mSdkVersion) { - // If they have explicitly targeted our current version - // or something after it, then note this. - targetsSdk = true; + pkg.applicationInfo.targetSdkVersion + = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT; + } else { + pkg.applicationInfo.targetSdkVersion = targetVers; } if (minVers > mSdkVersion) { @@ -824,8 +846,18 @@ public class PackageParser { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY; } - if (targetsSdk) { - pkg.applicationInfo.flags |= ApplicationInfo.FLAG_TARGETS_SDK; + final int NP = PackageParser.NEW_PERMISSIONS.length; + for (int ip=0; ip<NP; ip++) { + final PackageParser.NewPermissionInfo npi + = PackageParser.NEW_PERMISSIONS[ip]; + if (pkg.applicationInfo.targetSdkVersion >= npi.sdkVersion) { + break; + } + if (!pkg.requestedPermissions.contains(npi.name)) { + Log.i(TAG, "Impliciting adding " + npi.name + " to old pkg " + + pkg.packageName); + pkg.requestedPermissions.add(npi.name); + } } if (pkg.usesLibraries.size() > 0) { diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 5487c545c12a..4a4285eb8b89 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -87,6 +87,12 @@ public class Build { */ public static class VERSION_CODES { /** + * Magic version number for a current development build, which has + * not yet turned into an official release. + */ + public static final int CUR_DEVELOPMENT = 10000; + + /** * October 2008: The original, first, version of Android. Yay! */ public static final int BASE = 1; @@ -98,6 +104,19 @@ public class Build { * May 2009: Android 1.5. */ public static final int CUPCAKE = 3; + /** + * Current work on "Donut" development branch. + * + * <p>Applications targeting this or a later release will get these + * new changes in behavior:</p> + * <ul> + * <li> They must explicitly request the + * {@link android.Manifest.permission#WRITE_SDCARD} permission to be + * able to modify the contents of the SD card. (Apps targeting + * earlier versions will always request the permission.) + * </ul> + */ + public static final int DONUT = CUR_DEVELOPMENT; } /** The type of build, like "user" or "eng". */ diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 05fbe64e432c..d4b314a46573 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -389,11 +389,11 @@ android:description="@string/permgroupdesc_storage" /> <!-- Allows an application to write to the SD card --> - <permission android:name="android.permission.SDCARD_WRITE" + <permission android:name="android.permission.WRITE_SDCARD" android:permissionGroup="android.permission-group.STORAGE" android:label="@string/permlab_sdcardWrite" android:description="@string/permdesc_sdcardWrite" - android:protectionLevel="normal" /> + android:protectionLevel="dangerous" /> <!-- ============================================ --> <!-- Permissions for low-level system interaction --> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 9ddfa82aacf2..ce716b1871d8 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1076,7 +1076,7 @@ user dictionary.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permlab_sdcardWrite">write to SD card</string> + <string name="permlab_sdcardWrite">modify/delete SD card contents</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permdesc_sdcardWrite">Allows an application to write to the SD card.</string> diff --git a/data/etc/platform.xml b/data/etc/platform.xml index f80bd6b00cdc..526b6d908e13 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -54,7 +54,7 @@ <group gid="log" /> </permission> - <permission name="android.permission.SDCARD_WRITE" > + <permission name="android.permission.WRITE_SDCARD" > <group gid="sdcard_rw" /> </permission> @@ -84,6 +84,24 @@ others should have a fairly open environment in which to interact with the system. --> + <!-- Standard permissions granted to the shell. --> + <assign-permission name="android.permission.WRITE_SDCARD" uid="shell" /> + <assign-permission name="android.permission.SEND_SMS" uid="shell" /> + <assign-permission name="android.permission.CALL_PHONE" uid="shell" /> + <assign-permission name="android.permission.READ_CONTACTS" uid="shell" /> + <assign-permission name="android.permission.WRITE_CONTACTS" uid="shell" /> + <assign-permission name="android.permission.READ_OWNER_DATA" uid="shell" /> + <assign-permission name="android.permission.WRITE_OWNER_DATA" uid="shell" /> + <assign-permission name="android.permission.READ_CALENDAR" uid="shell" /> + <assign-permission name="android.permission.WRITE_CALENDAR" uid="shell" /> + <assign-permission name="android.permission.READ_USER_DICTIONARY" uid="shell" /> + <assign-permission name="android.permission.WRITE_USER_DICTIONARY" uid="shell" /> + <assign-permission name="android.permission.ACCESS_FINE_LOCATION" uid="shell" /> + <assign-permission name="android.permission.ACCESS_COARSE_LOCATION" uid="shell" /> + <assign-permission name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" uid="shell" /> + <assign-permission name="android.permission.ACCESS_NETWORK_STATE" uid="shell" /> + <assign-permission name="android.permission.ACCESS_WIFI_STATE" uid="shell" /> + <assign-permission name="android.permission.BLUETOOTH" uid="shell" /> <!-- System tool permissions granted to the shell. --> <assign-permission name="android.permission.GET_TASKS" uid="shell" /> <assign-permission name="android.permission.CHANGE_CONFIGURATION" uid="shell" /> @@ -114,6 +132,8 @@ <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="shell" /> <assign-permission name="android.permission.READ_FRAME_BUFFER" uid="shell" /> <assign-permission name="android.permission.DEVICE_POWER" uid="shell" /> + <assign-permission name="android.permission.INSTALL_LOCATION_PROVIDER" uid="shell" /> + <assign-permission name="android.permission.INSTALL_LOCATION_COLLECTOR" uid="shell" /> <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" /> <assign-permission name="android.permission.ACCESS_DRM" uid="media" /> diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 5194aea902d8..0007066080d2 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -2831,6 +2831,21 @@ class PackageManagerService extends IPackageManager.Stub { // we can't add any new permissions to it. if (!gp.loadedPermissions.contains(perm)) { allowed = false; + // Except... if this is a permission that was added + // to the platform (note: need to only do this when + // updating the platform). + final int NP = PackageParser.NEW_PERMISSIONS.length; + for (int ip=0; ip<NP; ip++) { + final PackageParser.NewPermissionInfo npi + = PackageParser.NEW_PERMISSIONS[ip]; + if (npi.name.equals(perm) + && pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) { + allowed = true; + Log.i(TAG, "Auto-granting WRITE_SDCARD to old pkg " + + pkg.packageName); + break; + } + } } } if (allowed) { @@ -3589,7 +3604,9 @@ class PackageManagerService extends IPackageManager.Stub { } else { // Re installation failed. Restore old information // Remove new pkg information - removePackageLI(newPackage, true); + if (newPackage != null) { + removePackageLI(newPackage, true); + } // Add back the old system package scanPackageLI(oldPkgSetting.codePath, oldPkgSetting.codePath, oldPkgSetting.resourcePath, diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h index 2d8471bb5cc6..216ece45cb3b 100644 --- a/tools/aapt/Bundle.h +++ b/tools/aapt/Bundle.h @@ -99,6 +99,17 @@ public: const android::Vector<const char*>& getNoCompressExtensions() const { return mNoCompressExtensions; } void addNoCompressExtension(const char* ext) { mNoCompressExtensions.add(ext); } + const char* getMinSdkVersion() const { return mMinSdkVersion; } + void setMinSdkVersion(const char* val) { mMinSdkVersion = val; } + const char* getTargetSdkVersion() const { return mTargetSdkVersion; } + void setTargetSdkVersion(const char* val) { mTargetSdkVersion = val; } + const char* getMaxSdkVersion() const { return mMaxSdkVersion; } + void setMaxSdkVersion(const char* val) { mMaxSdkVersion = val; } + const char* getVersionCode() const { return mVersionCode; } + void setVersionCode(const char* val) { mVersionCode = val; } + const char* getVersionName() const { return mVersionName; } + void setVersionName(const char* val) { mVersionName = val; } + /* * Set and get the file specification. * @@ -151,6 +162,12 @@ private: android::Vector<const char*> mNoCompressExtensions; android::Vector<const char*> mResourceSourceDirs; + const char* mMinSdkVersion; + const char* mTargetSdkVersion; + const char* mMaxSdkVersion; + const char* mVersionCode; + const char* mVersionName; + /* file specification */ int mArgc; char* const* mArgv; diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp index 71b1a3c86317..8bf2b075e6fe 100644 --- a/tools/aapt/Main.cpp +++ b/tools/aapt/Main.cpp @@ -54,9 +54,10 @@ void usage(void) " xmlstrings Print the strings of the given compiled xml assets.\n\n", gProgName); fprintf(stderr, " %s p[ackage] [-d][-f][-m][-u][-v][-x][-z][-M AndroidManifest.xml] \\\n" - " [-0 extension [-0 extension ...]] \\\n" - " [-g tolerance] \\\n" - " [-j jarfile] \\\n" + " [-0 extension [-0 extension ...]] [-g tolerance] [-j jarfile] \\\n" + " [--min-sdk-version VAL] [--target-sdk-version VAL] \\\n" + " [--max-sdk-version VAL] [--app-version VAL] \\\n" + " [--app-version-name TEXT] \\\n" " [-I base-package [-I base-package ...]] \\\n" " [-A asset-source-dir] [-P public-definitions-file] \\\n" " [-S resource-sources [-S resource-sources ...]] " @@ -115,7 +116,17 @@ void usage(void) " and the first match found (left to right) will take precedence." " -0 specifies an additional extension for which such files will not\n" " be stored compressed in the .apk. An empty string means to not\n" - " compress any files at all.\n"); + " compress any files at all.\n" + " --min-sdk-version\n" + " inserts android:minSdkVersion in to manifest.\n" + " --target-sdk-version\n" + " inserts android:targetSdkVersion in to manifest.\n" + " --max-sdk-version\n" + " inserts android:maxSdkVersion in to manifest.\n" + " --version-code\n" + " inserts android:versionCode in to manifest.\n" + " --version-name\n" + " inserts android:versionName in to manifest.\n"); } /* @@ -339,6 +350,59 @@ int main(int argc, char* const argv[]) bundle.setCompressionMethod(ZipEntry::kCompressStored); } break; + case '-': + if (strcmp(cp, "-min-sdk-version") == 0) { + argc--; + argv++; + if (!argc) { + fprintf(stderr, "ERROR: No argument supplied for '--min-sdk-version' option\n"); + wantUsage = true; + goto bail; + } + bundle.setMinSdkVersion(argv[0]); + } else if (strcmp(cp, "-target-sdk-version") == 0) { + argc--; + argv++; + if (!argc) { + fprintf(stderr, "ERROR: No argument supplied for '--target-sdk-version' option\n"); + wantUsage = true; + goto bail; + } + bundle.setTargetSdkVersion(argv[0]); + } else if (strcmp(cp, "-max-sdk-version") == 0) { + argc--; + argv++; + if (!argc) { + fprintf(stderr, "ERROR: No argument supplied for '--max-sdk-version' option\n"); + wantUsage = true; + goto bail; + } + bundle.setMaxSdkVersion(argv[0]); + } else if (strcmp(cp, "-version-code") == 0) { + argc--; + argv++; + if (!argc) { + fprintf(stderr, "ERROR: No argument supplied for '--version-code' option\n"); + wantUsage = true; + goto bail; + } + bundle.setVersionCode(argv[0]); + } else if (strcmp(cp, "-version-name") == 0) { + argc--; + argv++; + if (!argc) { + fprintf(stderr, "ERROR: No argument supplied for '--version-name' option\n"); + wantUsage = true; + goto bail; + } + bundle.setVersionName(argv[0]); + } else { + fprintf(stderr, "ERROR: Unknown option '-%s'\n", cp); + wantUsage = true; + goto bail; + } + cp += strlen(cp) - 1; + break; default: fprintf(stderr, "ERROR: Unknown flag '-%c'\n", *cp); wantUsage = true; diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index 2e4d0a4747c6..76b9d0ab7c9f 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -488,6 +488,58 @@ static void applyFileOverlay(const sp<AaptAssets>& assets, return; } +void addTagAttribute(const sp<XMLNode>& node, const char* ns8, + const char* attr8, const char* value) +{ + if (value == NULL) { + return; + } + + const String16 ns(ns8); + const String16 attr(attr8); + + if (node->getAttribute(ns, attr) != NULL) { + fprintf(stderr, "Warning: AndroidManifest.xml already defines %s (in %s)\n", + String8(attr).string(), String8(ns).string()); + return; + } + + node->addAttribute(ns, attr, String16(value)); +} + +status_t massageManifest(Bundle* bundle, sp<XMLNode> root) +{ + root = root->searchElement(String16(), String16("manifest")); + if (root == NULL) { + fprintf(stderr, "No <manifest> tag.\n"); + return UNKNOWN_ERROR; + } + + addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionCode", + bundle->getVersionCode()); + addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionName", + bundle->getVersionName()); + + if (bundle->getMinSdkVersion() != NULL + || bundle->getTargetSdkVersion() != NULL + || bundle->getMaxSdkVersion() != NULL) { + sp<XMLNode> vers = root->getChildElement(String16(), String16("uses-sdk")); + if (vers == NULL) { + vers = XMLNode::newElement(root->getFilename(), String16(), String16("uses-sdk")); + root->insertChildAt(vers, 0); + } + + addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "minSdkVersion", + bundle->getMinSdkVersion()); + addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "targetSdkVersion", + bundle->getTargetSdkVersion()); + addTagAttribute(vers, RESOURCES_ANDROID_NAMESPACE, "maxSdkVersion", + bundle->getMaxSdkVersion()); + } + + return NO_ERROR; +} + #define ASSIGN_IT(n) \ do { \ ssize_t index = resources->indexOfKey(String8(#n)); \ @@ -1006,7 +1058,15 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets) // Generate final compiled manifest file. manifestFile->clearData(); - err = compileXmlFile(assets, manifestFile, &table); + sp<XMLNode> manifestTree = XMLNode::parse(manifestFile); + if (manifestTree == NULL) { + return UNKNOWN_ERROR; + } + err = massageManifest(bundle, manifestTree); + if (err < NO_ERROR) { + return err; + } + err = compileXmlFile(assets, manifestTree, manifestFile, &table); if (err < NO_ERROR) { return err; } diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index ef11a83c8387..25ab1474d948 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -23,6 +23,16 @@ status_t compileXmlFile(const sp<AaptAssets>& assets, if (root == NULL) { return UNKNOWN_ERROR; } + + return compileXmlFile(assets, root, target, table, options); +} + +status_t compileXmlFile(const sp<AaptAssets>& assets, + const sp<XMLNode>& root, + const sp<AaptFile>& target, + ResourceTable* table, + int options) +{ if ((options&XML_COMPILE_STRIP_WHITESPACE) != 0) { root->removeWhitespace(true, NULL); } else if ((options&XML_COMPILE_COMPACT_WHITESPACE) != 0) { @@ -1307,7 +1317,7 @@ status_t ResourceTable::addIncludedResources(Bundle* bundle, const sp<AaptAssets } else if (id != 0) { if (id == 127) { if (mHaveAppPackage) { - fprintf(stderr, "Included resource have two application packages!\n"); + fprintf(stderr, "Included resources have two application packages!\n"); return UNKNOWN_ERROR; } mHaveAppPackage = true; diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h index 74ba326c2bf3..665232bb6d0d 100644 --- a/tools/aapt/ResourceTable.h +++ b/tools/aapt/ResourceTable.h @@ -15,6 +15,7 @@ using namespace std; +class XMLNode; class ResourceTable; enum { @@ -34,6 +35,12 @@ status_t compileXmlFile(const sp<AaptAssets>& assets, ResourceTable* table, int options = XML_COMPILE_STANDARD_RESOURCE); +status_t compileXmlFile(const sp<AaptAssets>& assets, + const sp<XMLNode>& xmlTree, + const sp<AaptFile>& target, + ResourceTable* table, + int options = XML_COMPILE_STANDARD_RESOURCE); + status_t compileResourceFile(Bundle* bundle, const sp<AaptAssets>& assets, const sp<AaptFile>& in, diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp index 50a21857462c..832ba6ca6c5f 100644 --- a/tools/aapt/XMLNode.cpp +++ b/tools/aapt/XMLNode.cpp @@ -525,12 +525,30 @@ const Vector<sp<XMLNode> >& XMLNode::getChildren() const return mChildren; } +const String8& XMLNode::getFilename() const +{ + return mFilename; +} + const Vector<XMLNode::attribute_entry>& XMLNode::getAttributes() const { return mAttributes; } +const XMLNode::attribute_entry* XMLNode::getAttribute(const String16& ns, + const String16& name) const +{ + for (size_t i=0; i<mAttributes.size(); i++) { + const attribute_entry& ae(mAttributes.itemAt(i)); + if (ae.ns == ns && ae.name == name) { + return &ae; + } + } + + return NULL; +} + const String16& XMLNode::getCData() const { return mChars; @@ -551,6 +569,38 @@ int32_t XMLNode::getEndLineNumber() const return mEndLineNumber; } +sp<XMLNode> XMLNode::searchElement(const String16& tagNamespace, const String16& tagName) +{ + if (getType() == XMLNode::TYPE_ELEMENT + && mNamespaceUri == tagNamespace + && mElementName == tagName) { + return this; + } + + for (size_t i=0; i<mChildren.size(); i++) { + sp<XMLNode> found = mChildren.itemAt(i)->searchElement(tagNamespace, tagName); + if (found != NULL) { + return found; + } + } + + return NULL; +} + +sp<XMLNode> XMLNode::getChildElement(const String16& tagNamespace, const String16& tagName) +{ + for (size_t i=0; i<mChildren.size(); i++) { + sp<XMLNode> child = mChildren.itemAt(i); + if (child->getType() == XMLNode::TYPE_ELEMENT + && child->mNamespaceUri == tagNamespace + && child->mElementName == tagName) { + return child; + } + } + + return NULL; +} + status_t XMLNode::addChild(const sp<XMLNode>& child) { if (getType() == TYPE_CDATA) { @@ -562,6 +612,17 @@ status_t XMLNode::addChild(const sp<XMLNode>& child) return NO_ERROR; } +status_t XMLNode::insertChildAt(const sp<XMLNode>& child, size_t index) +{ + if (getType() == TYPE_CDATA) { + SourcePos(mFilename, child->getStartLineNumber()).error("Child to CDATA node."); + return UNKNOWN_ERROR; + } + //printf("Adding child %p to parent %p\n", child.get(), this); + mChildren.insertAt(child, index); + return NO_ERROR; +} + status_t XMLNode::addAttribute(const String16& ns, const String16& name, const String16& value) { diff --git a/tools/aapt/XMLNode.h b/tools/aapt/XMLNode.h index 86548a22c858..a9bea4312ecc 100644 --- a/tools/aapt/XMLNode.h +++ b/tools/aapt/XMLNode.h @@ -68,6 +68,8 @@ public: const String16& getElementName() const; const Vector<sp<XMLNode> >& getChildren() const; + const String8& getFilename() const; + struct attribute_entry { attribute_entry() : index(~(uint32_t)0), nameResId(0) { @@ -91,6 +93,8 @@ public: const Vector<attribute_entry>& getAttributes() const; + const attribute_entry* getAttribute(const String16& ns, const String16& name) const; + const String16& getCData() const; const String16& getComment() const; @@ -98,8 +102,14 @@ public: int32_t getStartLineNumber() const; int32_t getEndLineNumber() const; + sp<XMLNode> searchElement(const String16& tagNamespace, const String16& tagName); + + sp<XMLNode> getChildElement(const String16& tagNamespace, const String16& tagName); + status_t addChild(const sp<XMLNode>& child); + status_t insertChildAt(const sp<XMLNode>& child, size_t index); + status_t addAttribute(const String16& ns, const String16& name, const String16& value); |