summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2009-06-30 13:27:30 -0700
committerDianne Hackborn <hackbod@google.com>2009-06-30 13:27:30 -0700
commitde7faf658cd40d34c08a98b39477055da8e19172 (patch)
tree8450b4d75fbe22a3fed25867c1d53a059c10d664
parentbd9aa793b19f7aa529ca4123492f8940b96486b8 (diff)
downloadframeworks_base-de7faf658cd40d34c08a98b39477055da8e19172.zip
frameworks_base-de7faf658cd40d34c08a98b39477055da8e19172.tar.gz
frameworks_base-de7faf658cd40d34c08a98b39477055da8e19172.tar.bz2
Fix issue #1673793: Theme styles don't apply.
It turns out this was not a problem in the resource code at all. Rather, the system process has a cache of pre-loaded attributes it uses to avoid continually reloading things as it needs them. Well it turns out this cache wasn't flushed after a package was uninstalled or a configuration changed, so you could re-install an app where you change its style resources so its theme now points to one that is inconsistent in the cache. This is mostly a problem for developers, where they continually install new versions of an app where resources have changed. This could possibly show up when updating an app on a normal phone, although the problem would eventually correct itself since this cache uses weak references. Anyway, the cache is now reworked to be flushed appropriately. This change also includes an update to aapt to be able to dump the contents of bags in resources.
-rw-r--r--include/utils/ResourceTypes.h4
-rw-r--r--libs/utils/ResourceTypes.cpp134
-rw-r--r--services/java/com/android/server/AttributeCache.java114
-rw-r--r--services/java/com/android/server/PackageManagerService.java1
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java11
5 files changed, 157 insertions, 107 deletions
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index 5c41ead..eb4151a 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -1441,7 +1441,7 @@ struct ResTable_type
* This is the beginning of information about an entry in the resource
* table. It holds the reference to the name of this entry, and is
* immediately followed by one of:
- * * A Res_value structures, if FLAG_COMPLEX is -not- set.
+ * * A Res_value structure, if FLAG_COMPLEX is -not- set.
* * An array of ResTable_map structures, if FLAG_COMPLEX is set.
* These supply a set of name/value mappings of data.
*/
@@ -1843,6 +1843,8 @@ private:
status_t parsePackage(
const ResTable_package* const pkg, const Header* const header);
+ void print_value(const Package* pkg, const Res_value& value) const;
+
mutable Mutex mLock;
status_t mError;
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 7a33220..4a5063a 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -3845,7 +3845,7 @@ void print_complex(uint32_t complex, bool isFraction)
& Res_value::COMPLEX_RADIX_MASK];
printf("%f", value);
- if (isFraction) {
+ 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;
@@ -3864,6 +3864,49 @@ void print_complex(uint32_t complex, bool isFraction)
}
}
+void ResTable::print_value(const Package* pkg, const Res_value& value) const
+{
+ 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) t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)\n",
+ (int)value.dataType, (int)value.data,
+ (int)value.size, (int)value.res0);
+ }
+}
+
void ResTable::print(bool inclValues) const
{
if (mError != 0) {
@@ -3985,27 +4028,31 @@ void ResTable::print(bool inclValues) const
continue;
}
- const Res_value* value = NULL;
+ uint16_t esize = dtohs(ent->size);
+ if ((esize&0x3) != 0) {
+ printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void*)esize);
+ continue;
+ }
+ if ((thisOffset+esize) > typeSize) {
+ printf("ResTable_entry OUT OF BOUNDS: %p+%p+%p (size is %p)\n",
+ (void*)entriesStart, (void*)thisOffset,
+ (void*)esize, (void*)typeSize);
+ continue;
+ }
+
+ const Res_value* valuePtr = NULL;
+ const ResTable_map_entry* bagPtr = NULL;
+ Res_value value;
if ((dtohs(ent->flags)&ResTable_entry::FLAG_COMPLEX) != 0) {
printf("<bag>");
+ bagPtr = (const ResTable_map_entry*)ent;
} else {
- uint16_t esize = dtohs(ent->size);
- if ((esize&0x3) != 0) {
- printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void*)esize);
- continue;
- }
- if ((thisOffset+esize) > typeSize) {
- printf("ResTable_entry OUT OF BOUNDS: %p+%p+%p (size is %p)\n",
- (void*)entriesStart, (void*)thisOffset,
- (void*)esize, (void*)typeSize);
- continue;
- }
-
- value = (const Res_value*)
+ valuePtr = (const Res_value*)
(((const uint8_t*)ent) + esize);
+ value.copyFrom_dtoh(*valuePtr);
printf("t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)",
- (int)value->dataType, (int)dtohl(value->data),
- (int)dtohs(value->size), (int)value->res0);
+ (int)value.dataType, (int)value.data,
+ (int)value.size, (int)value.res0);
}
if ((dtohs(ent->flags)&ResTable_entry::FLAG_PUBLIC) != 0) {
@@ -4014,44 +4061,23 @@ void ResTable::print(bool inclValues) const
printf("\n");
if (inclValues) {
- if (value != NULL) {
+ if (valuePtr != 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");
+ print_value(pkg, value);
+ } else if (bagPtr != NULL) {
+ const int N = dtohl(bagPtr->count);
+ const ResTable_map* mapPtr = (const ResTable_map*)
+ (((const uint8_t*)ent) + esize);
+ printf(" Parent=0x%08x, Count=%d\n",
+ dtohl(bagPtr->parent.ident), N);
+ for (int i=0; i<N; i++) {
+ printf(" #%i (Key=0x%08x): ",
+ i, dtohl(mapPtr->name.ident));
+ value.copyFrom_dtoh(mapPtr->value);
+ print_value(pkg, value);
+ const size_t size = dtohs(mapPtr->value.size);
+ mapPtr = (ResTable_map*)(((const uint8_t*)mapPtr)
+ + size + sizeof(*mapPtr)-sizeof(mapPtr->value));
}
}
}
diff --git a/services/java/com/android/server/AttributeCache.java b/services/java/com/android/server/AttributeCache.java
index 459ae52..81378dc 100644
--- a/services/java/com/android/server/AttributeCache.java
+++ b/services/java/com/android/server/AttributeCache.java
@@ -17,56 +17,36 @@
package com.android.server;
-import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.Intent;
-import android.content.BroadcastReceiver;
+import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.provider.Settings;
-import android.util.Config;
-import android.util.Log;
+import android.util.SparseArray;
+import java.util.HashMap;
import java.util.WeakHashMap;
-public final class AttributeCache extends BroadcastReceiver {
+/**
+ * TODO: This should be better integrated into the system so it doesn't need
+ * special calls from the activity manager to clear it.
+ */
+public final class AttributeCache {
private static AttributeCache sInstance = null;
private final Context mContext;
- private final WeakHashMap<Key, Entry> mMap =
- new WeakHashMap<Key, Entry>();
- private final WeakHashMap<String, Context> mContexts =
- new WeakHashMap<String, Context>();
+ private final WeakHashMap<String, Package> mPackages =
+ new WeakHashMap<String, Package>();
+ private final Configuration mConfiguration = new Configuration();
- final static class Key {
- public final String packageName;
- public final int resId;
- public final int[] styleable;
-
- public Key(String inPackageName, int inResId, int[] inStyleable) {
- packageName = inPackageName;
- resId = inResId;
- styleable = inStyleable;
- }
+ public final static class Package {
+ public final Context context;
+ private final SparseArray<HashMap<int[], Entry>> mMap
+ = new SparseArray<HashMap<int[], Entry>>();
- @Override public boolean equals(Object obj) {
- try {
- if (obj != null) {
- Key other = (Key)obj;
- return packageName.equals(other.packageName)
- && resId == other.resId
- && styleable == other.styleable;
- }
- } catch (ClassCastException e) {
- }
- return false;
- }
-
- @Override public int hashCode() {
- return packageName.hashCode() + resId;
+ public Package(Context c) {
+ context = c;
}
}
@@ -94,36 +74,68 @@ public final class AttributeCache extends BroadcastReceiver {
mContext = context;
}
- public Entry get(String packageName, int resId, int[] styleable) {
+ public void removePackage(String packageName) {
synchronized (this) {
- Key key = new Key(packageName, resId, styleable);
- Entry ent = mMap.get(key);
- if (ent != null) {
- return ent;
+ mPackages.remove(packageName);
+ }
+ }
+
+ public void updateConfiguration(Configuration config) {
+ synchronized (this) {
+ int changes = mConfiguration.updateFrom(config);
+ if ((changes & ~(ActivityInfo.CONFIG_FONT_SCALE |
+ ActivityInfo.CONFIG_KEYBOARD_HIDDEN |
+ ActivityInfo.CONFIG_ORIENTATION)) != 0) {
+ // The configurations being masked out are ones that commonly
+ // change so we don't want flushing the cache... all others
+ // will flush the cache.
+ mPackages.clear();
}
- Context context = mContexts.get(packageName);
- if (context == null) {
+ }
+ }
+
+ public Entry get(String packageName, int resId, int[] styleable) {
+ synchronized (this) {
+ Package pkg = mPackages.get(packageName);
+ HashMap<int[], Entry> map = null;
+ Entry ent = null;
+ if (pkg != null) {
+ map = pkg.mMap.get(resId);
+ if (map != null) {
+ ent = map.get(styleable);
+ if (ent != null) {
+ return ent;
+ }
+ }
+ } else {
+ Context context;
try {
context = mContext.createPackageContext(packageName, 0);
if (context == null) {
return null;
}
- mContexts.put(packageName, context);
} catch (PackageManager.NameNotFoundException e) {
return null;
}
+ pkg = new Package(context);
+ mPackages.put(packageName, pkg);
}
+
+ if (map == null) {
+ map = new HashMap<int[], Entry>();
+ pkg.mMap.put(resId, map);
+ }
+
try {
- ent = new Entry(context,
- context.obtainStyledAttributes(resId, styleable));
- mMap.put(key, ent);
+ ent = new Entry(pkg.context,
+ pkg.context.obtainStyledAttributes(resId, styleable));
+ map.put(styleable, ent);
} catch (Resources.NotFoundException e) {
return null;
}
+
return ent;
}
}
- @Override public void onReceive(Context context, Intent intent) {
- }
}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 972aa98..4ea2831 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -3292,6 +3292,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (extras != null) {
intent.putExtras(extras);
}
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
am.broadcastIntent(
null, intent,
null, null, 0, null, null, null, false, false);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 6d04b6b..f716571 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import com.android.internal.os.BatteryStatsImpl;
+import com.android.server.AttributeCache;
import com.android.server.IntentResolver;
import com.android.server.ProcessMap;
import com.android.server.ProcessStats;
@@ -61,7 +62,6 @@ import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.net.Uri;
-import android.os.BatteryStats;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
@@ -10715,6 +10715,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
uninstallPackageLocked(ssp,
intent.getIntExtra(Intent.EXTRA_UID, -1), false);
+ AttributeCache ac = AttributeCache.instance();
+ if (ac != null) {
+ ac.removePackage(ssp);
+ }
}
}
}
@@ -11765,6 +11769,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
null, false, false, MY_PID, Process.SYSTEM_UID);
+
+ AttributeCache ac = AttributeCache.instance();
+ if (ac != null) {
+ ac.updateConfiguration(mConfiguration);
+ }
}
}