当前位置:文档之家› Android视频播放数据读取的流程

Android视频播放数据读取的流程

Android视频播放数据读取的流程
Android视频播放数据读取的流程

Android视频播放数据读取的流程

https://www.doczj.com/doc/8e5093725.html,/s/blog_645b74b90101aezn.html

这里分析Android4.0.1本地视频数据读取的流程,其他过程类似

当播放条件准备妥当之后,就要循环进行读取视频的原始数据放到MediaBuffer,将MediaBuffer中的数据输送到解码器中解码,解码后的数据放到MediaBuffer中,在将这MediaBuffer中的数据进行render显示。

本文主要侧重读取原始数据的流程,主要是代码跟踪,不夹杂个人分析,有些mpeg4的算法不懂。

1:onVideoEvent中开始读取数据,具体代码如下:

void AwesomePlayer::onVideoEvent() {

if (!mVideoBuffer) {

MediaSource::ReadOptions options;

if (mSeeking != NO_SEEK) {

LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);

options.setSeekTo(

mSeekTimeUs,

mSeeking == SEEK_VIDEO_ONLY

? MediaSource::ReadOptions::SEEK_NEXT_SYNC

:

MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);

}

for (;;) {

status_t err = mVideoSource->read(&mVideoBuffer, &options); }

}

}

蓝色为核心代码,如果是正常读取,options为null,否则这个结构体中包含了seek到的时间和seek的模式,用于具体从文件中哪里开始读取,传入的mVideoBuffer引用用来装解码后的数据

2:蓝色部分调用的是OMXCodec::read函数,这个函数中核心的代码如下:status_t OMXCodec::read(

MediaBuffer **buffer, const ReadOptions *options) {

status_t err = OK;

*buffer = NULL;

bool seeking = false;

int64_t seekTimeUs;

ReadOptions::SeekMode seekMode;

if (options && options->getSeekTo(&seekTimeUs, &seekMode)) {

seeking = true;

}

if (seeking) {

CODEC_LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);

CHECK(seekTimeUs >= 0);

mSeekTimeUs = seekTimeUs;

mSeekMode = seekMode;

}

drainInputBuffers();

size_t index = *mFilledBuffers.begin(); // A list of indices into mPortStatus[kPortIndexOutput] filled with data.

mFilledBuffers.erase(mFilledBuffers.begin());

BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);

CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US);

info->mStatus = OWNED_BY_CLIENT;

info->mMediaBuffer->add_ref();

*buffer = info->mMediaBuffer;

return OK;

}

两点:

a,drainInputBuffers开始了数据的读取;

b,mFilledBuffers从这个队列中读取已经解码后的数据放入到传入的MediaBuffer中,mFilledBuffers队列中的MediaBuffer就是

drainInputBuffers中写进去的

3:跟到drainInputBuffer中看看

bool OMXCodec::drainInputBuffer(BufferInfo *info) {

CODEC_LOGV("calling emptyBuffer with codec specific data");

status_t err = mOMX->emptyBuffer(

mNode, info->mBuffer, 0, size,

OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG,

0);

CHECK_EQ(err, (status_t)OK);

info->mStatus = OWNED_BY_COMPONENT;

status_t err;

bool signalEOS = false;

int64_t timestampUs = 0;

size_t offset = 0;

int32_t n = 0;

for (;;) {

MediaBuffer *srcBuffer;

if (mSeekTimeUs >= 0) {

MediaSource::ReadOptions options;

options.setSeekTo(mSeekTimeUs, mSeekMode);

mSeekTimeUs = -1;

mSeekMode = ReadOptions::SEEK_CLOSEST_SYNC;

err = mSource->read(&srcBuffer, &options);

if (err == OK) {

int64_t targetTimeUs;

if (srcBuffer->meta_data()->findInt64(

kKeyTargetTime, &targetTimeUs)

&& targetTimeUs >= 0) {

CODEC_LOGV("targetTimeUs = %lld us", targetTimeUs); mTargetTimeUs = targetTimeUs;

} else {

mTargetTimeUs = -1;

}

}

}

}

CODEC_LOGV("Calling emptyBuffer on buffer %p (length %d), "

"timestamp %lld us (%.2f secs)",

info->mBuffer, offset,

timestampUs, timestampUs / 1E6);

err = mOMX->emptyBuffer(

mNode, info->mBuffer, 0, offset,

flags, timestampUs);

info->mStatus = OWNED_BY_COMPONENT;

return true;

}

两点:

a,调用err = mSource->read(&srcBuffer, &options);从原始文件中读取原始数据,

b,往srcBuffer中读取数据前后,都调用omx转移已经读取到该info中的数据,目的是解码,解码后的数据就房子了mFilledBuffers这个队列中;

4:针对mpeg4类型的视频,上面的read函数调用的是MPEG4Source的read函数,核心代码如下:

