summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/utils/ResourceTypes.h2
-rw-r--r--libs/utils/ResourceTypes.cpp87
-rw-r--r--services/java/com/android/server/BackupManagerService.java49
-rw-r--r--services/java/com/android/server/PackageManagerBackupAgent.java69
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/HardwareServicePermissionTest.java134
-rw-r--r--tools/aapt/Bundle.h4
-rw-r--r--tools/aapt/Command.cpp27
-rw-r--r--tools/aapt/Main.cpp6
8 files changed, 326 insertions, 52 deletions
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index 9b8c302..68f9233 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -1781,7 +1781,7 @@ public:
void getLocales(Vector<String8>* locales) const;
#ifndef HAVE_ANDROID_OS
- void print() const;
+ void print(bool inclValues) const;
#endif
private:
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 3d12dca..69d47f0 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -3830,9 +3830,45 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
#define CHAR16_ARRAY_EQ(constant, var, len) \
((len == (sizeof(constant)/sizeof(constant[0]))) && (0 == memcmp((var), (constant), (len))))
-void ResTable::print() const
+void print_complex(uint32_t complex, bool isFraction)
+{
+ const float MANTISSA_MULT =
+ 1.0f / (1<<Res_value::COMPLEX_MANTISSA_SHIFT);
+ const float RADIX_MULTS[] = {
+ 1.0f*MANTISSA_MULT, 1.0f/(1<<7)*MANTISSA_MULT,
+ 1.0f/(1<<15)*MANTISSA_MULT, 1.0f/(1<<23)*MANTISSA_MULT
+ };
+
+ float value = (complex&(Res_value::COMPLEX_MANTISSA_MASK
+ <<Res_value::COMPLEX_MANTISSA_SHIFT))
+ * RADIX_MULTS[(complex>>Res_value::COMPLEX_RADIX_SHIFT)
+ & Res_value::COMPLEX_RADIX_MASK];
+ printf("%f", value);
+
+ if (isFraction) {
+ switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
+ case Res_value::COMPLEX_UNIT_PX: printf("px"); break;
+ case Res_value::COMPLEX_UNIT_DIP: printf("dp"); break;
+ case Res_value::COMPLEX_UNIT_SP: printf("sp"); break;
+ case Res_value::COMPLEX_UNIT_PT: printf("pt"); break;
+ case Res_value::COMPLEX_UNIT_IN: printf("in"); break;
+ case Res_value::COMPLEX_UNIT_MM: printf("mm"); break;
+ default: printf(" (unknown unit)"); break;
+ }
+ } else {
+ switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
+ case Res_value::COMPLEX_UNIT_FRACTION: printf("%%"); break;
+ case Res_value::COMPLEX_UNIT_FRACTION_PARENT: printf("%%p"); break;
+ default: printf(" (unknown unit)"); break;
+ }
+ }
+}
+
+void ResTable::print(bool inclValues) const
{
- printf("mError=0x%x (%s)\n", mError, strerror(mError));
+ if (mError != 0) {
+ printf("mError=0x%x (%s)\n", mError, strerror(mError));
+ }
#if 0
printf("mParams=%c%c-%c%c,\n",
mParams.language[0], mParams.language[1],
@@ -3947,6 +3983,8 @@ void ResTable::print() const
(void*)(entriesStart + thisOffset));
continue;
}
+
+ const Res_value* value = NULL;
if ((dtohs(ent->flags)&ResTable_entry::FLAG_COMPLEX) != 0) {
printf("<bag>");
} else {
@@ -3962,7 +4000,7 @@ void ResTable::print() const
continue;
}
- const Res_value* value = (const Res_value*)
+ value = (const Res_value*)
(((const uint8_t*)ent) + esize);
printf("t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)",
(int)value->dataType, (int)dtohl(value->data),
@@ -3973,6 +4011,49 @@ void ResTable::print() const
printf(" (PUBLIC)");
}
printf("\n");
+
+ if (inclValues) {
+ if (value != NULL) {
+ printf(" ");
+ if (value->dataType == Res_value::TYPE_NULL) {
+ printf("(null)\n");
+ } else if (value->dataType == Res_value::TYPE_REFERENCE) {
+ printf("(reference) 0x%08x\n", value->data);
+ } else if (value->dataType == Res_value::TYPE_ATTRIBUTE) {
+ printf("(attribute) 0x%08x\n", value->data);
+ } else if (value->dataType == Res_value::TYPE_STRING) {
+ size_t len;
+ const char16_t* str = pkg->header->values.stringAt(
+ value->data, &len);
+ if (str == NULL) {
+ printf("(string) null\n");
+ } else {
+ printf("(string) \"%s\"\n",
+ String8(str, len).string());
+ }
+ } else if (value->dataType == Res_value::TYPE_FLOAT) {
+ printf("(float) %g\n", *(const float*)&value->data);
+ } else if (value->dataType == Res_value::TYPE_DIMENSION) {
+ printf("(dimension) ");
+ print_complex(value->data, false);
+ printf("\n");
+ } else if (value->dataType == Res_value::TYPE_FRACTION) {
+ printf("(fraction) ");
+ print_complex(value->data, true);
+ printf("\n");
+ } else if (value->dataType >= Res_value::TYPE_FIRST_COLOR_INT
+ || value->dataType <= Res_value::TYPE_LAST_COLOR_INT) {
+ printf("(color) #%08x\n", value->data);
+ } else if (value->dataType == Res_value::TYPE_INT_BOOLEAN) {
+ printf("(boolean) %s\n", value->data ? "true" : "false");
+ } else if (value->dataType >= Res_value::TYPE_FIRST_INT
+ || value->dataType <= Res_value::TYPE_LAST_INT) {
+ printf("(int) 0x%08x or %d\n", value->data, value->data);
+ } else {
+ printf("(unknown type)\n");
+ }
+ }
+ }
}
}
}
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index fa88111..75e0e64 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -54,6 +54,7 @@ import com.android.internal.backup.LocalTransport;
import com.android.internal.backup.IBackupTransport;
import com.android.server.PackageManagerBackupAgent;
+import com.android.server.PackageManagerBackupAgent.Metadata;
import java.io.EOFException;
import java.io.File;
@@ -111,9 +112,8 @@ class BackupManagerService extends IBackupManager.Stub {
// Do we need to back up the package manager metadata on the next pass?
private boolean mDoPackageManager;
private static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
- // Backups that we have started. These are separate to prevent starvation
- // if an app keeps re-enqueuing itself.
- private ArrayList<BackupRequest> mBackupQueue;
+
+ // locking around the pending-backup management
private final Object mQueueLock = new Object();
// The thread performing the sequence of queued backups binds to each app's agent
@@ -296,6 +296,7 @@ class BackupManagerService extends IBackupManager.Stub {
}
// snapshot the pending-backup set and work on that
+ ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>();
File oldJournal = mJournal;
synchronized (mQueueLock) {
if (mPendingBackups.size() == 0) {
@@ -303,13 +304,11 @@ class BackupManagerService extends IBackupManager.Stub {
break;
}
- if (mBackupQueue == null) {
- mBackupQueue = new ArrayList<BackupRequest>();
- for (BackupRequest b: mPendingBackups.values()) {
- mBackupQueue.add(b);
- }
- mPendingBackups = new HashMap<ApplicationInfo,BackupRequest>();
+ for (BackupRequest b: mPendingBackups.values()) {
+ queue.add(b);
}
+ Log.v(TAG, "clearing pending backups");
+ mPendingBackups.clear();
// Start a new backup-queue journal file too
if (mJournalStream != null) {
@@ -328,7 +327,7 @@ class BackupManagerService extends IBackupManager.Stub {
// at next boot and the journaled requests fulfilled.
}
- (new PerformBackupThread(transport, mBackupQueue, oldJournal)).start();
+ (new PerformBackupThread(transport, queue, oldJournal)).start();
break;
}
@@ -759,6 +758,8 @@ class BackupManagerService extends IBackupManager.Stub {
private boolean signaturesMatch(Signature[] storedSigs, Signature[] deviceSigs) {
// Allow unsigned apps, but not signed on one device and unsigned on the other
// !!! TODO: is this the right policy?
+ if (DEBUG) Log.v(TAG, "signaturesMatch(): stored=" + storedSigs
+ + " device=" + deviceSigs);
if ((storedSigs == null || storedSigs.length == 0)
&& (deviceSigs == null || deviceSigs.length == 0)) {
return true;
@@ -800,6 +801,7 @@ class BackupManagerService extends IBackupManager.Stub {
@Override
public void run() {
+ if (DEBUG) Log.v(TAG, "Beginning restore process");
/**
* Restore sequence:
*
@@ -847,13 +849,19 @@ class BackupManagerService extends IBackupManager.Stub {
PackageInfo app = isRestorable(pkg);
if (app != null) {
// Validate against the backed-up signature block, too
- Signature[] storedSigs
- = pmAgent.getRestoredSignatures(app.packageName);
- // !!! TODO: check app version here as well
- if (signaturesMatch(storedSigs, app.signatures)) {
- appsToRestore.add(app);
+ Metadata info = pmAgent.getRestoredMetadata(app.packageName);
+ if (app.versionCode >= info.versionCode) {
+ if (DEBUG) Log.v(TAG, "Restore version " + info.versionCode
+ + " compatible with app version " + app.versionCode);
+ if (signaturesMatch(info.signatures, app.signatures)) {
+ appsToRestore.add(app);
+ } else {
+ Log.w(TAG, "Sig mismatch restoring " + app.packageName);
+ }
} else {
- Log.w(TAG, "Sig mismatch on restore of " + app.packageName);
+ Log.i(TAG, "Restore set for " + app.packageName
+ + " is too new [" + info.versionCode
+ + "] for installed app version " + app.versionCode);
}
}
}
@@ -1202,11 +1210,10 @@ class BackupManagerService extends IBackupManager.Stub {
pw.println(app.toString());
}
}
- pw.println("Pending:");
- Iterator<BackupRequest> br = mPendingBackups.values().iterator();
- while (br.hasNext()) {
- pw.print(" ");
- pw.println(br);
+ pw.println("Pending: " + mPendingBackups.size());
+ for (BackupRequest req : mPendingBackups.values()) {
+ pw.print(" ");
+ pw.println(req);
}
}
}
diff --git a/services/java/com/android/server/PackageManagerBackupAgent.java b/services/java/com/android/server/PackageManagerBackupAgent.java
index 6bd32a0..cc84430 100644
--- a/services/java/com/android/server/PackageManagerBackupAgent.java
+++ b/services/java/com/android/server/PackageManagerBackupAgent.java
@@ -40,9 +40,6 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-// !!!TODO: take this out
-import java.util.zip.CRC32;
-
/**
* We back up the signatures of each package so that during a system restore,
* we can verify that the app whose data we think we have matches the app
@@ -57,7 +54,17 @@ public class PackageManagerBackupAgent extends BackupAgent {
private List<ApplicationInfo> mAllApps;
private PackageManager mPackageManager;
- private HashMap<String, Signature[]> mRestoredSignatures;
+ private HashMap<String, Metadata> mRestoredSignatures;
+
+ public class Metadata {
+ public int versionCode;
+ public Signature[] signatures;
+
+ Metadata(int version, Signature[] sigs) {
+ versionCode = version;
+ signatures = sigs;
+ }
+ }
// We're constructed with the set of applications that are participating
// in backup. This set changes as apps are installed & removed.
@@ -67,7 +74,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
mRestoredSignatures = null;
}
- public Signature[] getRestoredSignatures(String packageName) {
+ public Metadata getRestoredMetadata(String packageName) {
if (mRestoredSignatures == null) {
return null;
}
@@ -83,6 +90,9 @@ public class PackageManagerBackupAgent extends BackupAgent {
// For each app we have on device, see if we've backed it up yet. If not,
// write its signature block to the output, keyed on the package name.
+ if (DEBUG) Log.v(TAG, "onBackup()");
+ ByteArrayOutputStream bufStream = new ByteArrayOutputStream(); // we'll reuse these
+ DataOutputStream outWriter = new DataOutputStream(bufStream);
for (ApplicationInfo app : mAllApps) {
String packName = app.packageName;
if (!existing.contains(packName)) {
@@ -90,16 +100,27 @@ public class PackageManagerBackupAgent extends BackupAgent {
try {
PackageInfo info = mPackageManager.getPackageInfo(packName,
PackageManager.GET_SIGNATURES);
- // build a byte array out of the signature list
+ /*
+ * Metadata for each package:
+ *
+ * int version -- [4] the package's versionCode
+ * byte[] signatures -- [len] flattened Signature[] of the package
+ */
+
+ // marshall the version code in a canonical form
+ bufStream.reset();
+ outWriter.writeInt(info.versionCode);
+ byte[] versionBuf = bufStream.toByteArray();
+
byte[] sigs = flattenSignatureArray(info.signatures);
-// !!! TODO: take out this debugging
+
+ // !!! TODO: take out this debugging
if (DEBUG) {
- CRC32 crc = new CRC32();
- crc.update(sigs);
- Log.i(TAG, "+ flat sig array for " + packName + " : "
- + crc.getValue());
+ Log.v(TAG, "+ metadata for " + packName + " version=" + info.versionCode);
}
- data.writeEntityHeader(packName, sigs.length);
+ // Now we can write the backup entity for this package
+ data.writeEntityHeader(packName, versionBuf.length + sigs.length);
+ data.writeEntityData(versionBuf, versionBuf.length);
data.writeEntityData(sigs, sigs.length);
} catch (NameNotFoundException e) {
// Weird; we just found it, and now are told it doesn't exist.
@@ -113,6 +134,8 @@ public class PackageManagerBackupAgent extends BackupAgent {
} else {
// We've already backed up this app. Remove it from the set so
// we can tell at the end what has disappeared from the device.
+ // !!! TODO: take out the debugging message
+ if (DEBUG) Log.v(TAG, "= already backed up metadata for " + packName);
if (!existing.remove(packName)) {
Log.d(TAG, "*** failed to remove " + packName + " from package set!");
}
@@ -123,6 +146,8 @@ public class PackageManagerBackupAgent extends BackupAgent {
// mentioned in the saved state file, but appear to no longer be present
// on the device. Write a deletion entity for them.
for (String app : existing) {
+ // !!! TODO: take out this msg
+ if (DEBUG) Log.v(TAG, "- removing metadata for deleted pkg " + app);
try {
data.writeEntityHeader(app, -1);
} catch (IOException e) {
@@ -141,27 +166,29 @@ public class PackageManagerBackupAgent extends BackupAgent {
public void onRestore(BackupDataInput data, ParcelFileDescriptor newState)
throws IOException {
List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>();
- HashMap<String, Signature[]> sigMap = new HashMap<String, Signature[]>();
+ HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>();
while (data.readNextHeader()) {
int dataSize = data.getDataSize();
byte[] buf = new byte[dataSize];
data.readEntityData(buf, 0, dataSize);
- Signature[] sigs = unflattenSignatureArray(buf);
+ ByteArrayInputStream bufStream = new ByteArrayInputStream(buf);
+ DataInputStream in = new DataInputStream(bufStream);
+ int versionCode = in.readInt();
+
+ Signature[] sigs = unflattenSignatureArray(in);
String pkg = data.getKey();
// !!! TODO: take out this debugging
if (DEBUG) {
- CRC32 crc = new CRC32();
- crc.update(buf);
- Log.i(TAG, "- unflat sig array for " + pkg + " : "
- + crc.getValue());
+ Log.i(TAG, "+ restored metadata for " + pkg
+ + " versionCode=" + versionCode + " sigs=" + sigs);
}
ApplicationInfo app = new ApplicationInfo();
app.packageName = pkg;
restoredApps.add(app);
- sigMap.put(pkg, sigs);
+ sigMap.put(pkg, new Metadata(versionCode, sigs));
}
mRestoredSignatures = sigMap;
@@ -193,9 +220,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
return outBuf.toByteArray();
}
- private Signature[] unflattenSignatureArray(byte[] buffer) {
- ByteArrayInputStream inBufStream = new ByteArrayInputStream(buffer);
- DataInputStream in = new DataInputStream(inBufStream);
+ private Signature[] unflattenSignatureArray(/*byte[] buffer*/ DataInputStream in) {
Signature[] sigs = null;
try {
diff --git a/tests/permission/src/com/android/framework/permission/tests/HardwareServicePermissionTest.java b/tests/permission/src/com/android/framework/permission/tests/HardwareServicePermissionTest.java
new file mode 100644
index 0000000..dc6860a
--- /dev/null
+++ b/tests/permission/src/com/android/framework/permission/tests/HardwareServicePermissionTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.framework.permission.tests;
+
+import junit.framework.TestCase;
+
+import android.os.Binder;
+import android.os.IHardwareService;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+/**
+ * Verify that Hardware apis cannot be called without required permissions.
+ */
+public class HardwareServicePermissionTest extends TestCase {
+
+ private IHardwareService mHardwareService;
+
+ @Override
+ protected void setUp() throws Exception {
+ mHardwareService = IHardwareService.Stub.asInterface(
+ ServiceManager.getService("hardware"));
+ }
+
+ /**
+ * Test that calling {@link android.os.IHardwareService#vibrate(long)} requires permissions.
+ * <p>Tests permission:
+ * {@link android.Manifest.permission#VIBRATE}
+ * @throws RemoteException
+ */
+ public void testVibrate() throws RemoteException {
+ try {
+ mHardwareService.vibrate(2000);
+ fail("vibrate did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Test that calling {@link android.os.IHardwareService#vibratePattern(long[],
+ * int, android.os.IBinder)} requires permissions.
+ * <p>Tests permission:
+ * {@link android.Manifest.permission#VIBRATE}
+ * @throws RemoteException
+ */
+ public void testVibratePattern() throws RemoteException {
+ try {
+ mHardwareService.vibratePattern(new long[] {0}, 0, new Binder());
+ fail("vibratePattern did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Test that calling {@link android.os.IHardwareService#cancelVibrate()} requires permissions.
+ * <p>Tests permission:
+ * {@link android.Manifest.permission#VIBRATE}
+ * @throws RemoteException
+ */
+ public void testCancelVibrate() throws RemoteException {
+ try {
+ mHardwareService.cancelVibrate();
+ fail("cancelVibrate did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Test that calling {@link android.os.IHardwareService#setFlashlightEnabled(boolean)}
+ * requires permissions.
+ * <p>Tests permissions:
+ * {@link android.Manifest.permission#HARDWARE_TEST}
+ * {@link android.Manifest.permission#FLASHLIGHT}
+ * @throws RemoteException
+ */
+ public void testSetFlashlightEnabled() throws RemoteException {
+ try {
+ mHardwareService.setFlashlightEnabled(true);
+ fail("setFlashlightEnabled did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Test that calling {@link android.os.IHardwareService#enableCameraFlash(int)} requires
+ * permissions.
+ * <p>Tests permission:
+ * {@link android.Manifest.permission#HARDWARE_TEST}
+ * {@link android.Manifest.permission#CAMERA}
+ * @throws RemoteException
+ */
+ public void testEnableCameraFlash() throws RemoteException {
+ try {
+ mHardwareService.enableCameraFlash(100);
+ fail("enableCameraFlash did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Test that calling {@link android.os.IHardwareService#setBacklights(int)} requires
+ * permissions.
+ * <p>Tests permission:
+ * {@link android.Manifest.permission#HARDWARE_TEST}
+ * @throws RemoteException
+ */
+ public void testSetBacklights() throws RemoteException {
+ try {
+ mHardwareService.setBacklights(0);
+ fail("setBacklights did not throw SecurityException as expected");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+}
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index 2eb7a1d..a6fedf3 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -34,6 +34,7 @@ public:
mForce(false), mGrayscaleTolerance(0), mMakePackageDirs(false),
mUpdate(false), mExtending(false),
mRequireLocalization(false), mPseudolocalize(false),
+ mValues(false),
mCompressionMethod(0), mOutputAPKFile(NULL),
mAssetSourceDir(NULL),
mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
@@ -72,6 +73,8 @@ public:
void setRequireLocalization(bool val) { mRequireLocalization = val; }
bool getPseudolocalize(void) const { return mPseudolocalize; }
void setPseudolocalize(bool val) { mPseudolocalize = val; }
+ bool getValues(void) const { return mValues; }
+ void setValues(bool val) { mValues = val; }
int getCompressionMethod(void) const { return mCompressionMethod; }
void setCompressionMethod(int val) { mCompressionMethod = val; }
const char* getOutputAPKFile() const { return mOutputAPKFile; }
@@ -151,6 +154,7 @@ private:
bool mExtending;
bool mRequireLocalization;
bool mPseudolocalize;
+ bool mValues;
int mCompressionMethod;
const char* mOutputAPKFile;
const char* mAssetSourceDir;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index dc91a48..503f661 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -196,7 +196,7 @@ int doList(Bundle* bundle)
printf("\nNo resource table found.\n");
} else {
printf("\nResource table:\n");
- res.print();
+ res.print(false);
}
Asset* manifestAsset = assets.openNonAsset("AndroidManifest.xml",
@@ -380,7 +380,7 @@ int doDump(Bundle* bundle)
}
if (strcmp("resources", option) == 0) {
- res.print();
+ res.print(bundle->getValues());
} else if (strcmp("xmltree", option) == 0) {
if (bundle->getFileSpecCount() < 3) {
@@ -732,11 +732,12 @@ int doDump(Bundle* bundle)
activityIcon.string());
}
}
+
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 = "--_--";
@@ -744,6 +745,24 @@ int doDump(Bundle* bundle)
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) {
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 8bf2b07..12a0445 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -45,7 +45,7 @@ void usage(void)
" %s l[ist] [-v] [-a] file.{zip,jar,apk}\n"
" List contents of Zip-compatible archive.\n\n", gProgName);
fprintf(stderr,
- " %s d[ump] WHAT file.{apk} [asset [asset ...]]\n"
+ " %s d[ump] [--values] WHAT file.{apk} [asset [asset ...]]\n"
" badging Print the label and icon for the app declared in APK.\n"
" permissions Print the permissions from the APK.\n"
" resources Print the resource table from the APK.\n"
@@ -123,6 +123,8 @@ void usage(void)
" inserts android:targetSdkVersion in to manifest.\n"
" --max-sdk-version\n"
" inserts android:maxSdkVersion in to manifest.\n"
+ " --values\n"
+ " when used with \"dump resources\" also includes resource values.\n"
" --version-code\n"
" inserts android:versionCode in to manifest.\n"
" --version-name\n"
@@ -396,6 +398,8 @@ int main(int argc, char* const argv[])
goto bail;
}
bundle.setVersionName(argv[0]);
+ } else if (strcmp(cp, "-values") == 0) {
+ bundle.setValues(true);
} else {
fprintf(stderr, "ERROR: Unknown option '-%s'\n", cp);
wantUsage = true;