`
jgsj
  • 浏览: 960648 次
文章分类
社区版块
存档分类
最新评论

Android SurfaceFlinger服务启动过程源码分析

 
阅读更多

Android系统的SurfaceFlinger服务有两种启动方式:1)在SystemServer进程中以服务线程的方式提供服务;2)启动SurfaceFlinger独立的进程通过服务。第一种方式是在SystemServer进程启动过程中启动SurfaceFlinger服务的,而第二中方式是在Android启动脚本init.rc中配置SurfaceFlinger服务,通过init进程来启动的。下面就分别介绍SurfaceFlinger的两种启动方式。

1 服务线程启动方式

Android 开关机动画显示源码分析中已经简要介绍过SurfaceFlinger服务的这种启动方式,在SystemServer进程的init1阶段,通过JNI调用system_init()函数来启动SurfaceFlinger:
frameworks\base\cmds\system_server\library\system_init.cpp
extern "C" status_t system_init()
{
    ALOGI("Entered system_init()");
    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm = defaultServiceManager();
    ALOGI("ServiceManager: %p\n", sm.get());
    sp<GrimReaper> grim = new GrimReaper();
    sm->asBinder()->linkToDeath(grim, grim.get(), 0);
    char propBuf[PROPERTY_VALUE_MAX];
    property_get("system_init.startsurfaceflinger", propBuf, "1");
    if (strcmp(propBuf, "1") == 0) {
        // Start the SurfaceFlinger
        SurfaceFlinger::instantiate();
    }
	....
}
SurfaceFlinger继承于BinderService模板类,BinderService的instantiate函数实现:
static void instantiate() { publish(); }
static status_t publish(bool allowIsolated = false) {
	sp<IServiceManager> sm(defaultServiceManager());
	return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated);
}
函数首先得到ServiceManager的Binder代理对象,然后构造一个SurfaceFlinger对象,并注册到ServiceManager进程中。
在通过读取system_init.startsurfaceflinger属性值来决定是否在SystemServer进程中启动SurfaceFlinger服务,因此如果要在SystemServer中启动SurfaceFlinger,就必须设置system_init.startsurfaceflinger属性
如果system_init.startsurfaceflinger属性的值等于0,意味着SurfaceFlinger是以服务进程的方式启动的。

2.服务进程启动方式

当system_init.startsurfaceflinger属性的值设置为0时,就必须在init.rc中配置SurfaceFlinger服务,通过init进程启动。


当SurfaceFlinger以服务进程的方式启动时,必现提供进程入口函数main,在frameworks\native\cmds\surfaceflinger\main_surfaceflinger.cpp中实现:
int main(int argc, char** argv) {
    SurfaceFlinger::publishAndJoinThreadPool(true);
    // When SF is launched in its own process, limit the number of
    // binder threads to 4.
    ProcessState::self()->setThreadPoolMaxThreadCount(4);
    return 0;
}
函数调用SurfaceFlinger类的publishAndJoinThreadPool方法启动构造SurfaceFlinger对象并注册到ServiceManager进程中,然后调用setThreadPoolMaxThreadCount函数来设置SurfaceFlinger进程的最大Binder线程数。
static void publishAndJoinThreadPool(bool allowIsolated = false) {
	sp<IServiceManager> sm(defaultServiceManager());
	sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated);
	ProcessState::self()->startThreadPool();
	IPCThreadState::self()->joinThreadPool();
}
和前面的publish函数一样,首先得到ServiceManager的Binder代理对象,然后构造一个SurfaceFlinger对象,并注册到ServiceManager进程中,只不过这里额外调用了ProcessState::self()->startThreadPool()来启动Binder线程池,并且将当前进程的主线程注册到Binder线程池中,对于SurfaceFlinger服务进程来说,为了接收客户端的请求,SurfaceFlinger服务进程必现启动Binder线程池。如果SurfaceFlinger以服务线程的方式在SystemServer进程中启动的话,就无需启动Binder线程,因为SurfaceFlinger服务驻留在SystemServer进程中,而SysteServer进程自己维护了一个Binder线程池。

3.启动SurfaceFlinger

SurfaceFlinger::SurfaceFlinger()
    :   BnSurfaceComposer(), Thread(false),
        mTransactionFlags(0),
        mTransationPending(false),
        mLayersRemoved(false),
        mBootTime(systemTime()),
        mVisibleRegionsDirty(false),
        mHwWorkListDirty(false),
        mElectronBeamAnimationMode(0),
        mDebugRegion(0),
        mDebugDDMS(0),
        mDebugDisableHWC(0),
        mDebugDisableTransformHint(0),
        mDebugInSwapBuffers(0),
        mLastSwapBufferTime(0),
        mDebugInTransaction(0),
        mLastTransactionTime(0),
        mBootFinished(false),
        mSecureFrameBuffer(0)
{
    init();
}
构造过程仅仅初始化了SurfaceFlinger的成员变量,同时调用了父类BnSurfaceComposer的构造函数。最后使用init方法来作一些初始化工作。
void SurfaceFlinger::init()
{
    ALOGI("SurfaceFlinger is starting");
    char value[PROPERTY_VALUE_MAX];
    property_get("debug.sf.showupdates", value, "0");
    mDebugRegion = atoi(value);
    property_get("ro.bootmode", value, "mode");
    if (!(strcmp(value, "engtest")
        && strcmp(value, "special")
        && strcmp(value, "wdgreboot")
        && strcmp(value, "unknowreboot")
        && strcmp(value, "panic"))) {
        SurfaceFlinger::sBootanimEnable = false;
    }
}
读取开机模式属性ro.bootmode来决定是否要显示开机动画,关于开机动画在Android 开关机动画显示源码分析中介绍了。由于SurfaceFlinger继承于RefBase类,同时实现了RefBase的onFirstRef()方法,因此在第一次引用SurfaceFlinger对象时,onFirstRef()函数自动被调用:
void SurfaceFlinger::onFirstRef()
{
    mEventQueue.init(this);
    run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
    // Wait for the main thread to be done with its initialization
    mReadyToRunBarrier.wait();
}
mEventQueue是MessageQueue类型变量,定义在frameworks\native\services\surfaceflinger\MessageQueue.h这里调用init函数初始化mEventQueue消息队列
void MessageQueue::init(const sp<SurfaceFlinger>& flinger)
{
    mFlinger = flinger;
    mLooper = new Looper(true);
    mHandler = new Handler(*this);
}
mReadyToRunBarrier为Barrier类型的变量,用于阻塞,启动线程运行,对象构造时,状态初始化为CLOSED,因此在调用它的wait方法时,当前SurfaceFlinger线程睡眠等待SystemServer主线程调用readyToRun()函数完成SurfaceFlinger运行前的初始化工作。
inline Barrier() : state(CLOSED) { }
void wait() const {
	Mutex::Autolock _l(lock);
	while (state == CLOSED) {
		cv.wait(lock);
	}
}
SurfaceFlinger继承于Thread类,因此构造一个SurfaceFlinger对象,其实就是创建一个线程,当调用其run方法时,就是启动该线程的运行,在SurfaceFlinger线程运行前,需要主线程初始化OpenGL库,因此在主线程完成初始化工作前,需要让SurfaceFlinger线程睡眠等待,主线程初始化工作:
status_t SurfaceFlinger::readyToRun()
{
    ALOGI( "SurfaceFlinger's main thread ready to run. ""Initializing graphics H/W...");
    // we only support one display currently
    int dpy = 0;
    {
        //初始化主显示屏,即从SurfaceFlinger中取出第0号GraphicPlane
        GraphicPlane& plane(graphicPlane(dpy));
		//创建DisplayHardware,并和显示屏绑定
        DisplayHardware* const hw = new DisplayHardware(this, dpy);
        plane.setDisplayHardware(hw);
    }
    //创建一块大小为4k的匿名共享内存,用于共享显示屏幕信息
    mServerHeap = new MemoryHeapBase(4096,MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");
    ALOGE_IF(mServerHeap==0, "can't create shared memory dealer");
	//将该匿名共享内存的首地址转换为surface_flinger_cblk_t类型的指针,表明该共享内存存储surface_flinger_cblk_t结构体数据
    mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());
    ALOGE_IF(mServerCblk==0, "can't get to shared control block's address");
    new(mServerCblk) surface_flinger_cblk_t;
    //从显示屏的DisplayHardware中得到屏幕的宽高,并设置为当前主显示屏
    const GraphicPlane& plane(graphicPlane(dpy));
    const DisplayHardware& hw = plane.displayHardware();
    const uint32_t w = hw.getWidth();
    const uint32_t h = hw.getHeight();
    const uint32_t f = hw.getFormat();
    hw.makeCurrent();
    //将屏幕信息保存到匿名共享内存中,从而共享给所有进程
    mServerCblk->connected |= 1<<dpy;
    display_cblk_t* dcblk = mServerCblk->displays + dpy;
    memset(dcblk, 0, sizeof(display_cblk_t));
    dcblk->w            = plane.getWidth();
    dcblk->h            = plane.getHeight();
    dcblk->format       = f;
    dcblk->orientation  = ISurfaceComposer::eOrientationDefault;
    dcblk->xdpi         = hw.getDpiX();
    dcblk->ydpi         = hw.getDpiY();
    dcblk->fps          = hw.getRefreshRate();
    dcblk->density      = hw.getDensity();
    //初始化OpenGL|ES
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    glPixelStorei(GL_PACK_ALIGNMENT, 4);
    glEnableClientState(GL_VERTEX_ARRAY);
    glShadeModel(GL_FLAT);
    glDisable(GL_DITHER);
    glDisable(GL_CULL_FACE);
    const uint16_t g0 = pack565(0x0F,0x1F,0x0F);
    const uint16_t g1 = pack565(0x17,0x2f,0x17);
    const uint16_t wormholeTexData[4] = { g0, g1, g1, g0 };
    glGenTextures(1, &mWormholeTexName);
    glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0,GL_RGB, GL_UNSIGNED_SHORT_5_6_5, wormholeTexData);
    const uint16_t protTexData[] = { pack565(0x03, 0x03, 0x03) };
    glGenTextures(1, &mProtectedTexName);
    glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0,GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    // put the origin in the left-bottom corner
    glOrthof(0, w, 0, h, 0, 1); // l=0, r=w ; b=0, t=h
    // 启动EventThread线程
    mEventThread = new EventThread(this);
    mEventQueue.setEventThread(mEventThread);
    hw.startSleepManagement();
    //主线程已经完成初始化工作,唤醒睡眠等待中的SurfaceFlinger线程接收客户端的请求
    mReadyToRunBarrier.open();
    //启动开机动画
    startBootAnim();
    return NO_ERROR;
}
函数首先初始化主显示屏,为该GraphicPlane创建DisplayHardware对象,然后创建一块匿名共享内存,用于保存显示屏幕信息,同时共享给系统的其他进程访问,接着初始化OpenGL库,同时启动EventThread线程,唤醒SurfaceFlinger线程,并启动开机动画。

1)获取GraphicPlane

GraphicPlane& SurfaceFlinger::graphicPlane(int dpy)
{
    return const_cast<GraphicPlane&>(const_cast<SurfaceFlinger const *>(this)->graphicPlane(dpy));
}
//Android4.1只支持1个屏幕显示,#define DISPLAY_COUNT       1
const GraphicPlane& SurfaceFlinger::graphicPlane(int dpy) const
{
    ALOGE_IF(uint32_t(dpy) >= DISPLAY_COUNT, "Invalid DisplayID %d", dpy);
    const GraphicPlane& plane(mGraphicPlanes[dpy]);
    return plane;
}

2)构造DisplayHardware对象

DisplayHardware::DisplayHardware(const sp<SurfaceFlinger>& flinger,uint32_t dpy): DisplayHardwareBase(flinger, dpy),
      mFlinger(flinger), mFlags(0), mHwc(0)
{
    init(dpy);
}
构造DisplayHardware对象前,首先会构造其父类DisplayHardwareBase对象。
DisplayHardwareBase::DisplayHardwareBase(const sp<SurfaceFlinger>& flinger,
        uint32_t displayIndex) 
{
    mScreenAcquired = true;
    mDisplayEventThread = new DisplayEventThread(flinger);
}
在DisplayHardwareBase对象内部创建一个DisplayEventThread线程
DisplayHardwareBase::DisplayEventThread::DisplayEventThread(const sp<SurfaceFlinger>& flinger)
    : Thread(false), mFlinger(flinger) {
}
然后初始化DisplayHardware
void DisplayHardware::init(uint32_t dpy)
{
	//创建FramebufferNativeWindow对象
    mNativeWindow = new FramebufferNativeWindow();
	//在构造FramebufferNativeWindow对象时,通过打开Gralloc硬件抽象层模块,得到framebuffer_device_t
    framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
    if (!fbDev) {
        ALOGE("Display subsystem failed to initialize. check logs. exiting...");
        exit(0);
    }
    int format;
    ANativeWindow const * const window = mNativeWindow.get();
	//查询指定window的format信息
    window->query(window, NATIVE_WINDOW_FORMAT, &format);
    mDpiX = mNativeWindow->xdpi;
    mDpiY = mNativeWindow->ydpi;
    mRefreshRate = fbDev->fps;
    if (mDpiX == 0 || mDpiY == 0) {
        ALOGE("invalid screen resolution from fb HAL (xdpi=%f, ydpi=%f), ""defaulting to 160 dpi", mDpiX, mDpiY);
        mDpiX = mDpiY = 160;
    }
    class Density {
		//通过读取属性得到屏幕像素密度
        static int getDensityFromProperty(char const* propName) {
            char property[PROPERTY_VALUE_MAX];
            int density = 0;
            if (property_get(propName, property, NULL) > 0) {
                density = atoi(property);
            }
            return density;
        }
    public:
		//提供两个得到屏幕像素密度的接口,getEmuDensity用于得到模拟器的像素密度;getBuildDensity用于得到编译指定的屏幕像素密度
        static int getEmuDensity() {
            return getDensityFromProperty("qemu.sf.lcd_density"); }
        static int getBuildDensity()  {
            return getDensityFromProperty("ro.sf.lcd_density"); }
    };
    // The density of the device is provided by a build property
    mDensity = Density::getBuildDensity() / 160.0f;
    if (mDensity == 0) {
        // the build doesn't provide a density -- this is wrong! use xdpi instead
        ALOGE("ro.sf.lcd_density must be defined as a build property");
        mDensity = mDpiX / 160.0f;
    }
    if (Density::getEmuDensity()) {
        // if "qemu.sf.lcd_density" is specified, it overrides everything
        mDpiX = mDpiY = mDensity = Density::getEmuDensity();
        mDensity /= 160.0f;
    }
    /* FIXME: this is a temporary HACK until we are able to report the refresh rate
     * properly from the HAL. The WindowManagerService now relies on this value.
     */
#ifndef REFRESH_RATE
    mRefreshRate = fbDev->fps;
#else
    mRefreshRate = REFRESH_RATE;
#warning "refresh rate set via makefile to REFRESH_RATE"
#endif
    mRefreshPeriod = nsecs_t(1e9 / mRefreshRate);
    EGLint w, h, dummy;
    EGLint numConfigs=0;
    EGLSurface surface;
    EGLContext context;
    EGLBoolean result;
    status_t err;
    // initialize EGL
    EGLint attribs[] = {
            EGL_SURFACE_TYPE,       EGL_WINDOW_BIT,
            EGL_NONE,               0,
            EGL_NONE
    };
    // debug: disable h/w rendering
    char property[PROPERTY_VALUE_MAX];
    if (property_get("debug.sf.hw", property, NULL) > 0) {
        if (atoi(property) == 0) {
            ALOGW("H/W composition disabled");
            attribs[2] = EGL_CONFIG_CAVEAT;
            attribs[3] = EGL_SLOW_CONFIG;
        }
    }
    // TODO: all the extensions below should be queried through
    // eglGetProcAddress().
    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    eglInitialize(display, NULL, NULL);
    eglGetConfigs(display, NULL, 0, &numConfigs);

    EGLConfig config = NULL;
    err = selectConfigForPixelFormat(display, attribs, format, &config);
    ALOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
    
    EGLint r,g,b,a;
    eglGetConfigAttrib(display, config, EGL_RED_SIZE,   &r);
    eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
    eglGetConfigAttrib(display, config, EGL_BLUE_SIZE,  &b);
    eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);

    if (mNativeWindow->isUpdateOnDemand()) {
        mFlags |= PARTIAL_UPDATES;
    }
    
    if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
        if (dummy == EGL_SLOW_CONFIG)
            mFlags |= SLOW_CONFIG;
    }
    //Create our main surface
    surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
    eglQuerySurface(display, surface, EGL_WIDTH,  &mWidth);
    eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
    if (mFlags & PARTIAL_UPDATES) {
        // if we have partial updates, we definitely don't need to
        // preserve the backbuffer, which may be costly.
        eglSurfaceAttrib(display, surface,EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED);
    }
    //Create our OpenGL ES context
    EGLint contextAttributes[] = {
#ifdef EGL_IMG_context_priority
#ifdef HAS_CONTEXT_PRIORITY
#warning "using EGL_IMG_context_priority"
        EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG,
#endif
#endif
        EGL_NONE, EGL_NONE
    };
    context = eglCreateContext(display, config, NULL, contextAttributes);
    mDisplay = display;
    mConfig  = config;
    mSurface = surface;
    mContext = context;
    mFormat  = fbDev->format;
    mPageFlipCount = 0;
    // Gather OpenGL ES extensions
    result = eglMakeCurrent(display, surface, surface, context);
    if (!result) {
        ALOGE("Couldn't create a working GLES context. check logs. exiting...");
        exit(0);
    }
    GLExtensions& extensions(GLExtensions::getInstance());
    extensions.initWithGLStrings(
            glGetString(GL_VENDOR),
            glGetString(GL_RENDERER),
            glGetString(GL_VERSION),
            glGetString(GL_EXTENSIONS),
            eglQueryString(display, EGL_VENDOR),
            eglQueryString(display, EGL_VERSION),
            eglQueryString(display, EGL_EXTENSIONS));
    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
    glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);

    // Unbind the context from this thread
    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    // initialize the H/W composer
    mHwc = new HWComposer(mFlinger, *this, mRefreshPeriod);
    if (mHwc->initCheck() == NO_ERROR) {
        mHwc->setFrameBuffer(mDisplay, mSurface);
    }
}

3)创建匿名共享内存保存屏幕信息

//创建一块大小为4k的匿名共享内存,用于共享显示屏幕信息
mServerHeap = new MemoryHeapBase(4096,MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");
ALOGE_IF(mServerHeap==0, "can't create shared memory dealer");
//将该匿名共享内存的首地址转换为surface_flinger_cblk_t类型的指针,表明该共享内存存储surface_flinger_cblk_t结构体数据
mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());
ALOGE_IF(mServerCblk==0, "can't get to shared control block's address");
new(mServerCblk) surface_flinger_cblk_t;
//从显示屏的DisplayHardware中得到屏幕的宽高,并设置为当前主显示屏
const GraphicPlane& plane(graphicPlane(dpy));
const DisplayHardware& hw = plane.displayHardware();
const uint32_t w = hw.getWidth();
const uint32_t h = hw.getHeight();
const uint32_t f = hw.getFormat();
hw.makeCurrent();
//将屏幕信息保存到匿名共享内存中,从而共享给所有进程
mServerCblk->connected |= 1<<dpy;
display_cblk_t* dcblk = mServerCblk->displays + dpy;
memset(dcblk, 0, sizeof(display_cblk_t));
dcblk->w            = plane.getWidth();
dcblk->h            = plane.getHeight();
dcblk->format       = f;
dcblk->orientation  = ISurfaceComposer::eOrientationDefault;
dcblk->xdpi         = hw.getDpiX();
dcblk->ydpi         = hw.getDpiY();
dcblk->fps          = hw.getRefreshRate();
dcblk->density      = hw.getDensity();

4)SurfaceFlinger线程模型

无论SurfaceFlinger是以服务线程启动还是已服务进程启动,在启动过程中,主线程启动SurfaceFlinger线程,EventThread线程及DisplayEventThread线程
EventThread线程启动过程:
EventThread::EventThread(const sp<SurfaceFlinger>& flinger)
    : mFlinger(flinger),
      mHw(flinger->graphicPlane(0).editDisplayHardware()),
      mLastVSyncTimestamp(0),
      mVSyncTimestamp(0),
      mUseSoftwareVSync(false),
      mDeliveredEvents(0),
      mDebugVsyncEnabled(false)
{
}

void EventThread::onFirstRef() {
    mHw.setVSyncHandler(this);
    run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
}
DisplayEventThread线程启动过程:
void DisplayHardwareBase::startSleepManagement() const {
    if (mDisplayEventThread->initCheck() == NO_ERROR) {
        mDisplayEventThread->run("DisplayEventThread", PRIORITY_URGENT_DISPLAY);
    } else {
        ALOGW("/sys/power/wait_for_fb_{wake|sleep} don't exist");
    }
}

分享到:
评论

相关推荐

    《深入理解Android:卷I》试读本

    第3章分析了init进程,揭示了通过解析init.rc来启动Zygote以及属性服务的工作原理;第4章分析了Zygote、SystemServer等进程的工作机制,同时还讨论了Android的启动速度、虚拟机HeapSize的大小调整、Watchdog工作原理...

    深入理解Android 卷1.pdf

    第3章分析了init进程,揭示了通过解析init.rc来启动Zygote以及属性服务的工作原理;第4章分析了Zygote、SystemServer等进程的工作机制,同时还讨论了Android的启动速度、虚拟机HeapSize的大小调整、Watchdog工作原理...

    深入理解Android卷1

    第3章分析了init进程,揭示了通过解析init.rc来启动Zygote以及属性服务的工作原理;第4章分析了Z ygote、SystemServer等进程的工作机制,同时还讨论了Android的启动速度、虚拟机HeapSize的大小调整、Watchdog工作...

    深入理解Android:卷2

    第3章分析了init进程,揭示了通过解析init.rc来启动Zygote以及属性服务的工作原理;第4章分析了Z ygote、SystemServer等进程的工作机制,同时还讨论了Android的启动速度、虚拟机HeapSize的大小调整、Watchdog工作...

    深入理解Android++卷1pdf电子书

    第3章分析了init进程,揭示了通过解析init.rc来启动Zygote以及属性服务的工作原理;第4章分析了Zygote、SystemServer等进程的工作机制,同时还讨论了Android的启动速度、虚拟机HeapSize的大小调整、Watchdog工作原理...

    深入理解Android:卷I--详细书签版

    CruiseYoung提供的带有详细书签的电子书籍目录 ... 深入理解Android:卷I(51CTO网站“2011年度最受读者喜爱的原创IT技术... //这里是源码分析和一些注释。  如有一些需要特别说明的地方,则会用下面的格式表示:  ...

    深入理解Android 卷I

    第3章分析了init进程,揭示了通过解析init.rc来启动zygote以及属性服务的工作原理;第4章分析了zygote、systemserver等进程的工作机制,同时还讨论了android的启动速度、虚拟机heapsize的大小调整、watchdog工作原理...

    深入理解Android

    第3章分析了init进程,揭示了通过解析init.rc来启动Zygote以及属性服务的工作原理;第4章分析了Zygote、SystemServer等进程的工作机制,同时还讨论了Android的启动速度、虚拟机HeapSize的大小调整、Watchdog工作原理...

Global site tag (gtag.js) - Google Analytics