android 开机启动流程分析(15)SystemServer部分服务解读

198 篇文章 98 订阅

该系列文章总纲链接:专题总纲目录 Android Framework 总纲


本章关键点总结 & 说明:

这里因为整体的导图太大,因此截取一部分 ,方便大家看的清楚:

这一部分实际上使用的就是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分析非常透彻,在此引用,链接如下:

Android System Server大纲之ClipboardService_flutter hook 解决 hasprimaryclip 和 getprimaryclipdes-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

图王大胜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值