#include "ResourceTable.h"
#include "XMLNode.h"
-#include <utils.h>
-#include <utils/ZipFile.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Errors.h>
#include <fcntl.h>
#include <errno.h>
printf("\nNo resource table found.\n");
} else {
printf("\nResource table:\n");
- res.print();
+ res.print(false);
}
Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
return -1;
}
-static String8 getAttribute(const ResXMLTree& tree, const char* ns,
+String8 getAttribute(const ResXMLTree& tree, const char* ns,
const char* attr, String8* outError)
{
ssize_t idx = tree.indexOfAttribute(ns, attr);
return str ? String8(str, len) : String8();
}
-static int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes, String8* outError)
+static int32_t getIntegerAttribute(const ResXMLTree& tree, uint32_t attrRes,
+ String8* outError, int32_t defValue = -1)
{
ssize_t idx = indexOfAttribute(tree, attrRes);
if (idx < 0) {
- return -1;
+ return defValue;
}
Res_value value;
if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
- if (value.dataType != Res_value::TYPE_INT_DEC) {
+ if (value.dataType < Res_value::TYPE_FIRST_INT
+ || value.dataType > Res_value::TYPE_LAST_INT) {
if (outError != NULL) *outError = "attribute is not an integer value";
- return -1;
+ return defValue;
}
}
return value.data;
VERSION_NAME_ATTR = 0x0101021c,
LABEL_ATTR = 0x01010001,
ICON_ATTR = 0x01010002,
- MIN_SDK_VERSION_ATTR = 0x0101020c
+ MIN_SDK_VERSION_ATTR = 0x0101020c,
+ MAX_SDK_VERSION_ATTR = 0x01010271,
+ REQ_TOUCH_SCREEN_ATTR = 0x01010227,
+ REQ_KEYBOARD_TYPE_ATTR = 0x01010228,
+ REQ_HARD_KEYBOARD_ATTR = 0x01010229,
+ REQ_NAVIGATION_ATTR = 0x0101022a,
+ REQ_FIVE_WAY_NAV_ATTR = 0x01010232,
+ TARGET_SDK_VERSION_ATTR = 0x01010270,
+ TEST_ONLY_ATTR = 0x01010272,
+ DENSITY_ATTR = 0x0101026c,
+ GL_ES_VERSION_ATTR = 0x01010281,
+ SMALL_SCREEN_ATTR = 0x01010284,
+ NORMAL_SCREEN_ATTR = 0x01010285,
+ LARGE_SCREEN_ATTR = 0x01010286,
+ REQUIRED_ATTR = 0x0101028e,
};
const char *getComponentName(String8 &pkgName, String8 &componentName) {
const char* filename = bundle->getFileSpecEntry(1);
AssetManager assets;
- if (!assets.addAssetPath(String8(filename), NULL)) {
+ void* assetsCookie;
+ if (!assets.addAssetPath(String8(filename), &assetsCookie)) {
fprintf(stderr, "ERROR: dump failed because assets could not be loaded\n");
return 1;
}
}
if (strcmp("resources", option) == 0) {
- res.print();
+ res.print(bundle->getValues());
} else if (strcmp("xmltree", option) == 0) {
if (bundle->getFileSpecCount() < 3) {
ResXMLTree tree;
asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER);
if (asset == NULL) {
- fprintf(stderr, "ERROR: dump failed because resource %p found\n", resname);
+ fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
goto bail;
}
ResXMLTree tree;
asset = assets.openNonAsset(resname, Asset::ACCESS_BUFFER);
if (asset == NULL) {
- fprintf(stderr, "ERROR: dump failed because resource %p found\n", resname);
+ fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname);
goto bail;
}
bool withinActivity = false;
bool isMainActivity = false;
bool isLauncherActivity = false;
+ bool isSearchable = false;
bool withinApplication = false;
bool withinReceiver = false;
+ bool withinService = false;
+ bool withinIntentFilter = false;
+ bool hasMainActivity = false;
+ bool hasOtherActivities = false;
+ bool hasOtherReceivers = false;
+ bool hasOtherServices = false;
+ bool hasWallpaperService = false;
+ bool hasImeService = false;
+ bool hasWidgetReceivers = false;
+ bool hasIntentFilter = false;
+ bool actMainActivity = false;
+ bool actWidgetReceivers = false;
+ bool actImeService = false;
+ bool actWallpaperService = false;
+ bool specCameraFeature = false;
+ bool hasCameraPermission = false;
+ int targetSdk = 0;
+ int smallScreen = 1;
+ int normalScreen = 1;
+ int largeScreen = 1;
String8 pkg;
String8 activityName;
String8 activityLabel;
String8 activityIcon;
String8 receiverName;
+ String8 serviceName;
while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::END_TAG) {
depth--;
+ if (depth < 2) {
+ withinApplication = false;
+ } else if (depth < 3) {
+ if (withinActivity && isMainActivity && isLauncherActivity) {
+ const char *aName = getComponentName(pkg, activityName);
+ if (aName != NULL) {
+ printf("launchable activity name='%s'", aName);
+ }
+ printf("label='%s' icon='%s'\n",
+ activityLabel.string(),
+ activityIcon.string());
+ }
+ if (!hasIntentFilter) {
+ hasOtherActivities |= withinActivity;
+ hasOtherReceivers |= withinReceiver;
+ hasOtherServices |= withinService;
+ }
+ withinActivity = false;
+ withinService = false;
+ withinReceiver = false;
+ hasIntentFilter = false;
+ isMainActivity = isLauncherActivity = false;
+ } else if (depth < 4) {
+ if (withinIntentFilter) {
+ if (withinActivity) {
+ hasMainActivity |= actMainActivity;
+ hasOtherActivities |= !actMainActivity;
+ } else if (withinReceiver) {
+ hasWidgetReceivers |= actWidgetReceivers;
+ hasOtherReceivers |= !actWidgetReceivers;
+ } else if (withinService) {
+ hasImeService |= actImeService;
+ hasWallpaperService |= actWallpaperService;
+ hasOtherServices |= (!actImeService && !actWallpaperService);
+ }
+ }
+ withinIntentFilter = false;
+ }
continue;
}
if (code != ResXMLTree::START_TAG) {
}
depth++;
String8 tag(tree.getElementName(&len));
- //printf("Depth %d tag %s\n", depth, tag.string());
+ //printf("Depth %d, %s\n", depth, tag.string());
if (depth == 1) {
if (tag != "manifest") {
fprintf(stderr, "ERROR: manifest does not start with <manifest> tag\n");
goto bail;
}
printf("icon='%s'\n", icon.string());
+ int32_t testOnly = getIntegerAttribute(tree, TEST_ONLY_ATTR, &error, 0);
+ if (error != "") {
+ fprintf(stderr, "ERROR getting 'android:testOnly' attribute: %s\n", error.string());
+ goto bail;
+ }
+ if (testOnly != 0) {
+ printf("testOnly='%d'\n", testOnly);
+ }
} else if (tag == "uses-sdk") {
- int32_t sdkVersion = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error);
+ int32_t code = getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error);
+ if (error != "") {
+ error = "";
+ String8 name = getResolvedAttribute(&res, tree, MIN_SDK_VERSION_ATTR, &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n",
+ error.string());
+ goto bail;
+ }
+ if (name == "Donut") targetSdk = 4;
+ printf("sdkVersion:'%s'\n", name.string());
+ } else if (code != -1) {
+ targetSdk = code;
+ printf("sdkVersion:'%d'\n", code);
+ }
+ code = getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1);
+ if (code != -1) {
+ printf("maxSdkVersion:'%d'\n", code);
+ }
+ code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error);
+ if (error != "") {
+ error = "";
+ String8 name = getResolvedAttribute(&res, tree, TARGET_SDK_VERSION_ATTR, &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
+ error.string());
+ goto bail;
+ }
+ if (name == "Donut" && targetSdk < 4) targetSdk = 4;
+ printf("targetSdkVersion:'%s'\n", name.string());
+ } else if (code != -1) {
+ if (targetSdk < code) {
+ targetSdk = code;
+ }
+ printf("targetSdkVersion:'%d'\n", code);
+ }
+ } else if (tag == "uses-configuration") {
+ int32_t reqTouchScreen = getIntegerAttribute(tree,
+ REQ_TOUCH_SCREEN_ATTR, NULL, 0);
+ int32_t reqKeyboardType = getIntegerAttribute(tree,
+ REQ_KEYBOARD_TYPE_ATTR, NULL, 0);
+ int32_t reqHardKeyboard = getIntegerAttribute(tree,
+ REQ_HARD_KEYBOARD_ATTR, NULL, 0);
+ int32_t reqNavigation = getIntegerAttribute(tree,
+ REQ_NAVIGATION_ATTR, NULL, 0);
+ int32_t reqFiveWayNav = getIntegerAttribute(tree,
+ REQ_FIVE_WAY_NAV_ATTR, NULL, 0);
+ printf("uses-configuation:");
+ if (reqTouchScreen != 0) {
+ printf(" reqTouchScreen='%d'", reqTouchScreen);
+ }
+ if (reqKeyboardType != 0) {
+ printf(" reqKeyboardType='%d'", reqKeyboardType);
+ }
+ if (reqHardKeyboard != 0) {
+ printf(" reqHardKeyboard='%d'", reqHardKeyboard);
+ }
+ if (reqNavigation != 0) {
+ printf(" reqNavigation='%d'", reqNavigation);
+ }
+ if (reqFiveWayNav != 0) {
+ printf(" reqFiveWayNav='%d'", reqFiveWayNav);
+ }
+ printf("\n");
+ } else if (tag == "supports-density") {
+ int32_t dens = getIntegerAttribute(tree, DENSITY_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n", error.string());
+ fprintf(stderr, "ERROR getting 'android:density' attribute: %s\n",
+ error.string());
goto bail;
}
- if (sdkVersion != -1) {
- printf("sdkVersion:'%d'\n", sdkVersion);
+ printf("supports-density:'%d'\n", dens);
+ } else if (tag == "supports-screens") {
+ smallScreen = getIntegerAttribute(tree,
+ SMALL_SCREEN_ATTR, NULL, 1);
+ normalScreen = getIntegerAttribute(tree,
+ NORMAL_SCREEN_ATTR, NULL, 1);
+ largeScreen = getIntegerAttribute(tree,
+ LARGE_SCREEN_ATTR, NULL, 1);
+ } else if (tag == "uses-feature") {
+ String8 name = getAttribute(tree, NAME_ATTR, &error);
+
+ if (name != "" && error == "") {
+ int req = getIntegerAttribute(tree,
+ REQUIRED_ATTR, NULL, 1);
+ if (name == "android.hardware.camera") {
+ specCameraFeature = true;
+ }
+ printf("uses-feature%s:'%s'\n",
+ req ? "" : "-not-required", name.string());
+ } else {
+ int vers = getIntegerAttribute(tree,
+ GL_ES_VERSION_ATTR, &error);
+ if (error == "") {
+ printf("uses-gl-es:'0x%x'\n", vers);
+ }
+ }
+ } else if (tag == "uses-permission") {
+ String8 name = getAttribute(tree, NAME_ATTR, &error);
+ if (name != "" && error == "") {
+ if (name == "android.permission.CAMERA") {
+ hasCameraPermission = true;
+ }
+ printf("uses-permission:'%s'\n", name.string());
+ } else {
+ fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
+ error.string());
+ goto bail;
}
}
} else if (depth == 3 && withinApplication) {
withinActivity = false;
withinReceiver = false;
+ withinService = false;
+ hasIntentFilter = false;
if(tag == "activity") {
withinActivity = true;
activityName = getAttribute(tree, NAME_ATTR, &error);
fprintf(stderr, "ERROR getting 'android:name' attribute for uses-library: %s\n", error.string());
goto bail;
}
- printf("uses-library:'%s'\n", libraryName.string());
+ int req = getIntegerAttribute(tree,
+ REQUIRED_ATTR, NULL, 1);
+ printf("uses-library%s:'%s'\n",
+ req ? "" : "-not-required", libraryName.string());
} else if (tag == "receiver") {
withinReceiver = true;
receiverName = getAttribute(tree, NAME_ATTR, &error);
fprintf(stderr, "ERROR getting 'android:name' attribute for receiver: %s\n", error.string());
goto bail;
}
+ } else if (tag == "service") {
+ withinService = true;
+ serviceName = getAttribute(tree, NAME_ATTR, &error);
+
+ if (error != "") {
+ fprintf(stderr, "ERROR getting 'android:name' attribute for service: %s\n", error.string());
+ goto bail;
+ }
}
- } else if (depth == 5) {
- if (withinActivity) {
- if (tag == "action") {
- //printf("LOG: action tag\n");
- String8 action = getAttribute(tree, NAME_ATTR, &error);
- if (error != "") {
- fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string());
- goto bail;
- }
- if (action == "android.intent.action.MAIN") {
- isMainActivity = true;
- //printf("LOG: isMainActivity==true\n");
- }
- } else if (tag == "category") {
- String8 category = getAttribute(tree, NAME_ATTR, &error);
- if (error != "") {
- fprintf(stderr, "ERROR getting 'name' attribute: %s\n", error.string());
- goto bail;
- }
- if (category == "android.intent.category.LAUNCHER") {
- isLauncherActivity = true;
- //printf("LOG: isLauncherActivity==true\n");
- }
+ } else if ((depth == 4) && (tag == "intent-filter")) {
+ hasIntentFilter = true;
+ withinIntentFilter = true;
+ actMainActivity = actWidgetReceivers = actImeService = actWallpaperService = false;
+ } else if ((depth == 5) && withinIntentFilter){
+ String8 action;
+ if (tag == "action") {
+ action = getAttribute(tree, NAME_ATTR, &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n", error.string());
+ goto bail;
}
- } else if (withinReceiver) {
- if (tag == "action") {
- String8 action = getAttribute(tree, NAME_ATTR, &error);
- if (error != "") {
- fprintf(stderr, "ERROR getting 'android:name' attribute for receiver: %s\n", error.string());
- goto bail;
+ if (withinActivity) {
+ if (action == "android.intent.action.MAIN") {
+ isMainActivity = true;
+ actMainActivity = true;
}
+ } else if (withinReceiver) {
if (action == "android.appwidget.action.APPWIDGET_UPDATE") {
- const char *rName = getComponentName(pkg, receiverName);
- if (rName != NULL) {
- printf("gadget-receiver:'%s/%s'\n", pkg.string(), rName);
- }
+ actWidgetReceivers = true;
}
+ } else if (withinService) {
+ if (action == "android.view.InputMethod") {
+ actImeService = true;
+ } else if (action == "android.service.wallpaper.WallpaperService") {
+ actWallpaperService = true;
+ }
+ }
+ if (action == "android.intent.action.SEARCH") {
+ isSearchable = true;
}
}
- }
- if (depth < 2) {
- withinApplication = false;
- }
- if (depth < 3) {
- //if (withinActivity) printf("LOG: withinActivity==false\n");
- withinActivity = false;
- withinReceiver = false;
+ if (tag == "category") {
+ String8 category = getAttribute(tree, NAME_ATTR, &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR getting 'name' attribute: %s\n", error.string());
+ goto bail;
+ }
+ if (withinActivity) {
+ if (category == "android.intent.category.LAUNCHER") {
+ isLauncherActivity = true;
+ }
+ }
+ }
}
+ }
- if (depth < 5) {
- //if (isMainActivity) printf("LOG: isMainActivity==false\n");
- //if (isLauncherActivity) printf("LOG: isLauncherActivity==false\n");
- isMainActivity = false;
- isLauncherActivity = false;
- }
+ if (!specCameraFeature && hasCameraPermission) {
+ // For applications that have not explicitly stated their
+ // camera feature requirements, but have requested the camera
+ // permission, we are going to give them compatibility treatment
+ // of requiring the equivalent to original android devices.
+ printf("uses-feature:'android.hardware.camera'\n");
+ printf("uses-feature:'android.hardware.camera.autofocus'\n");
+ }
+
+ if (hasMainActivity) {
+ printf("main\n");
+ }
+ if (hasWidgetReceivers) {
+ printf("app-widget\n");
+ }
+ if (hasImeService) {
+ printf("ime\n");
+ }
+ if (hasWallpaperService) {
+ printf("wallpaper\n");
+ }
+ if (hasOtherActivities) {
+ printf("other-activities\n");
+ }
+ if (isSearchable) {
+ printf("search\n");
+ }
+ if (hasOtherReceivers) {
+ printf("other-receivers\n");
+ }
+ if (hasOtherServices) {
+ printf("other-services\n");
+ }
- if (withinActivity && isMainActivity && isLauncherActivity) {
- printf("launchable activity:");
- const char *aName = getComponentName(pkg, activityName);
- if (aName != NULL) {
- printf(" name='%s'", aName);
- }
- printf("label='%s' icon='%s'\n",
- activityLabel.string(),
- activityIcon.string());
- }
+ // Determine default values for any unspecified screen sizes,
+ // based on the target SDK of the package. As of 4 (donut)
+ // the screen size support was introduced, so all default to
+ // enabled.
+ if (smallScreen > 0) {
+ smallScreen = targetSdk >= 4 ? -1 : 0;
+ }
+ if (normalScreen > 0) {
+ normalScreen = -1;
+ }
+ if (largeScreen > 0) {
+ largeScreen = targetSdk >= 4 ? -1 : 0;
}
+ printf("supports-screens:");
+ if (smallScreen != 0) printf(" 'small'");
+ if (normalScreen != 0) printf(" 'normal'");
+ if (largeScreen != 0) printf(" 'large'");
+ printf("\n");
+
printf("locales:");
Vector<String8> locales;
res.getLocales(&locales);
- const size_t N = locales.size();
- for (size_t i=0; i<N; i++) {
+ const size_t NL = locales.size();
+ for (size_t i=0; i<NL; i++) {
const char* localeStr = locales[i].string();
if (localeStr == NULL || strlen(localeStr) == 0) {
localeStr = "--_--";
printf(" '%s'", localeStr);
}
printf("\n");
+
+ Vector<ResTable_config> configs;
+ res.getConfigurations(&configs);
+ SortedVector<int> densities;
+ const size_t NC = configs.size();
+ for (size_t i=0; i<NC; i++) {
+ int dens = configs[i].density;
+ if (dens == 0) dens = 160;
+ densities.add(dens);
+ }
+
+ printf("densities:");
+ const size_t ND = densities.size();
+ for (size_t i=0; i<ND; i++) {
+ printf(" '%d'", densities[i]);
+ }
+ printf("\n");
+
+ AssetDir* dir = assets.openNonAssetDir(assetsCookie, "lib");
+ if (dir != NULL) {
+ if (dir->getFileCount() > 0) {
+ printf("native-code:");
+ for (size_t i=0; i<dir->getFileCount(); i++) {
+ printf(" '%s'", dir->getFileName(i).string());
+ }
+ printf("\n");
+ }
+ delete dir;
+ }
} else if (strcmp("configurations", option) == 0) {
Vector<ResTable_config> configs;
res.getConfigurations(&configs);
}
}
+ // Write out the ProGuard file
+ err = writeProguardFile(bundle, assets);
+ if (err < 0) {
+ goto bail;
+ }
+
// Write the apk
if (outputAPKFile) {
err = writeAPK(bundle, assets, String8(outputAPKFile));