android加載第三方圖標機制分析
系統如何獲取圖片等資源
當我們調用Resources.Java 來獲取圖片等資源的時候會調用getDrawable 方法, getDrawable最終把這還是使用loadDrawable 方法來處理.
Resources.java
public Drawable getDrawable(int id) throws NotFoundException {
TypedValue value;
synchronized (mAccessLock) {
value = http://www.ithao123.cn/mTmpValue;
if (value =http://www.ithao123.cn/= null) {
value = http://www.ithao123.cn/new TypedValue();
} else {
mTmpValue = http://www.ithao123.cn/null;
}
getValue(id, value, true);
}
Drawable res = loadDrawable(value, id);
synchronized (mAccessLock) {
if (mTmpValue =http://www.ithao123.cn/= null) {
mTmpValue = http://www.ithao123.cn/value;
}
}
return res;
}
loadDrawable 方法在獲取資源的時候會先判斷該資源是否在緩存中,如果在緩存中就直接獲取返回,如果沒有就繼續查詢.同時使用color配置的圖片的資源也會先去緩存中讀取,這樣可以提高代碼的效率.如果還是沒有找到就會調用AssetManager.java 的openNonAsset 方法,再接著分析會發現調用的是Jni 的一個方法openNonAssetNative,Jni 最終會去調用AssetManager.cpp 的openNonAsset的方法來根據不同主題去獲取對應的資源.
frameworks/base/core/jni/android_util_AssetManager.cpp àopenNonAssetNative
static jint android_content_AssetManager_openNonAssetNative(JNIEnv* env, jobject clazz,
jint cookie,
jstring fileName,
jint mode)
{
AssetManager* am = assetManagerForJavaObject(env, clazz);
if (am == NULL) {
return 0;
}
ALOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
ScopedUtfChars fileName8(env, fileName);
if (fileName8.c_str() == NULL) {
return -1;
}
if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
&& mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
return -1;
}
Asset* a = cookie
? am->openNonAsset((void*)cookie, fileName8.c_str(), (Asset::AccessMode)mode)
: am->openNonAsset(fileName8.c_str(), (Asset::AccessMode)mode);
if (a == NULL) {
jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
return -1;
}
//printf("Created Asset Stream: %p\n", a);
return (jint)a;
}
Resources.java
Drawable loadDrawable(TypedValue value, int id)
throws NotFoundException {
if (TRACE_FOR_PRELOAD) {
// Log only framework resources
if ((id >>> 24) == 0x1) {//framework resources id 是以0x1 開頭, mediatek Resource id 是一0x2 開頭. 第3方資源一般以0x7 開頭
final String name = getResourceName(id);
if (name != null) android.util.Log.d("PreloadDrawable", name);
}
}
boolean isColorDrawable = false;
if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
isColorDrawable = true;
}
final long key = isColorDrawable ? value.data :
(((long) value.assetCookie) << 32) | value.data;
Drawable dr = getCachedDrawable(isColorDrawable ? mColorDrawableCache : mDrawableCache, key);//從緩存中讀取,如果緩存中已經存在,就直接獲取並返回,緩存中沒有的話就繼續執行下面的代碼去查詢獲取對應的資源文件.
if (dr != null) {
return dr;
}
Drawable.ConstantState cs = null;
/// M: Theme manager @{
Boolean checkPreload = true;
if (FeatureOption.MTK_THEMEMANAGER_APP) {
String skin= Configuration.getSkin();
if ((skin != null) &&
!(skin.equals(sDefaultSkin))){
checkPreload = false;
}
}
/// @}
//使用color配置的圖片可以也直接從緩存中讀取,提高效率.
if (checkPreload) {/// M: Theme manager
if (isColorDrawable) {
cs = sPreloadedColorDrawables.get(key);
} else {
cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
}
}/// M: Theme manager
if (cs != null) {
dr = cs.newDrawable(this);
} else {
if (isColorDrawable) {
dr = new ColorDrawable(value.data);
}
if (dr == null) {
if (value.string == null) {
throw new NotFoundException(
"Resource is not a Drawable (color or path): " + value);
}
String file = value.string.toString();
if (TRACE_FOR_MISS_PRELOAD) {
// Log only framework resources
if ((id >>> 24) == 0x1) {
final String name = getResourceName(id);
if (name != null) android.util.Log.d(TAG, "Loading framework drawable #"
+ Integer.toHexString(id) + ": " + name
+ " at " + file);
}
}
if (DEBUG_LOAD) Log.v(TAG, "Loading drawable for cookie "
+ value.assetCookie + ": " + file);
if (file.endsWith(".xml")) {
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
try {
XmlResourceParser rp = loadXmlResourceParser(
file, id, value.assetCookie, "drawable");
dr = Drawable.createFromXml(this, rp);
rp.close();
} catch (Exception e) {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
NotFoundException rnf = new NotFoundException(
"File " + file + " from drawable resource ID #0x"
+ Integer.toHexString(id));
rnf.initCause(e);
throw rnf;
}
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
} else {
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
try {
InputStream is = mAssets.openNonAsset(
value.assetCookie, file, AssetManager.ACCESS_STREAMING);
//system.out.println("Opened file " + file + ": " + is);
dr = Drawable.createFromResourceStream(this, value, is,
file, null);
is.close();
//System.out.println("Created stream: " + dr);
} catch (Exception e) {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
NotFoundException rnf = new NotFoundException(
"File " + file + " from drawable resource ID #0x"
+ Integer.toHexString(id));
rnf.initCause(e);
throw rnf;
}
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
}
}
if (dr != null) {
dr.setChangingConfigurations(value.changingConfigurations);
cs = dr.getConstantState();
if (cs != null) {
if (mPreloading) {
final int changingConfigs = cs.getChangingConfigurations();
if (isColorDrawable) {
if (verifyPreloadConfig(changingConfigs, 0, value.resourceId,
"drawable")) {
sPreloadedColorDrawables.put(key, cs);
}
} else {
if (verifyPreloadConfig(changingConfigs,
LAYOUT_DIR_CONFIG, value.resourceId, "drawable")) {
if ((changingConfigs&LAYOUT_DIR_CONFIG) == 0) {
// If this resource does not vary based on layout direction,
// we can put it in all of the preload maps.
sPreloadedDrawables[0].put(key, cs);
sPreloadedDrawables[1].put(key, cs);
} else {
// Otherwise, only in the layout dir we loaded it for.
final LongSparseArray<Drawable.ConstantState> preloads
= sPreloadedDrawables[mConfiguration.getLayoutDirection()];
preloads.put(key, cs);
}
}
}
} else {
synchronized (mAccessLock) {
//Log.i(TAG, "Saving cached drawable @ #" +
// Integer.toHexString(key.intValue())
// + " in " + this + ": " + cs);
if (isColorDrawable) {
mColorDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
} else {
mDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
}
}
}
}
}
return dr;
}
如何替換第三方應用裏面的資源
frameworks/base/libs/androidfw/AssetManager.cpp
bool AssetManager::addAssetPath(constString8& path,void** cookie)
{
......
// add overlay packages for /system/framework; apps are handled by the
// (Java) package manager
if(strncmp(path.string(),"/system/framework/",18)==0){
// When there is an environment variable for /vendor, this
// should be changed to something similar to how ANDROID_ROOT
// and ANDROID_DATA are used in this file.
String8 overlayPath("/vendor/overlay/framework/");
overlayPath.append(path.getPathLeaf());
if(TEMP_FAILURE_RETRY(access(overlayPath.string(), R_OK))==0){
asset_path oap;
oap.path = overlayPath;
oap.type =::getFileType(overlayPath.string());
bool addOverlay =(oap.type == kFileTypeRegular);// only .apks supported as overlay
if(addOverlay){
oap.idmap = idmapPathForPackagePath(overlayPath);
if(isIdmapStaleLocked(ap.path, oap.path, oap.idmap)){
addOverlay = createIdmapFileLocked(ap.path, oap.path, oap.idmap);
}
}
if(addOverlay){
mAssetPaths.add(oap);
}else{
ALOGW("failed to add overlay package %s\n", overlayPath.string());
}
}
}
returntrue;
}
比如將上面的代碼改成
-if (strncmp(path.string(), "/system/framework/", 18) == 0) {
+if (strncmp(path.string(), "/system/app/", 12) == 0) {
// When there is an environment variable for /vendor, this
// should be changed to something similar to how ANDROID_ROOT
// and ANDROID_DATA are used in this file.
-String8 overlayPath("/vendor/overlay/framework/");
+String8 overlayPath("/system/vendor/thirds/");
overlayPath.append(path.getPathLeaf());
if (TEMP_FAILURE_RETRY(access(overlayPath.string(), R_OK)) == 0) {
然後再vendor目錄下面放對應的文件
vendor/mediatek/eastaeon92_wet_tdd/artifacts/out/target/product/eastaeon92_wet_tdd/system/vendor/thirds/iReader.apk
Tags: android 第三方 return color null
文章來源: