当前位置: 58彩票app下载 > 编程技术 > 正文

Android省电的地下

时间:2019-09-18 11:14来源:编程技术
前言## adb是查看系统状态一个很好的工具,本文使用adb来解读JobScheduler的状态。JobScheduler是google为了省电而设计的一种用于调度工作的机制,为了查看JobScheduler的运行效果,除了实际观

前言##

adb是查看系统状态一个很好的工具,本文使用adb来解读JobScheduler的状态。JobScheduler是google为了省电而设计的一种用于调度工作的机制,为了查看JobScheduler的运行效果,除了实际观察运行状态外,adb也是一种很不错的辅助调试工具。

前言:
准备记录一下自己的学习笔记,本文代码基于Android M 源码

目录##

一.系统服务JobSchedulerService二.注册的job记录文件jobs.xml三.job参数解释

1.编写AIDL

android/frameworks/base/core/java/android/os/ITestService.aidl

interface ITestService {
    test();
}
一.系统服务JobSchedulerService####

服务在SystemServer中注册,属于系统服务源码路径:/frameworks/base/services/java/com/android/server/SystemServer.java

mSystemServiceManager.startService(JobSchedulerService.class);

执行 adb shell service list查看系统服务,在列出的所有系统服务中可以找到

jobscheduler: [android.app.job.IJobScheduler]

2.修改mk文件

android/frameworks/base/Android.mk

LOCAL_SRC_FILES += 
    core/java/android/os/ITestService.aidl
二.注册的job记录文件jobs.xml####

源码路径:/frameworks/base/services/core/java/com/android/server/job/JobStore.java系统中的job记录在文件jobs.xml,完整路径是/data/system/job/jobs.xml,查看该文件手机要先root

 private JobStore(Context context, File dataDir) { mContext = context; mDirtyOperations = 0; File systemDir = new File(dataDir, "system"); File jobDir = new File(systemDir, "job"); jobDir.mkdirs(); mJobsFile = new AtomicFile(new File(jobDir, "jobs.xml")); mJobSet = new ArraySet<JobStatus>(); readJobMapFromDisk; }

cat命令查看该文件,文件记录着系统中此刻所有被调度的job

root@Xiaomi:/data/system/job # cat jobs.xml<?xml version='1.0' encoding='utf-8' standalone='yes' ?><job-info version="0"> <job job package="com.google.android.apps.maps" u> <constraints connectivity="true" idle="true" charging="true" /> <periodic period="86400000" delay="1485554596322" /> <extras /> </job> <job job package="com.google.android.apps.maps" u> <constraints connectivity="true" idle="true" charging="true" /> <one-off delay="1485444550825" /> <extras /> </job> <job job package="com.example.wfcvs" u> <constraints charging="true" /> <one-off delay="1485348887275" /> <extras /> </job> <job job package="android" u> <constraints connectivity="true" charging="true" /> <one-off deadline="1485591350955" delay="1485519812187" /> <extras /> </job> <job job package="android" u> <constraints idle="true" charging="true" /> <one-off delay="1485417599095" /> <extras /> </job></job-info>

3.编写真正工作的服务类,继承ITestService.Stub类

(目前他并不是一个真正的服务,下面会通过SystemServer注册)
android/frameworks/base/services/core/java/com/android/server/TestService.java

public class TestService extends ITestService.Stub {
    //实现ITestService.aidl中定义的接口。
    test()  {
        //调用native方法
    }
}
三.job参数解释####
参数 解释
jobid 每个job的id,android.app.job.JobInfo.Builder.Builder(int jobId, ComponentName jobService) 指定
package 包名
class job的类名,这个类继承于JobService
uid 应用uid
constraints job被调度的条件
one-off 跟时间相关,记录job的deadline,和延时执行的时间,注意这个是时间点,由函数systemclock.elapsedrealtime()生成,即系统启动的时间,到这个时间点job会被触发

例如:<constraints connectivity="true" charging="true" /> 代表网络连接并且在充电状态下,job会被调度<one-off delay="1485348887275" /> 代表job在满足条件的情况下,必须要等到1485348887275这个时间点才会被执行

jobs.xml文件需要手机root情况下才能查看,没有root要怎么查看呢?当然有方法,执行adb shell dumpsys jobscheduler

 adb shell dumpsys jobschedulerStarted users: u0Registered jobs: 117..:[ComponentInfo{com.google.android.apps.maps/com.google.android.apps.gmm.offline.OfflineAutoUpdateJobService},jId=137303610,u0,R=(-172:44:27,none),N=1,C=true,I=true,F=1,P=true,ANI=true] 148..:[ComponentInfo{com.google.android.apps.maps/com.google.android.apps.gmm.offline.OfflineAutoUpdateJobService},jId=137303609,u0,R=(-203:18:32,none),N=1,C=true,I=true,F=1,P=true,ANI=true] 849..:[ComponentInfo{com.example.wfcvs/com.example.wfcvs.wenfengService},jId=1,u0,R=(56:07,none),N=0,C=true,I=false,F=8,P=true,ANI=true] 246..:[ComponentInfo{android/com.android.server.MountServiceIdler},jId=808,u0,R=(-210:47:44,none),N=0,C=true,I=true,F=0,P=false,ANI=true]Conn.connected: true unmetered: true148..: C=true, UM=false117..: C=true, UM=falseAlarms (843148174)Next delay alarm in 3367sNext deadline alarm in 9223372036011627sTracking:849..: (846515518, N/A)Idle: false3 246.. 148.. 117..Batt.Stable power: true246885848,14863036,11761044,84957259AppIdleParole On: falseandroid:idle=false, com.google.android.apps.maps:idle=false, com.google.android.apps.maps:idle=false, com.example.wfcvs:idle=false,Pending:Active jobs:mReadyToRock=truemDeviceIdleMode=false