status_t MPEG4Source::read(

MediaBuffer **out, const ReadOptions *options) {

*out = NULL;

int64_t seekTimeUs;

ReadOptions::SeekMode mode;

if (options && options->getSeekTo(&seekTimeUs, &mode)) {

if分支是用于有seek的流程

1:首先找到seektime附近的sampleIndex;

2:然后找到sampleIndex附近的关键帧的syncSampleIndex;

3:然后syncSampleIndex找到具体的sampleTime,sampleTime就是

目前需要播放到的位置;

4:mSampleTable->getMetaDataForSample调用这个函数找到sampleTime时间的offset和size;

5:有了offset和size之后剩下就是调用mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);读取数据放到buffer中去了;

uint32_t findFlags = 0;

switch (mode) {

case ReadOptions::SEEK_PREVIOUS_SYNC:

findFlags = SampleTable::kFlagBefore;

break;

case ReadOptions::SEEK_NEXT_SYNC:

findFlags = SampleTable::kFlagAfter;

break;

case ReadOptions::SEEK_CLOSEST_SYNC:

case ReadOptions::SEEK_CLOSEST:

findFlags = SampleTable::kFlagClosest;

break;

default:

CHECK(!"Should not be here.");

break;

}

uint32_t sampleIndex;

status_t err = mSampleTable->findSampleAtTime(

seekTimeUs * mTimescale / 1000000,

&sampleIndex, findFlags);

uint32_t syncSampleIndex;

if (err == OK) {

err = mSampleTable->findSyncSampleNear(

sampleIndex, &syncSampleIndex, findFlags);

}

uint32_t sampleTime;

if (err == OK) {

err = mSampleTable->getMetaDataForSample(

sampleIndex, NULL, NULL, &sampleTime);

}

if (mode == ReadOptions::SEEK_CLOSEST) {

targetSampleTimeUs = (sampleTime * 1000000ll) / mTimescale; }

mCurrentSampleIndex = syncSampleIndex;

}

off64_t offset;

size_t size;

uint32_t cts;

bool isSyncSample;

bool newBuffer = false;

if (mBuffer == NULL) {

newBuffer = true;

status_t err =

mSampleTable->getMetaDataForSample(

mCurrentSampleIndex, &offset, &size, &cts, &isSyncSample);

if (err != OK) {

return err;

}

err = mGroup->acquire_buffer(&mBuffer);

if (err != OK) {

CHECK(mBuffer == NULL);

return err;

}

}

if (!mIsAVC || mWantsNALFragments) {

if (newBuffer) {

ssize_t num_bytes_read =

mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);

CHECK(mBuffer != NULL);

mBuffer->set_range(0, size);

mBuffer->meta_data()->clear();

mBuffer->meta_data()->setInt64(

kKeyTime, ((int64_t)cts * 1000000) / mTimescale);

if (isSyncSample) {

mBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);

}

++mCurrentSampleIndex;

}

if (!mIsAVC) {

*out = mBuffer;

mBuffer = NULL;

return OK;

}

// Each NAL unit is split up into its constituent fragments and // each one of them returned in its own buffer.

CHECK(mBuffer->range_length() >= mNALLengthSize);

const uint8_t *src =

(const uint8_t *)mBuffer->data() + mBuffer->range_offset();

size_t nal_size = parseNALSize(src);

MediaBuffer *clone = mBuffer->clone();

CHECK(clone != NULL);

clone->set_range(mBuffer->range_offset() + mNALLengthSize, nal_size);

CHECK(mBuffer != NULL);

mBuffer->set_range(

mBuffer->range_offset() + mNALLengthSize + nal_size, mBuffer->range_length() - mNALLengthSize - nal_size);

if (mBuffer->range_length() == 0) {

mBuffer->release();

mBuffer = NULL;

}

*out = clone;

return OK;

}

}

蓝色部分为主要的流程

5:后续就是开始调用SampleTable.cpp和SampleIterator.cpp这两个类的相关函数解析文件和读取数据,最主要的函数时通过sampleIndex获取offset和size信息了,代码如下:

status_t SampleTable::getMetaDataForSample(

uint32_t sampleIndex,

off64_t *offset,

size_t *size,

uint32_t *compositionTime,

bool *isSyncSample) {

Mutex::Autolock autoLock(mLock);

status_t err;

if ((err = mSampleIterator->seekTo(sampleIndex)) != OK) {

return err;

}

if (offset) {

*offset = mSampleIterator->getSampleOffset();

}

if (size) {

*size = mSampleIterator->getSampleSize();

}

if (compositionTime) {

*compositionTime = mSampleIterator->getSampleTime();

}

if (isSyncSample) {

*isSyncSample = false;

if (mSyncSampleOffset < 0) {

// Every sample is a sync sample.

*isSyncSample = true;

} else {

size_t i = (mLastSyncSampleIndex < mNumSyncSamples)

&& (mSyncSamples[mLastSyncSampleIndex] <= sampleIndex)

? mLastSyncSampleIndex : 0;

while (i < mNumSyncSamples && mSyncSamples[i] < sampleIndex) {

++i;

}

if (i < mNumSyncSamples && mSyncSamples[i] == sampleIndex) {

*isSyncSample = true;

}

mLastSyncSampleIndex = i;

}

}

return OK;

}

下面这个函数没有看懂,对具体的mpeg4压缩协议没有进行深入了解

