本文主要介绍系统资源的加载、读取、添加流程。
一、加载。
1、优先加载的系统资源。
在zygote进程初始化时,有部分系统资源被优先加载,当他们加载完,zygote进程才开始启动其它应用进程。
Zygote是系统启动初始化的进程,如何执行那?
public static void main(String argv[]) { try { // Start profiling the zygote initialization. SamplingProfilerIntegration.start(); registerZygoteSocket(); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis()); preload(); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); // Finish profiling the zygote initialization. SamplingProfilerIntegration.writeZygoteSnapshot(); // Do an initial gc to clean up after startup gc(); // If requested, start system server directly from Zygote if (argv.length != 2) { throw new RuntimeException(argv[0] + USAGE_STRING); } if (argv[1].equals("start-system-server")) { startSystemServer(); } else if (!argv[1].equals("")) { throw new RuntimeException(argv[0] + USAGE_STRING); } Log.i(TAG, "Accepting command socket connections"); if (ZYGOTE_FORK_MODE) { runForkMode(); } else { runSelectLoopMode(); } closeServerSocket(); } catch (MethodAndArgsCaller caller) { caller.run(); } catch (RuntimeException ex) { Log.e(TAG, "Zygote died with exception", ex); closeServerSocket(); throw ex; } }
这个函数中有三个很重要的方法。1、preload();2、startSystemServer();3、runSelectLoopMode();,这也是此函数内部执行的三个阶段。
我们来看加载“优先系统资源”。
static void preload() { preloadClasses(); preloadResources(); }预加载分两步,预加载class,预加载Resource。我们来看预加载Resource。
private static void preloadResources() { final VMRuntime runtime = VMRuntime.getRuntime(); Debug.startAllocCounting(); try { System.gc(); runtime.runFinalizationSync(); mResources = Resources.getSystem(); mResources.startPreloading(); if (PRELOAD_RESOURCES) { Log.i(TAG, "Preloading resources..."); long startTime = SystemClock.uptimeMillis(); TypedArray ar = mResources.obtainTypedArray( com.android.internal.R.array.preloaded_drawables); int N = preloadDrawables(runtime, ar); Log.i(TAG, "...preloaded " + N + " resources in " + (SystemClock.uptimeMillis()-startTime) + "ms."); startTime = SystemClock.uptimeMillis(); ar = mResources.obtainTypedArray( com.android.internal.R.array.preloaded_color_state_lists); N = preloadColorStateLists(runtime, ar); Log.i(TAG, "...preloaded " + N + " resources in " + (SystemClock.uptimeMillis()-startTime) + "ms."); } mResources.finishPreloading(); } catch (RuntimeException e) { Log.w(TAG, "Failure preloading resources", e); } finally { Debug.stopAllocCounting(); } }首先通过Resource.getSystem得到Resource对象。此函数我们可以在应用层中调用,但通过此方式得到的Resource对象,依据上篇博文可知,仅能访问framework层资源。
public static Resources getSystem() { synchronized (mSync) { Resources ret = mSystem; if (ret == null) { ret = new Resources(); mSystem = ret; } return ret; } }
private Resources() { mAssets = AssetManager.getSystem(); // NOTE: Intentionally leaving this uninitialized (all values set // to zero), so that anyone who tries to do something that requires // metrics will get a very wrong value. mConfiguration.setToDefaults(); mMetrics.setToDefaults(); updateConfiguration(null, null); mAssets.ensureStringBlocks(); mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO; }
总结一下:zygote进程创建Resource对象和普通进程不同,前者使用静态函数getSystem后者使用带参数的Resource构造创建,参数包含了应用程序资源文件的路径信息。
2、有了Resource对象,接着调用mResources.startPreloading();。
public final void startPreloading() { synchronized (mSync) { if (mPreloaded) { throw new IllegalStateException("Resources already preloaded"); } mPreloaded = true; mPreloading = true; } }在finishPreloading中置为false。
public final void finishPreloading() { if (mPreloading) { mPreloading = false; flushLayoutCache(); } }这一步为Resource对象中的成员变量赋值。mPreloaded以及mPreloading成员属性的存在保证了getDrawable以及getColor不同的流程。
3、执行加载过程。preloadDrawable以及preloadColorStateLists。
TypedArray ar = mResources.obtainTypedArray( com.android.internal.R.array.preloaded_drawables); int N = preloadDrawables(runtime, ar);和
ar = mResources.obtainTypedArray( com.android.internal.R.array.preloaded_color_state_lists); N = preloadColorStateLists(runtime, ar);这两个函数目的是加载定义在com.android.internal.R.array.preloaded_drawables以及com.android.internal.R.array.preloaded_color_state_llists两个xml文件中定义的资源。
4、加载过程,就是执行Resource对象的loadDrawable以及loadColorxx等。但是与普通加载不同的是,此处加载会根据2种两个变量mPreloaded的true或者false,执行不同的逻辑,最终将加载的资源存放在Resource对象的成员静态List中。
if (mPreloading) { if (isColorDrawable) { sPreloadedColorDrawables.put(key, cs); } else { sPreloadedDrawables.put(key, cs); } } else { synchronized (mTmpValue) { //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)); } } }
private static final LongSparseArray<Drawable.ConstantState> sPreloadedDrawables = new LongSparseArray<Drawable.ConstantState>(); private static final SparseArray<ColorStateList> mPreloadedColorStateLists = new SparseArray<ColorStateList>(); private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables = new LongSparseArray<Drawable.ConstantState>();static关键字保证了被应用程序进程创建的新的Resource对象保存了zygote进程预加载的资源。
二、framework层资源的添加。
framework包含了很多资源,预加载的只是其中一部分,非预加载的资源不会被记载道Resource缓冲静态列表中。这意味着,多个应用需要一个非预加载资源,则会在各自的进程中保存一个资源的缓冲。
系统资源,按照是否公开,分为私有资源和公开资源。私有资源是指仅能在framework内部访问的资源或者说手机厂商拥有源码编译环境的厂商或者团体才能使用。公开资源是指被编译到android SDK中的资源
公开资源R文件:android.R
私有资源R文件:com.android.internal.R。
公开资源是私有资源的一个子集,私有资源来源自res/values/public.xml中的定义。在此文件中定义的string等资源在各个sdk版本中都会保持值一致。
framework值定义规范:
0x0104f000
01代表framework资源
04代表string类型的资源
f000:代表资源编号。