use of android.util.LongSparseArray in project AndroidLife by CaMnter.
the class MonkeyPatcher method pruneResourceCache.
/**
* 如果 < 6.0 会删除
* ResourcesImpl 内的 mDrawableCache、mColorDrawableCache、mColorStateListCache 资源缓存
* 同时,如果还是 4.3 的话,会额外删除
* Resources 内的 sPreloadedDrawables、sPreloadedColorDrawables、sPreloadedColorStateLists
* 资源缓存
*
* @param resources ResourcesImpl or Resources
* @param fieldName 以上 field name
* @return 是否清空
*/
private static boolean pruneResourceCache(@NonNull Object resources, @NonNull String fieldName) {
try {
/**
* Step 1
*
* 从 ResourcesImpl or Resources 拿到对应的 fieldName 的 Field
*
* 当然,如果 ResourcesImpl 获取失败了,会 catch 。
* 然后直接 Resources.class.getDeclaredField(fieldName) 去拿 Field
*/
Class<?> resourcesClass = resources.getClass();
Field cacheField;
try {
cacheField = resourcesClass.getDeclaredField(fieldName);
} catch (NoSuchFieldException ignore) {
cacheField = Resources.class.getDeclaredField(fieldName);
}
cacheField.setAccessible(true);
Object cache = cacheField.get(resources);
/**
* Step 2
*
* 上面拿到的 Field
* 然后判断 Field 的类型:
*
* 1 如果 < 4.1,有两种选择:
* 1.1 如果属于 SparseArray 类型,直接 clear 清空,返回 true
* 1.2 如果 => 4.0 并且 属于 LongSparseArray,也是直接 clear 清空,返回 true
*
* 2 如果 4.1 < x < 6.0,有四种选择:
* 2.1 如果 Field 是 mColorStateListCache,并且属于 LongSparseArray,也是直接 clear 清空
* 2.2 如果 Field 的类型实现了 ArrayMap 的超类( Map ),然后反射调用 Resource clearDrawableCachesLocked 方法
* 2.3 如果 Field 是类型实现了 LongSparseArray 的超类 ( Cloneable ? ),然后反射调用 Resource clearDrawableCachesLocked 方法
* 注: 2.2 与 2.3 的区别在于 clearDrawableCachesLocked 的参数不一样,一个是 ArrayMap,一个是 LongSparseArray
*
* 2.4 如果 Field 是类型实现是 数组类型,并且数组的 class 类型( getComponentType ) 实现了 LongSparseArray 的超类 ( Cloneable ? )
* 然后强转为 LongSparseArray[] 类型,一个一个拿出 LongSparseArray,然后 clear
*
* 3. 如果 >= 6.0 ( 主要针对 Marshmallow: DrawableCache class )
* 反射拿到该 Field 的 onConfigurationChange 的方法并且调用
* 如果有就返回
* 如果没有的话,继续拿到父类,继续反射拿到 onConfigurationChange 的方法并且调用。直到调用过一次 onConfigurationChange 为止
*
* 4. 如果 1-3 内又没一个选择的话,那么就是没有做任何 删除资源缓存操作 or 删除资源缓存失败了
*/
// Find the class which defines the onConfigurationChange method
Class<?> type = cacheField.getType();
if (SDK_INT < JELLY_BEAN) {
if (cache instanceof SparseArray) {
((SparseArray) cache).clear();
return true;
} else if (SDK_INT >= ICE_CREAM_SANDWICH && cache instanceof LongSparseArray) {
// LongSparseArray has API level 16 but was private (and available inside
// the framework) in 15 and is used for this cache.
// noinspection AndroidLintNewApi
((LongSparseArray) cache).clear();
return true;
}
} else if (SDK_INT < M) {
// JellyBean, KitKat, Lollipop
if ("mColorStateListCache".equals(fieldName)) {
// this field
if (cache instanceof LongSparseArray) {
// noinspection AndroidLintNewApi
((LongSparseArray) cache).clear();
}
} else if (type.isAssignableFrom(ArrayMap.class)) {
Method clearArrayMap = Resources.class.getDeclaredMethod("clearDrawableCachesLocked", ArrayMap.class, Integer.TYPE);
clearArrayMap.setAccessible(true);
clearArrayMap.invoke(resources, cache, -1);
return true;
} else if (type.isAssignableFrom(LongSparseArray.class)) {
try {
Method clearSparseMap = Resources.class.getDeclaredMethod("clearDrawableCachesLocked", LongSparseArray.class, Integer.TYPE);
clearSparseMap.setAccessible(true);
clearSparseMap.invoke(resources, cache, -1);
return true;
} catch (NoSuchMethodException e) {
if (cache instanceof LongSparseArray) {
// noinspection AndroidLintNewApi
((LongSparseArray) cache).clear();
return true;
}
}
} else if (type.isArray() && type.getComponentType().isAssignableFrom(LongSparseArray.class)) {
LongSparseArray[] arrays = (LongSparseArray[]) cache;
for (LongSparseArray array : arrays) {
if (array != null) {
// noinspection AndroidLintNewApi
array.clear();
}
}
return true;
}
} else {
// Marshmallow: DrawableCache class
while (type != null) {
try {
Method configChangeMethod = type.getDeclaredMethod("onConfigurationChange", Integer.TYPE);
configChangeMethod.setAccessible(true);
configChangeMethod.invoke(cache, -1);
return true;
} catch (Throwable ignore) {
}
type = type.getSuperclass();
}
}
} catch (Throwable ignore) {
// Not logging these; while there is some checking of SDK_INT here to avoid
// doing a lot of unnecessary field lookups, it's not entirely accurate and
// errs on the side of caution (since different devices may have picked up
// different snapshots of the framework); therefore, it's normal for this
// to attempt to look up a field for a cache that isn't there; only if it's
// really there will it continue to flush that particular cache.
}
return false;
}
use of android.util.LongSparseArray in project Douya by DreaminginCodeZH.
the class ResourcesFlusher method flushThemedResourceCache.
@MainThread
@RequiresApi(Build.VERSION_CODES.M)
@SuppressLint("PrivateApi")
private static void flushThemedResourceCache(@NonNull Object themedResourceCache) {
if (!sThemedResourceCacheClassInitialized) {
try {
sThemedResourceCacheClass = Class.forName("android.content.res.ThemedResourceCache");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
sThemedResourceCacheClassInitialized = true;
}
if (sThemedResourceCacheClass == null) {
return;
}
if (!sThemedResourceCacheMThemedEntriesFieldInitialized) {
try {
sThemedResourceCacheMThemedEntriesField = sThemedResourceCacheClass.getDeclaredField("mThemedEntries");
sThemedResourceCacheMThemedEntriesField.setAccessible(true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
sThemedResourceCacheMThemedEntriesFieldInitialized = true;
}
if (sThemedResourceCacheMThemedEntriesField != null) {
ArrayMap themedEntries = null;
try {
themedEntries = (ArrayMap) sThemedResourceCacheMThemedEntriesField.get(themedResourceCache);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if (themedEntries != null) {
themedEntries.clear();
}
}
if (!sThemedResourceCacheMUnthemedEntriesFieldInitialized) {
try {
sThemedResourceCacheMUnthemedEntriesField = sThemedResourceCacheClass.getDeclaredField("mUnthemedEntries");
sThemedResourceCacheMUnthemedEntriesField.setAccessible(true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
sThemedResourceCacheMUnthemedEntriesFieldInitialized = true;
}
if (sThemedResourceCacheMUnthemedEntriesField != null) {
LongSparseArray unthemedEntries = null;
try {
unthemedEntries = (LongSparseArray) sThemedResourceCacheMUnthemedEntriesField.get(themedResourceCache);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if (unthemedEntries != null) {
unthemedEntries.clear();
}
}
if (!sThemedResourceCacheMNullThemedEntriesFieldInitialized) {
try {
sThemedResourceCacheMNullThemedEntriesField = sThemedResourceCacheClass.getDeclaredField("mNullThemedEntries");
sThemedResourceCacheMNullThemedEntriesField.setAccessible(true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
sThemedResourceCacheMNullThemedEntriesFieldInitialized = true;
}
if (sThemedResourceCacheMNullThemedEntriesField != null) {
LongSparseArray nullThemedEntries = null;
try {
nullThemedEntries = (LongSparseArray) sThemedResourceCacheMNullThemedEntriesField.get(themedResourceCache);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if (nullThemedEntries != null) {
nullThemedEntries.clear();
}
}
}
use of android.util.LongSparseArray in project robolectric by robolectric.
the class ShadowAppOpsManager method toOpEntry.
protected OpEntry toOpEntry(Integer op, int mode) {
if (RuntimeEnvironment.getApiLevel() < Build.VERSION_CODES.M) {
return ReflectionHelpers.callConstructor(OpEntry.class, ClassParameter.from(int.class, op), ClassParameter.from(int.class, mode), ClassParameter.from(long.class, OP_TIME), ClassParameter.from(long.class, REJECT_TIME), ClassParameter.from(int.class, DURATION));
} else if (RuntimeEnvironment.getApiLevel() < Build.VERSION_CODES.Q) {
return ReflectionHelpers.callConstructor(OpEntry.class, ClassParameter.from(int.class, op), ClassParameter.from(int.class, mode), ClassParameter.from(long.class, OP_TIME), ClassParameter.from(long.class, REJECT_TIME), ClassParameter.from(int.class, DURATION), ClassParameter.from(int.class, PROXY_UID), ClassParameter.from(String.class, PROXY_PACKAGE));
} else if (RuntimeEnvironment.getApiLevel() < Build.VERSION_CODES.R) {
final long key = AppOpsManager.makeKey(AppOpsManager.UID_STATE_TOP, AppOpsManager.OP_FLAG_SELF);
final LongSparseLongArray accessTimes = new LongSparseLongArray();
accessTimes.put(key, OP_TIME);
final LongSparseLongArray rejectTimes = new LongSparseLongArray();
rejectTimes.put(key, REJECT_TIME);
final LongSparseLongArray durations = new LongSparseLongArray();
durations.put(key, DURATION);
final LongSparseLongArray proxyUids = new LongSparseLongArray();
proxyUids.put(key, PROXY_UID);
final LongSparseArray<String> proxyPackages = new LongSparseArray<>();
proxyPackages.put(key, PROXY_PACKAGE);
return ReflectionHelpers.callConstructor(OpEntry.class, ClassParameter.from(int.class, op), ClassParameter.from(boolean.class, false), ClassParameter.from(int.class, mode), ClassParameter.from(LongSparseLongArray.class, accessTimes), ClassParameter.from(LongSparseLongArray.class, rejectTimes), ClassParameter.from(LongSparseLongArray.class, durations), ClassParameter.from(LongSparseLongArray.class, proxyUids), ClassParameter.from(LongSparseArray.class, proxyPackages));
} else {
final long key = AppOpsManager.makeKey(AppOpsManager.UID_STATE_TOP, AppOpsManager.OP_FLAG_SELF);
LongSparseArray<NoteOpEvent> accessEvents = new LongSparseArray<>();
LongSparseArray<NoteOpEvent> rejectEvents = new LongSparseArray<>();
accessEvents.put(key, new NoteOpEvent(OP_TIME, DURATION, new OpEventProxyInfo(PROXY_UID, PROXY_PACKAGE, null)));
rejectEvents.put(key, new NoteOpEvent(REJECT_TIME, -1, null));
return new OpEntry(op, mode, Collections.singletonMap(null, new AttributedOpEntry(op, false, accessEvents, rejectEvents)));
}
}
use of android.util.LongSparseArray in project robolectric by robolectric.
the class ShadowResourcesImpl method obtainResettableArrays.
private static List<LongSparseArray<?>> obtainResettableArrays() {
List<LongSparseArray<?>> resettableArrays = new ArrayList<>();
Field[] allFields = Resources.class.getDeclaredFields();
for (Field field : allFields) {
if (Modifier.isStatic(field.getModifiers()) && field.getType().equals(LongSparseArray.class)) {
field.setAccessible(true);
try {
LongSparseArray<?> longSparseArray = (LongSparseArray<?>) field.get(null);
if (longSparseArray != null) {
resettableArrays.add(longSparseArray);
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
return resettableArrays;
}
use of android.util.LongSparseArray in project Resurrection_packages_apps_Settings by ResurrectionRemix.
the class ProcStatsData method getProcs.
private ArrayList<ProcStatsEntry> getProcs(ProcessDataCollection bgTotals, ProcessDataCollection runTotals) {
final ArrayList<ProcStatsEntry> procEntries = new ArrayList<>();
if (DEBUG)
Log.d(TAG, "-------------------- PULLING PROCESSES");
final ProcessMap<ProcStatsEntry> entriesMap = new ProcessMap<ProcStatsEntry>();
for (int ipkg = 0, N = mStats.mPackages.getMap().size(); ipkg < N; ipkg++) {
final SparseArray<LongSparseArray<ProcessStats.PackageState>> pkgUids = mStats.mPackages.getMap().valueAt(ipkg);
for (int iu = 0; iu < pkgUids.size(); iu++) {
final LongSparseArray<ProcessStats.PackageState> vpkgs = pkgUids.valueAt(iu);
for (int iv = 0; iv < vpkgs.size(); iv++) {
final ProcessStats.PackageState st = vpkgs.valueAt(iv);
for (int iproc = 0; iproc < st.mProcesses.size(); iproc++) {
final ProcessState pkgProc = st.mProcesses.valueAt(iproc);
final ProcessState proc = mStats.mProcesses.get(pkgProc.getName(), pkgProc.getUid());
if (proc == null) {
Log.w(TAG, "No process found for pkg " + st.mPackageName + "/" + st.mUid + " proc name " + pkgProc.getName());
continue;
}
ProcStatsEntry ent = entriesMap.get(proc.getName(), proc.getUid());
if (ent == null) {
ent = new ProcStatsEntry(proc, st.mPackageName, bgTotals, runTotals, mUseUss);
if (ent.mRunWeight > 0) {
if (DEBUG)
Log.d(TAG, "Adding proc " + proc.getName() + "/" + proc.getUid() + ": time=" + ProcessStatsUi.makeDuration(ent.mRunDuration) + " (" + ((((double) ent.mRunDuration) / memTotalTime) * 100) + "%)" + " pss=" + ent.mAvgRunMem);
entriesMap.put(proc.getName(), proc.getUid(), ent);
procEntries.add(ent);
}
} else {
ent.addPackage(st.mPackageName);
}
}
}
}
}
if (DEBUG)
Log.d(TAG, "-------------------- MAPPING SERVICES");
// Add in service info.
for (int ip = 0, N = mStats.mPackages.getMap().size(); ip < N; ip++) {
SparseArray<LongSparseArray<ProcessStats.PackageState>> uids = mStats.mPackages.getMap().valueAt(ip);
for (int iu = 0; iu < uids.size(); iu++) {
LongSparseArray<ProcessStats.PackageState> vpkgs = uids.valueAt(iu);
for (int iv = 0; iv < vpkgs.size(); iv++) {
ProcessStats.PackageState ps = vpkgs.valueAt(iv);
for (int is = 0, NS = ps.mServices.size(); is < NS; is++) {
ServiceState ss = ps.mServices.valueAt(is);
if (ss.getProcessName() != null) {
ProcStatsEntry ent = entriesMap.get(ss.getProcessName(), uids.keyAt(iu));
if (ent != null) {
if (DEBUG)
Log.d(TAG, "Adding service " + ps.mPackageName + "/" + ss.getName() + "/" + uids.keyAt(iu) + " to proc " + ss.getProcessName());
ent.addService(ss);
} else {
Log.w(TAG, "No process " + ss.getProcessName() + "/" + uids.keyAt(iu) + " for service " + ss.getName());
}
}
}
}
}
}
return procEntries;
}
Aggregations