status_t SampleIterator::findSampleTime(

uint32_t sampleIndex, uint32_t *time) {

if (sampleIndex >= mTable->mNumSampleSizes) {

return ERROR_OUT_OF_RANGE;

}

while (sampleIndex >= mTTSSampleIndex + mTTSCount) {

if (mTimeToSampleIndex == mTable->mTimeToSampleCount) {

return ERROR_OUT_OF_RANGE;

}

mTTSSampleIndex += mTTSCount;

mTTSSampleTime += mTTSCount * mTTSDuration;

mTTSCount = mTable->mTimeToSample[2 * mTimeToSampleIndex];

mTTSDuration = mTable->mTimeToSample[2 * mTimeToSampleIndex + 1];

++mTimeToSampleIndex;

}

*time = mTTSSampleTime + mTTSDuration * (sampleIndex - mTTSSampleIndex);

*time += mTable->getCompositionTimeOffset(sampleIndex);

return OK;

}

android系统开机启动流程分析

一,系统引导bootloader 加电,cpu执行bootloader程序,正常启动系统,加载boot.img【其中包含内核。还有ramdisk】 二,内核kernel bootloader加载kernel,kernel自解压,初始化,载入built-in驱动程序,完成启动。 内核启动后会创建若干内核线程,在后装入并执行程序/sbin/init/,载入init process,切换至用户空间(user-space) 内核zImage解压缩 head.S【这是ARM-Linux运行的第一个文件,这些代码是一个比较独立的代码包裹器。其作用就是解压Linux内核,并将PC指针跳到内核(vmlinux)的第一条指令】首先初始化自解压相关环境(内存等),调用decompress_kernel进行解压,解压后调用start_kernel启动内核【start_kernel是任何版本linux内核的通用初始化函数,它会初始化很多东西,输出linux版本信息,设置体系结构相关的环境,页表结构初始化,设置系 统自陷入口,初始化系统IRQ,初始化核心调度器等等】,最后调用rest_init【rest_init 会调用kernel_init启动init进程(缺省是/init)。然后执行schedule开始任务调度。这个init是由android的./system/core/init下的代码编译出来的,由此进入了android的代码】。 三,Init进程启动 【init是kernel启动的第一个进程,init启动以后,整个android系统就起来了】 init进程启动后,根据init.rc 和init. .rc脚本文件建立几个基本 服务(servicemanager zygote),然后担当property service 的功能 打开.rc文件,解析文件内容。【system/core/init/init.c】将service信息放置到service.list中【system/core/init/init_parser.c】。 建立service进程。【service_start(…) execve(…)】 在init.c中,完成以下工作 1、初始化log系统【解析/init.rc和init.%hardware%.rc文件,在两个 文件解析步骤2时执行“early-init”行动】 2、初始化设备【在/dev下创建所有设备节点,下载firmwares】 3、初始化属性服务器【在两个文件解析步骤2时执行“init”行动】

Android 开机启动流程

Android的开机流程 1. 系统引导bootloader 1) 源码:bootable/bootloader/* 2) 说明:加电后,CPU将先执行bootloader程序,此处有三种选择 a) 开机按Camera+Power启动到fastboot,即命令或SD卡烧写模式,不加载内核及文件系统,此处可以进行工厂模式的烧写 b) 开机按Home+Power启动到recovery模式,加载recovery.img,recovery.i mg包含内核,基本的文件系统,用于工程模式的烧写 c) 开机按Power,正常启动系统,加载boot.img,boot.img包含内核,基本文件系统,用于正常启动手机(以下只分析正常启动的情况) 2. 内核kernel 1) 源码:kernel/* 2) 说明:kernel由bootloader加载 3. 文件系统及应用init 1) 源码:system/core/init/* 2) 配置文件:system/rootdir/init.rc, 3) 说明:init是一个由内核启动的用户级进程,它按照init.rc中的设置执行:启动服务(这里的服务指linux底层服务,如adbd提供adb支持,vold提供SD卡挂载等),执行命令和按其中的配置语句执行相应功能 4. 重要的后台程序zygote 1)源码:frameworks/base/cmds/app_main.cpp等 2) 说明:zygote是一个在init.rc中被指定启动的服务,该服务对应的命令是/system/bin/app_process a)建立Java Runtime,建立虚拟机 b) 建立Socket接收ActivityManangerService的请求,用于Fork应用程序 c) 启动System Server 5. 系统服务system server 1)源码:frameworks/base/services/java/com/android/server/SystemServer.jav a 2) 说明:被zygote启动,通过SystemManager管理android的服务(这里的服务指frameworks/base/services下的服务,如卫星定位服务,剪切板服务等) 6. 桌面launcher 1)源码:ActivityManagerService.java为入口,packages/apps/launcher*实现 2) 说明:系统启动成功后SystemServer使用xxx.systemReady()通知各个服务,系统已经就绪,桌面程序Home就是在ActivityManagerService.systemReady()通知的过程中建立的,最终调用()启launcher 7. 解锁 1) 源码: frameworks/policies/base/phone/com/android/internal/policy/impl/*lock* 2) 说明:系统启动成功后SystemServer调用wm.systemReady()通知WindowManagerService,进而调用PhoneWindowManager,最终通过LockPatternKeyguardView显示解锁界面,跟踪代码可以看到解锁界面并不是一个Activity,这是只是向特定层上绘图,其代码了存放在特殊的位置

linux内核启动 Android系统启动过程详解

linux内核启动+Android系统启动过程详解 第一部分:汇编部分 Linux启动之 linux-rk3288-tchip/kernel/arch/arm/boot/compressed/ head.S分析这段代码是linux boot后执行的第一个程序,完成的主要工作是解压内核,然后跳转到相关执行地址。这部分代码在做驱动开发时不需要改动,但分析其执行流程对是理解android的第一步 开头有一段宏定义这是gnu arm汇编的宏定义。关于GUN 的汇编和其他编译器,在指令语法上有很大差别,具体可查询相关GUN汇编语法了解 另外此段代码必须不能包括重定位部分。因为这时一开始必须要立即运行的。所谓重定位,比如当编译时某个文件用到外部符号是用动态链接库的方式,那么该文件生成的目标文件将包含重定位信息,在加载时需要重定位该符号,否则执行时将因找不到地址而出错 #ifdef DEBUG//开始是调试用,主要是一些打印输出函数,不用关心 #if defined(CONFIG_DEBUG_ICEDCC)

……具体代码略 #endif 宏定义结束之后定义了一个段, .section ".start", #alloc, #execinstr 这个段的段名是 .start,#alloc表示Section contains allocated data, #execinstr表示Section contains executable instructions. 生成最终映像时,这段代码会放在最开头 .align start: .type start,#function /*.type指定start这个符号是函数类型*/ .rept 8 mov r0, r0 //将此命令重复8次,相当于nop,这里是为中断向量保存空间 .endr b 1f .word 0x016f2818 @ Magic numbers to help the loader

