该系列文章总纲链接:专题分纲目录 android 开机启动流程分析
这里因为整体的导图太大,因此截取一部分 ,方便大家看的清楚:
这一部分实际上使用的就是SystemServer运行的步骤,在上图中关注➕“startOtherServices”部分即可。同时,下面的图是开机启动流程分析 持续迭代的效果,可放大观看。
1 EntropyService
熵表示粒子之间无规则的排列程度;或者说,表示系统紊乱程度,系统越“乱”,熵就越大;系统越有序,熵就越小 熵服务主要是为了让产生随机数时确保其不可预测性,即保证了随机数的随机性
//SS->startOtherServices->ServiceManager.addService("entropy", new EntropyMixer(context)); //从构造函数分析EntropyMixer public EntropyMixer(Context context,String entropyFile,String randomDevice,String hwRandomDevice) { ... //说明:entropyFile="/entropy.dat";randomDevice="/dev/urandom";hwRandomDevice = "/dev/hw_random" /** 功能:读文件entropyFile中内容,将其写入到randomDevice文件中{参数false表示sync} RandomBlock.fromFile(entropyFile).toFile(randomDevice, false); */ loadInitialEntropy(); /** 将一些和设备相关的信息写入randomDevice设备,信息如下: out.println(START_TIME); out.println(START_NANOTIME); out.println(SystemProperties.get("ro.serialno")); out.println(SystemProperties.get("ro.bootmode")); out.println(SystemProperties.get("ro.baseband")); ... */ addDeviceSpecificEntropy(); /** 功能:读文件hwRandomDevice中内容,将其写入到randomDevice文件中 RandomBlock.fromFile(hwRandomDevice).toFile(randomDevice, false); */ addHwRandomEntropy(); /** 功能:读文件randomDevice中内容,将其写入到entropyFile文件中 RandomBlock.fromFile(randomDevice).toFile(entropyFile, true); */ writeEntropy(); /** 功能:3小时后发送一次消息ENTROPY_WHAT mHandler.sendEmptyMessageDelayed(ENTROPY_WHAT, ENTROPY_WRITE_PERIOD); 消息处理handleMessage:{每隔3小时会执行一次该逻辑处理} addHwRandomEntropy(); writeEntropy(); scheduleEntropyWriter(); */ scheduleEntropyWriter(); /** 注册BroadcastReceiver,接收上电和重启的广播 注册的广播处理方法onReceive:->writeEntropy(); */ IntentFilter broadcastFilter = new IntentFilter(Intent.ACTION_SHUTDOWN); broadcastFilter.addAction(Intent.ACTION_POWER_CONNECTED); broadcastFilter.addAction(Intent.ACTION_REBOOT); context.registerReceiver(mBroadcastReceiver, broadcastFilter); }2 DBMS
DropBoxManagerService,记录着系统日志关键信息,主要是系统或者某个应用程序出错时的信息 @1 启动服务后,构造器实现如下:
//SS->startOtherServices->ServiceManager.addService( //Context.DROPBOX_SERVICE,new DropBoxManagerService(context, new File("/data/system/dropbox"))); public final class DropBoxManagerService extends IDropBoxManagerService.Stub { ... public DropBoxManagerService(final Context context, File path) { mDropBoxDir = path; //目录为/data/system/dropbox // Set up intent receivers mContext = context; mContentResolver = context.getContentResolver(); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW); //监听存储设备可用空间低的广播 filter.addAction(Intent.ACTION_BOOT_COMPLETED); //监听开机完毕的广播 context.registerReceiver(mReceiver, filter); //消息关联receiver //Settings数据库变化时则回调广播接收者的onReceive方法,此处CONTENT_URI=content://settings/global" mContentResolver.registerContentObserver( Settings.Global.CONTENT_URI, true, new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange) { //当setting数据库发生变化时,call mReceiver.onReceive mReceiver.onReceive(context, (Intent) null); } }); mHandler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == MSG_SEND_BROADCAST) {//发送广播 mContext.sendBroadcastAsUser((Intent)msg.obj, UserHandle.OWNER, android.Manifest.permission.READ_LOGS); } } }; } ... }3 DiskStatsService
@1 该服务主要是为dumpsys调试而生,本身并没有实现有效的具体功能,因此这里主要看其dump方法实现,如下:
//SS->startOtherServices->ServiceManager.addService("diskstats", new DiskStatsService(context)); protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); ...//执行一个性能测试:写512个字节,并测量其写入速度并通过日志输出 /** reportFreeSpace,获取制定目录剩余空间 通过stat方法获取BlockSize,AvailBlockSize,BlockCount 做一些简单的处理后输出 */ reportFreeSpace(Environment.getDataDirectory(), "Data", pw); reportFreeSpace(Environment.getDownloadCacheDirectory(), "Cache", pw); reportFreeSpace(new File("/system"), "System", pw); ... }DiskStatsService即为磁盘状态服务,继承Binder也是为了在使用dumpsys时可以常看磁盘的一些基本信息
@2 dumpsys调试时很常用的手段,代码实现如下:
int main(int argc, char* const argv[]) { signal(SIGPIPE, SIG_IGN); sp<IServiceManager> sm = defaultServiceManager(); ... Vector<String16> services; Vector<String16> args; //为dump方法的参数,可以根据所要查看service来填写 bool showListOnly = false; if ((argc == 2) && (strcmp(argv[1], "-l") == 0)) { showListOnly = true; } if ((argc == 1) || showListOnly) {//只执行dumpsys或dumpsys -l时会列出所有服务 services = sm->listServices(); services.sort(sort_func); args.add(String16("-a")); } else {//否则只会添加一个服务 services.add(String16(argv[1])); for (int i=2; i<argc; i++) { args.add(String16(argv[i])); } } const size_t N = services.size(); if (N > 1) { //打印出当前所有的服务 } if (showListOnly) { return 0; } ...//遍历所有的service,执行每个service的dump{服务名+参数}方法 //说明:这也就是为什么只执行dumpsys后会打出很多调试信息的原因 }4 DeviceStorageMonitorService
DeviceStorageMonitorService实际上就是一个检测内部存储空间状态的一个服务。
@1 首先,在SystemServer中添加该服务,直接看该服务的构造函数:
//mSystemServiceManager.startService(DeviceStorageMonitorService.class); public DeviceStorageMonitorService(Context context) { super(context); mLastReportedFreeMemTime = 0; mResolver = context.getContentResolver(); mIsBootImageOnDisk = isBootImageOnDisk(); //create StatFs object mDataFileStats = new StatFs(DATA_PATH.getAbsolutePath()); //获取data分区信息 mSystemFileStats = new StatFs(SYSTEM_PATH.getAbsolutePath()); //获取system分区信息 mCacheFileStats = new StatFs(CACHE_PATH.getAbsolutePath()); //获取cache分区信息 //获得data分区的总大小 mTotalMemory = (long)mDataFileStats.getBlockCount() * mDataFileStats.getBlockSize(); //创建intent,分别用于通知 存储空间不足、存储空间恢复正常、存储空间满 mStorageLowIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_LOW); mStorageLowIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); mStorageOkIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_OK); mStorageOkIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); mStorageFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_FULL); mStorageFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); mStorageNotFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_NOT_FULL); mStorageNotFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); }因为 DeviceStorageMonitorService 继承了SystemService,而在第一步执行startService时会调用该服务的onStart方法 @2 onStart方法实现如下:
public void onStart() { // cache storage thresholds final StorageManager sm = StorageManager.from(getContext()); //查询Setting数据库中的值,/data 分区不到10%时认为空间不足 mMemLowThreshold = sm.getStorageLowBytes(DATA_PATH); //当/data分区只剩下1M时,就认为空间已满,剩下1M留给系统自用 mMemFullThreshold = sm.getStorageFullBytes(DATA_PATH); mMemCacheStartTrimThreshold = ((mMemLowThreshold*3)+mMemFullThreshold)/4; mMemCacheTrimToThreshold = mMemLowThreshold + ((mMemLowThreshold-mMemCacheStartTrimThreshold)*2); mFreeMemAfterLastCacheClear = mTotalMemory; //检查内存 checkMemory(true); mCacheFileDeletedObserver = new CacheFileDeletedObserver(); mCacheFileDeletedObserver.startWatching(); publishBinderService(SERVICE, mRemoteService); publishLocalService(DeviceStorageMonitorInternal.class, mLocalService); }这里比较关注 checkMemory,实现如下:
void checkMemory(boolean checkCache) { if(mClearingCache) { //如果正在清理,不作处理 } else { restatDataDir();//重新计算 3各分区大小 if (localLOGV) Slog.v(TAG, "freeMemory="+mFreeMem); //post intent to NotificationManager to display icon if necessary if (mFreeMem < mMemLowThreshold) {//如果空间<mMemLowThreshold,先清理一次空间 if (checkCache) { //... clearCache();//call PkgMS清理空间 } else { mFreeMemAfterLastCacheClear = mFreeMem; //如果空间不足,则发送广播,状态栏设置警告 } } else { //... } //如果空间不足,则发送广播,状态栏设置警告 //... //如果空间已满,则发送一次存储已满广播 //... } //每分钟 触发一次检查 postCheckMemoryMsg(true, DEFAULT_CHECK_INTERVAL); }总结:该服务功能相对单一,没有重载dump函数,就是一个检测内部存储空间状态的一个服务
5 SamplingProfilerService服务解读
@1 该服务主要是为 性能采样和统计文件服务的,启动代码如下:
/**ServiceManager.addService ("samplingprofiler", new SamplingProfilerService(context)); */ public SamplingProfilerService(Context context) { mContext = context; registerSettingObserver(context); //监测setting数据库的变化 startWorking(context); }@2 这里继续分析 startWorking,代码实现如下:
private void startWorking(Context context) { final DropBoxManager dropbox = (DropBoxManager) context.getSystemService(Context.DROPBOX_SERVICE); //获取/data/snapshots目录下的文件 File[] snapshotFiles = new File(SNAPSHOT_DIR).listFiles(); for (int i = 0; snapshotFiles != null && i < snapshotFiles.length; i++) { //文件转移到dropbox中,然后删除这个文件 handleSnapshotFile(snapshotFiles[i], dropbox); } //监测,如果目录中来了新文件,把他们转移到dropbox中 snapshotObserver = new FileObserver(SNAPSHOT_DIR, FileObserver.ATTRIB) { @Override public void onEvent(int event, String path) { handleSnapshotFile(new File(SNAPSHOT_DIR, path), dropbox); } }; //inotify机制,监测文件变化 snapshotObserver.startWatching(); }服务启动后主要是将日志文件转移到dropbox,而性能分析主要是依靠 SamplingProfilerIntegration这个类完成 @3 系统中很多重要进程都需要对性能进行统计,比如Zygote,这里分析 zygoteInit.java的main方法,关注代码如下:
public static void main(String argv[]) { //启动性能分析 SamplingProfilerIntegration.start(); //...性能分析代码 //结束性能分析 SamplingProfilerIntegration.writeZygoteSnapshot(); }这里关注SamplingProfilerIntegration类,分析start方法以及 writeZygoteSnapshot方法 @3.1 启动性能分析代码如下:
public static void start() { if (!enabled) {//enable选项,SamplingProfilerIntegration类中static定义 return; } if (samplingProfiler != null) { Log.e(TAG, "SamplingProfilerIntegration already started at " + new Date(startMillis)); return; } ThreadGroup group = Thread.currentThread().getThreadGroup(); SamplingProfiler.ThreadSet threadSet = SamplingProfiler.newThreadGroupThreadSet(group); //创建对象 samplingProfiler = new SamplingProfiler(samplingProfilerDepth, threadSet); //启动性能统计,由dalvik虚拟机提供 samplingProfiler.start(samplingProfilerMilliseconds); startMillis = System.currentTimeMillis(); }@3.2 输出统计文件代码如下:
public static void writeZygoteSnapshot() { if (!enabled) { return; } //功能:在shots目录下生产一个统计文件名称的规则为“进程名_开始统计性能的时间戳.snapshot writeSnapshotFile("zygote", null); samplingProfiler.shutdown(); samplingProfiler = null; startMillis = 0; }性能分析 默认是不开启的,开启需要重新编译代码。同时 性能分析的核心实现在虚拟机代码来做的
6 ClipboardService
这里有一篇文章 对ClipboardService分析非常透彻,在此引用,链接如下:
https://blog.csdn.net/myfriend0/article/details/55267374