例如

849..:[ComponentInfo{com.example.wfcvs/com.example.wfcvs.wenfengService},jId=1,u0,R=(56:07,none),N=0,C=true,I=false,F=8,P=true,ANI=true]

849 代表这个job的hashcode的前三位R 代表延时时间和deadline,(56:07,none)代表延时到56:07才能执行,deadline为none代表没有deadline。N 代表网络C 代表充电I 代表idleF 代表调度失败的次数P 代表job是否Persist

好了,伙伴们,使用你们的adb工具感受下吧!新年快乐!!

4.编写一个TestService管理类,TestServiceManager,方便app调用

android/frameworks/base/core/java/android/os/TestServiceManager.java

public class TestServiceManager {
    private static final String TAG = "TestServiceManager";

    private final ITestService mService;

    public TestServiceManager() {
        mService = ITestService.Stub.asInterface(
                ServiceManager.getService("test"));
    }

    public TestServiceManager(Context context) {
        super(context);
        mService = ITestService.Stub.asInterface(
                ServiceManager.getService("test"));
    }

    public void test() {
        if (mService == null) {
            Log.w(TAG, "Failed");
            return;
        }
        try {
            mService.test();
        } catch (RemoteException e) {
            Log.w(TAG, "Failed.", e);
        }
    }
}

5.将自定义服务注册到SystemServer,使得开机过程中被添加。

android/frameworks/base/services/java/com/android/server/SystemServer.java
简单看一下流程,从main函数进入,会调用自身的run方法

public static void main(String[] args) {
      new SystemServer().run();
}

在run方法中,通过下面的方法启动:开机,核心,以及其他服务

private void run() {
    ...
    // Start services.
    try {
        startBootstrapServices();
        startCoreServices();
        startOtherServices();
     } catch (Throwable ex) {
        Slog.e("System", "******************************************");
        Slog.e("System", "************ Failure starting system services", ex);
        throw ex;
    }
    ...
}

因此可以把自己创建的service 添加到startOtherServices中

public final class SystemServer {
    ....
    private void startOtherServices() {
        ....
        TestService test = null;
        ....
        Slog.i(TAG, "Test Service");
        test = new TestService(context);
        ServiceManager.addService("test", test);
        //ServiceManager.addService(Context.TEST_SERVICE, test);
        ....
        try {
            test.systemReady();
        } catch (Throwable e) {
            reportWtf("making Test Service ready", e);
        }
    }
    ....
}

:另外可以把"test"字段,定义在Context中,方便从app中获取service
android/frameworks/base/core/java/android/content/Context.java

    public static final String TEST_SERVICE = "test";

6.让app侧,可以通过getSystemService接口获得服务

android/frameworks/base/core/java/android/app/ContextImpl.java
通过查看getSystemService实现

@Override
public Object getSystemService(String name) {
    return SystemServiceRegistry.getSystemService(this, name);
}

实际是通过SystemServiceRegistry.getSystemService来获取具体的服务
android/frameworks/base/core/java/android/app/SystemServiceRegistry.java

public static Object getSystemService(ContextImpl ctx, String name) {
        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        return fetcher != null ? fetcher.getService(ctx) : null;
}
private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
            new HashMap<String, ServiceFetcher<?>>();

获取系统服务是通过ServiceFetcher的getService来获取的,并且SYSTEM_SERVICE_FETCHERS就是一个Map实例,所以肯定是通过put方法为它赋值的, 通过registerService注册

private static <T> void registerService(String serviceName, Class<T> serviceClass,
            ServiceFetcher<T> serviceFetcher) {
        SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}

所以在SystemServiceRegistry的static静态代码块中进行注册

static {
.....
        registerService(Context.VIBRATOR_SERVICE, TestServiceManager.class,
                new CachedServiceFetcher<TestServiceManager>() {
            @Override
            public Vibrator createService(ContextImpl ctx) {
                return new TestServiceManager(ctx);
            }});
.....
}

7.更新API

由于在工程中添加了自己定义的类及常量,系统的api没有更新,因此需要先在工程中make clean然后make update-api,执行完后会发现frameworksbaseapicurrent.xml文件中多出自己定义的一些东西。current.xml这个文件包含了所有系统所有能被应用层使用的类及其方法等。
之后再使用make编出来的固件及jar包就能包含自定义的接口。

最后:
在framework 添加自己的服务就算完了,向上为app提供接口,向下与HAL层交互。下一步准备学习一下framework与HAL层之间的桥梁JNI。

编辑:编程技术 本文来源:Android省电的地下

关键词:

  • 上一篇:没有了
  • 下一篇:没有了