Android开机启动流程样本

Android的开机流程 1. 系统引导bootloader 1) 源码: bootable/bootloader/* 2) 说明: 加电后, CPU将先执行bootloader程序, 此处有三种选择 a) 开机按Camera+Power启动到fastboot, 即命令或SD卡烧写模式, 不加载内核及文件系统, 此处能够进行工厂模式的烧写 b) 开机按Home+Power启动到recovery模式, 加载recovery.img, recovery.img包含内核, 基本的文件系统, 用于工程模式的烧写 c) 开机按Power, 正常启动系统, 加载boot.img, boot.img包含内核, 基本文件系统, 用于正常启动手机( 以下只分析正常启动的情况) 2. 内核kernel 1) 源码: kernel/* 2) 说明: kernel由bootloader加载 3. 文件系统及应用init 1) 源码: system/core/init/* 2) 配置文件: system/rootdir/init.rc, 3) 说明: init是一个由内核启动的用户级进程, 它按照init.rc中的设置执行: 启动服务( 这里的服务指linux底层服务, 如adbd提供adb支持, vold提供SD卡挂载等) , 执行命令和按其中的配置语句执行相应功能 4. 重要的后台程序zygote 1) 源码: frameworks/base/cmds/app_main.cpp等 2) 说明: zygote是一个在init.rc中被指定启动的服务, 该服务对应的命令是/system/bin/app_process

Android系统启动过程详解

Android系统启动过程详解 Android系统启动过程 首先Android框架架构图:(来自网上,我觉得这张图看起来很清晰) Linux内核启动之后就到Android Init进程,进而启动Android相关的服务和应用。 启动的过程如下图所示:(图片来自网上,后面有地址)

下面将从Android4.0源码中,和网络达人对此的总结中,对此过程加以学习了解和总结, 以下学习过程中代码片段中均有省略不完整,请参照源码。

一Init进程的启动 init进程,它是一个由内核启动的用户级进程。内核自行启动(已经被载入内存,开始运行, 并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序init的方式,完成引导进程。init始终是第一个进程。 启动过程就是代码init.c中main函数执行过程:system\core\init\init. c 在函数中执行了:文件夹建立,挂载,rc文件解析,属性设置,启动服务,执行动作,socket监听…… 下面看两个重要的过程:rc文件解析和服务启动。 1 rc文件解析 .rc文件是Android使用的初始化脚本文件(System/Core/Init/readm e.txt中有描述: four broad classes of statements which are Actions, Commands, Services, and Options.) 其中Command 就是系统支持的一系列命令,如:export,hostname,mkdir,mount,等等,其中一部分是linux 命令, 还有一些是android 添加的,如:class_start :启动服务,class_stop :关闭服务,等等。 其中Options是针对Service 的选项的。 系统初始化要触发的动作和要启动的服务及其各自属性都在rc脚本文件中定义。具体看一下启动脚本:\system\core\rootdir\init.rc 在解析rc脚本文件时,将相应的类型放入各自的List中: \system\core\init\Init_parser.c :init_parse_config_file( )存入到 action_queue、action_list、service_list中,解析过程可以看一下parse_config函数,类似状态机形式挺有意思。 这其中包含了服务:adbd、servicemanager、vold、ril-daemon、deb uggerd、surfaceflinger、zygote、media…… 2 服务启动 文件解析完成之后将service放入到service_list中。 文件解析完成之后将service放入到service_list中。 \system\core\init\builtins.c

AndroidL系统启动及加载流程分析

Android L系统启动及加载流程分析 1、概述 Android L的启动可以分为几个步骤:Linux内核启动、init进程启动、native系统服务及java系统服务启动、Home启动,主要过程如下图: 图1 整个启动流程跟4.4及之前的版本相差不多,只是有个别不同之处,本文我们主要分析Linux内核启动之后的过程。

2、启动过程分析 2.1 init进程启动 当系统内核加载完成之后,会启动init守护进程,它是内核启动的第一个用户级进程,是Android的一个进程,进程号为1,init进程启动后执行入口函数main(),主要操作为: 图2 AndroidL上将selinux的安全等级提高了,设为了enforcing模式,4.4上是permissive模式。 解析rc脚本文件,即init.rc脚本,该文件是Android初始化脚本,定义了一系列的动作和执行这些动作的时间阶段e aryl-init、init、early-boot、boot、post-fs等阶段。init进程main 函数中会根据这些阶段进行解析执行。AndroidL上为了流程更清晰,增加了charger(充电开机)、ffbm(工厂模式)、以及late-init阶段,实际上这些阶段是对其他阶段的组合执行,比如late-init:

2.2 ServiceManager的启动 servicemanager的启动就是init进程通过init.rc脚本启动的: 源码在frameworks/native/cmds/servicemanager/service_manager.c中,servicemanager是服务管理器,它本身也是一个服务(handle=0),通过binder调用,为native和Java系统服务提供注册和查询服务的,即某个服务启动后,需要将自己注册到servicemanager中,供其他服务或者应用查询使用。AndroidL上servicemanger中在处理注册和查询动作之前添加了selinux安全检测相关的处理。 2.3 SurfaceFinger、MediaServer进程启动 Android4.4以前,surfacefinger的启动根据属性system_init.startsurfaceflinger,决定是通过init.rc启动还是systemserver进程启动,之后的版本包括AndoridL都是通过init.rc启动的: 启动后会向servicemanager进程注册服务中,该服务启动时主要功能是初始化整个显

android开机启动流程简单分析

android开机启动流程简单分析 android启动 当引导程序启动Linux内核后,会加载各种驱动和数据结构,当有了驱动以后,开始启动Android系统同时会加载用户级别的第一个进程init(system\core\init\init.cpp)代码如下: int main(int argc, char** argv) { ..... //创建文件夹,挂载 // Get the basic filesystem setup we need put together in the initramdisk // on / and then we'll let the rc file figure out the rest. if (is_first_stage) { mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"); mkdir("/dev/pts", 0755); mkdir("/dev/socket", 0755); mount("devpts", "/dev/pts", "devpts", 0, NULL); #define MAKE_STR(x) __STRING(x) mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)); mount("sysfs", "/sys", "sysfs", 0, NULL); } ..... //打印日志,设置log的级别 klog_init(); klog_set_level(KLOG_NOTICE_LEVEL); ..... Parser& parser = Parser::GetInstance(); parser.AddSectionParser("service",std::make_unique()); parser.AddSectionParser("on", std::make_unique()); parser.AddSectionParser("import", std::make_unique()); // 加载init.rc配置文件 parser.ParseConfig("/init.rc"); } 加载init.rc文件,会启动一个Zygote进程,此进程是Android系统的一个母进程,用来启动Android的其他服务进程,代码: 从Android L开始,在/system/core/rootdir 目录中有4 个zygote 相关的启动脚本如下图:

Android ninja 编译启动过程分析

Android ninja编译启动过程分析 ---make是如何转换到到ninja编译的 1.首先你的得对make的工作机制有个大概的了解: 运行的命令在要编译的目录下运行make,或者make target_name a.分析处理保存阶段(没有实际编译动作):它首先对当前目录下的Makefile文件的做一次扫描,语法分析,还有处理,主要是变量的保存,目标依赖列表生成,目标下的action列表的生成,然后记住 b.然后按记住的目标执行action列表动作(有实际编译动作). 编译启动的入口方式还是运行make: 2开始make-jxxx方式进入.....(xxx是本机cpu的数量) make开始做进行第一次扫描.... 目前USE_NINJA还是没有定义,估计以后很久很久才能启用的了! BUILDING_WITH_NINJA开始也是没定义的 看make扫描入口文件: Makefile: include build/core/main.mk 在build/core/main.mk: 在ninia之前都有include help.mk和config.mk 97include$(BUILD_SYSTEM)/help.mk 98 99#Set up various standard variables based on configuration 100#and host information. 101include$(BUILD_SYSTEM)/config.mk 说明make help//显示make帮助make config//当前显示配置 103relaunch_with_ninja:= 104ifneq($(USE_NINJA),false) 105ifndef BUILDING_WITH_NINJA<==第二次扫描不会到这里了 106relaunch_with_ninja:=true 107endif 108endif 116ifeq($(relaunch_with_ninja),true)<===第一次扫描入这里了 117#Mark this is a ninja build. 118$(shell mkdir-p$(OUT_DIR)&&touch$(OUT_DIR)/ninja_build) 119include build/core/ninja.mk//---进入ninja.mk 第一次扫描到此为止就结束掉了,因为在当前ifeq else endif后面没有代码了 120else#///!relaunch_with_ninja<===第二次扫描入这里了

Android应用程序内部启动Activity过程(startActivity)的源代码分析

上文介绍了Android应用程序的启动过程,即应用程序默认Activity的启动过程,一般来说,这种默认Activity是在新的进程和任务中启动的;本文将继续分析在应用程序内部启动非默认Activity的过程的源代码,这种非默认Activity一般是在原来的进程和任务中启动的。 这里,我们像上一篇文章Android应用程序启动过程源代码分析一样,采用再上一篇文章Android 应用程序的Activity启动过程简要介绍和学习计划所举的例子来分析在应用程序内部启动非默认Activity的过程。 在应用程序内部启动非默认Activity的过程与在应用程序启动器Launcher中启动另外一个应用程序的默认Activity的过程大体上一致的,因此,这里不会像上文Android应用程序启动过程源代码分析一样详细分析每一个步骤,我们着重关注有差别的地方。 回忆一下Android应用程序的Activity启动过程简要介绍和学习计划一文所用的应用程序Activity,它包含两个Activity,分别是MainActivity和SubActivity,前者是应用程序的默认Activity,后者是非默认Activity。MainActivity启动起来,通过点击它界面上的按钮,便可以在应用程序内部启动SubActivity。 我们先来看一下应用程序的配置文件AndroidManifest.xml,看看这两个Activity是如何配置的:view plain 1. 2. 6. 7. 9. 10. 11. 12. 13. 14. 16. 17. 18. 19. 20. 21. 22.

Android系统完整的启动过程

Android系统完整的启动过程,从系统层次角度可分为Linux系统层、Android系统服务层、Zygote进程模型三个阶段;从开机到启动Home Launcher完成具体的任务细节可分为七个步骤,下面就从具体的细节来解读Android系统完整的初始化过程。 一、启动BootLoader Android 系统是基于Linux操作系统的,所以它最初的启动过程和Linux一样。当设备通电后首先执行BootLoader引导装载器,BootLoader是在操作系统内核运行之前运行的一段小程序。通过这段小程序初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境引导进入合适的状态,以便为最终调用操作系统内核准备好正确的运行环境。 而Linux系统启动时: 1)首先要加载BIOS的硬件信息,并获取第一个启动设备的代号 2)读取第一个启动设备的MBR的引导加载程序(lilo、grub等)的启动信息。 3)加载核心操作系统的核心信息,核心开始解压缩,并且尝试驱动所有的硬件设备。 ………… 在嵌入式系统中,通常不会有像BIOS那样的固件程序,因此整个系统的加载任务都是通过BootLoader完成的。 二、加载系统内核 Linux内核映像通常包括两部分代码,分别为实模式代码和保护模式代码。当BootLoader装载内核映像到代码段内存时,分别放置实模式代码和保护模式代码到不同的位置,然后进入实模式代码执行,实模式代码执行完成后转入保护模式代码。 实模式和保护模式的概念再次不做过多解释,读者可以自行查阅资料。 三、启动Init进程 当系统内核加载完成之后,会首先启动Init守护进程,它是内核启动的第一个用户级进程,它的进程号总是1。Init进程启动完成之后,还负责启动其他的一些重要守护进程,包括: Usbd进程(USB Daemon):USB连接后台进程,负责管理USB连接。 adbd 进程(Android Debug Bridge Daemon):ADB连接后台进程,负责管理ADB连接。 debuggerd 进程(Debugger Daemon) :调试器后台进程,负责管理调试请求及调试过程。 rild进程(Radio Interface Layer Daemon):无线接口层后台进程,负责管理无线通信服务。 四、启动Zygote进程 Init进程和一些重要的守护进程启动完成之后,系统启动Zygote 进程。Zygote 进程启动后,首先初始化一个Dalvik VM实例,然后为它加载资源与系统共享库,并开启Socket监听服务,当收到创建Dalvik VM实例请求时,会通过COW(copy on write)技术最大程度地复用自己,生成一个新的Dalvik VM实例。Dalvik VM实例的创建方法基于linux系统的fork原理。

android应用程序开发流程要点

目录 1小结要点................................................................................................................................................................................. (11) (11) 2JAVA基础知识..................................................................................................................................................................... 3ANDROID应用程序开发环境搭建..................................................................................................................................... (22) (55) 4ANDROID应用程序目录结构............................................................................................................................................. 5新建一个ANDROID应用.................................................................................................................................................... (66) 6ANDROID四大组件及界面UI元素 (7) (88) 7ANDROID应用程序的工作机制......................................................................................................................................... (1212) 8ANDROID应用程序常用功能接口...................................................................................................................................

Android系统默认Home应用程序(Launcher)的启动过程源代码分析

在前面一篇文章中,我们分析了Android系统在启动时安装应用程序的过程,这些应用程序安装好之后,还需要有一个Home应用程序来负责把它们在桌面上展示出来,在Android系统中,这个默认的Home 应用程序就是Launcher了,本文将详细分析Launcher应用程序的启动过程。 Android系统的Home应用程序Launcher是由ActivityManagerService启动的,而ActivityManagerService和PackageManagerService一样,都是在开机时由SystemServer组件启动的,SystemServer组件首先是启动ePackageManagerServic,由它来负责安装系统的应用程序,具体可以参考前面一篇文章Android应用程序安装过程源代码分析,系统中的应用程序安装好了以后,SystemServer 组件接下来就要通过ActivityManagerService来启动Home应用程序Launcher了,Launcher在启动的时候便会通过PackageManagerServic把系统中已经安装好的应用程序以快捷图标的形式展示在桌面上,这样用户就可以使用这些应用程序了,整个过程如下图所示:

点击查看大图下面详细分析每一个步骤。 Step 1. SystemServer.main

这个函数定义在frameworks/base/services/java/com/android/server/SystemServer.java文件中,具体可以参考前面一篇文章Android应用程序安装过程源代码分析的Step 1。 Step 2. SystemServer.init1 这个函数是一个JNI方法,实现 在 frameworks/base/services/jni/com_android_server_SystemServer.cpp文件中,具体可以参考前面一篇文章Android应用程序安装过程源代码分析的Step 2。 Step 3. libsystem_server.system_init 函数system_init实现在libsystem_server库中,源代码位于 frameworks/base/cmds/system_server/library/system_init.cpp文件中,具体可以参考前面一篇文章Android应用程序安装过程源代码分析的Step 3。 Step 4. AndroidRuntime.callStatic 这个函数定义在frameworks/base/core/jni/AndroidRuntime.cpp文件中,具体可以参考前面一篇文章Android应用程序安装过程源代码分析的Step 4。 Step 5. SystemServer.init2 这个函数定义在frameworks/base/services/java/com/android/server/SystemServer.java文件中,具体可以参考前面一篇文章Android应用程序安装过程源代码分析的Step 5。 Step 6. ServerThread.run 这个函数定义在frameworks/base/services/java/com/android/server/SystemServer.java文件中,具体可以参考前面一篇文章Android应用程序安装过程源代码分析的Step 6。 Step 7. ActivityManagerService.main 这个函数定义在 frameworks/base/services/java/com/android/server/am/ActivityManagerServcie.java文件中: view plain 1.public final class ActivityManagerService extends ActivityManagerNative 2.implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { 3. ...... 4. 5.public static final Context main(int factoryTest) { 6. AThread thr = new AThread(); 7. thr.start(); 8. 9.synchronized (thr) { 10.while (thr.mService == null) { 11.try { 12. thr.wait(); 13. } catch (InterruptedException e) { 14. } 15. } 16. } 17. 18. ActivityManagerService m = thr.mService; 19. mSelf = m;

Android的RIL驱动模块启动流程

Android的RIL驱动模块启动流程 Android的RIL驱动模块,在hardware/ril目录下,一共分rild,libril.so 以及librefrence_ril.so三个部分,另有一radiooptions可供自动或手动调试使用。都依赖于include目录中ril.h头文件。目前cupcake分支上带的是gsm的支持,另有一cdma分支,这里分析的是gsm驱动。 GSM模块,由于Modem的历史原因,AP一直是通过基于串口的AT命令与BB交互。包括到了目前的一些edge或3g模块,或像omap这类ap,bp集成的芯片,已经使用了USB或其他等高速总线通信,但大多仍然使用模拟串口机制来使用AT命令。这里的RIL(Radio Interface Layer)层,主要也就是基于AT 命令的操作,如发命令,response解析等。(gprs等传输会用到的MUX协议等在这里并没有包含,也暂不作介绍。) 以下是详细分析,本文主要涉及基本架构和初始化的内容: 首先介绍一下rild与libril.so以及librefrence_ril.so的关系: 1. rild: 仅实现一main函数作为整个ril层的入口点,负责完成初始化。 2. libril.so: 与rild 结合相当紧密,是其共享库,编译时就已经建立了这一关系。组成部分为ril.cpp,ril_event.cpp。libril.so驻留在rild这一守护进程中,主要完成同上层通信的工作,接受ril请求并传递给librefrence_ril.so,同时把来自librefrence_ril.so的反馈回传给调用进程。 3. librefrence_ril.so: rild 通过手动的dlopen方式加载,结合稍微松散,这也是因为librefrence.so 主要负责跟Modem硬件通信的缘故。这样做更方便替换或修改以适配更多的Modem种类。它转换来自libril.so的请求为AT命令,同时监控Modem的反馈信息,并传递回libril.so。在初始化时,rild通过符号RIL_Init获取一组函数指针并以此与之建立联系。 4. radiooptions: radiooptiongs通过获取启动参数,利用socket与rild通信,可供调试时配置Modem参数。 接下来分析初始化流程,主入口是rild.c中的main函数,主要完成三个任务: 1. 开启libril.so中的event机制,在RIL_startEventLoop中,是最核心的由多路I/O驱动的消息循环。 2. 初始化librefrence_ril.so,也就是跟硬件或模拟硬件modem通信的部分(后

Android 6.0启动过程详细解析

Android 6.0启动过程详细解析 从代码角度仔细学习Android系统的启动过程,同时,学习Android启动过程中的初始化脚本语言,即init.rc中的语言语法。在这里,不在详细介绍Linux内核的启动过程,主要学习从Linux内核启动之后,init初始化是如何工作的,他是如何启动Android系统的第一个进程–Zygote进程。并且还会继续了解后面其他的进程是如何通过Zygote进程启动的。话不多说,我们现在就来气Android系统启动之路。 ## Android系统启动流程图 我们都知道,Android系统内核是基于Linux内核,所以在Android系统启动过程中,首先启动Linux内核,Bootloader加载并启动Linux内核,内核启动完成之后,内核开始启动Android系统的init进程,然后init进程通过init.rc启动脚本语言的执行,来启动Zygote进程,作为Android其他进程的父进程,Zygote进程做完初始化工作之后,启动SystemServer 来启动其他系统服务。 下面我们从init进程的启动开始学习。 int main(int argc, char** argv) { if (!strcmp(basename(argv[0]), "ueventd")) { return ueventd_main(argc, argv); }

if (!strcmp(basename(argv[0]), "watchdogd")) { return watchdogd_main(argc, argv); } // Clear the umask. umask(0); add_environment("PA TH", _PATH_DEFPATH); bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0); // Get the basic filesystem setup we need put together in the initramdisk // on / and then we'll let the rc file figure out the rest. if (is_first_stage) { mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"); mkdir("/dev/pts", 0755); mkdir("/dev/socket", 0755); mount("devpts", "/dev/pts", "devpts", 0, NULL); mount("proc", "/proc", "proc", 0, NULL); mount("sysfs", "/sys", "sysfs", 0, NULL); } // We must have some place other than / to create the device nodes for // kmsg and null, otherwise we won't be able to remount / read-only // later on. Now that tmpfs is mounted on /dev, we can actually talk // to the outside world. open_devnull_stdio(); klog_init(); klog_set_level(KLOG_NOTICE_LEVEL); NOTICE("init%s started!\n", is_first_stage ? "" : " second stage"); if (!is_first_stage) { // Indicate that booting is in progress to background fw loaders, etc. close(open("/dev/.booting", O_WRONL Y | O_CREAT | O_CLOEXEC, 0000)); property_init(); // If arguments are passed both on the command line and in DT, // properties set in DT always have priority over the command-line ones. process_kernel_dt(); process_kernel_cmdline(); // Propogate the kernel variables to internal variables

Android程序启动过程源码分析

Android应用程序启动过程源代码分析 分类:Android 2011-08-19 00:58 5447人阅读评论(40) 收藏举报 前文简要介绍了Android应用程序的Activity的启动过程。在Android系统中,应用程序是由Activity组成的,因此,应用程序的启动过程实际上就是应用程序中的默认Activity 的启动过程,本文将详细分析应用程序框架层的源代码,了解Android应用程序的启动过程。 在上一篇文章Android应用程序的Activity启动过程简要介绍和学习计划中,我们举例子说明了启动Android应用程序中的Activity的两种情景,其中,在手机屏幕中点击应用程序图标的情景就会引发Android应用程序中的默认Activity的启动,从而把应用程序启动起来。这种启动方式的特点是会启动一个新的进程来加载相应的Activity。这里,我们继续以这个例子为例来说明Android应用程序的启动过程,即MainActivity的启动过程。 MainActivity的启动过程如下图所示:

点击查看大图下面详细分析每一步是如何实现的。 Step 1. Launcher.startActivitySafely

在Android系统中,应用程序是由Launcher启动起来的,其实,Launcher本身也是一个应用程序,其它的应用程序安装后,就会Launcher的界面上出现一个相应的图标,点击这个图标时,Launcher就会对应的应用程序启动起来。 Launcher的源代码工程在packages/apps/Launcher2目录下,负责启动其它应用程序的源代码实现在src/com/android/launcher2/Launcher.java文件中: view plaincopy to clipboardprint? 1./** 2.* Default launcher application. 3.*/ 4.public final class Launcher extends Activity 5. implements View.OnClickListener, OnLongClickListener, LauncherMod el.Callbacks, AllAppsView.Watcher { 6. 7. ...... 8. 9. /** 10. * Launches the intent referred by the clicked shortcut. 11. * 12. * @param v The view representing the clicked shortcut. 13. */ 14. public void onClick(View v) { 15. Object tag = v.getTag(); 16. if (tag instanceof ShortcutInfo) { 17. // Open shortcut 18. final Intent intent = ((ShortcutInfo) tag).intent; 19. int[] pos = new int[2]; 20. v.getLocationOnScreen(pos); 21. intent.setSourceBounds(new Rect(pos[0], pos[1], 22. pos[0] + v.getWidth(), pos[1] + v.getHeight())); 23. startActivitySafely(intent, tag); 24. } else if (tag instanceof FolderInfo) { 25. ...... 26. } else if (v == mHandleView) {

相关主题
文本预览
相关文档 最新文档