做系统开发,经常会为三方应用做一些定制性的功能,在提供api时我们可以考虑用广播,也可以用自定义系统服务,我这里说一下通过使用自定义系统服务的方式。一般没有特殊要求,都是添加到/frameworks/base/core/java/android/os 或者app下因为我这里是客户给定了调用包名,所以我是放在frameworks/base/core/java/com/下的。我在这的功能需求是给摩托罗拉的PTT对讲机项目提供修改和查看drx的api。那么什么是drx呢?

DRX:英文全称为Discontinuous Reception,即不连续接收,这种方法可以让UE周期性的在某些时候进入睡眠状态(sleep mode),不去监听PDCCH子帧,而需要监听的时候,则从睡眠状态中唤醒(wake up),这样就可以使UE达到省电的目的。虽然这样做对数据传输的时延有一定的影响,但如果这种时延并不影响用户体验,那么考虑到UE更为重要的功率消耗,执行DRX是很有意义的。

DRX是在LTE中引入的一种新的省电工作机制,使UE在没有数据传输时不需要进入空闲模式,仍保持与基站的同步状态。

功能:就是连续接收 和非连续接收的 timer,它的目的是更大的drx时间配置,理论上可能会更省一点电,降低功耗。

更多内容可点击这里去了解 DRX介绍。

第一步:写一个aidl接口WavePttDrx.aidl,添加你需要的方法

package com.kodiak.pttExtensions;
interface WavePttDrx{boolean changeDRX (int drx_value, int duration);int[] getSupportedModes();int getDefaultCycle();int getCurrentMode();
}
  • 更新Android.mk文件,在安卓10.0,则是在Android.bp里添加,在frameworks/base/Android.mk文件的LOCAL_SRC_FILES中系统添加了很多aidl文件,我们需要添加自己定义的WavePttDrx.aidl文件:

"core/java/com/kodiak/pttExtensions/WavePttDrx.aidl",


LOCAL_SRC_FILES += \core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl \.....core/java/com/com/kodiak/pttExtensions/WavePttDrx.aidl \

Android.bp

光这样配置的话,生成的api并没有服务管理类以及方法,虽然打包的framework.jar包在app验证编译没问题,但是运行会报找不到该方法的错误,所以还得再加上这句:

packages_to_document = [
    "android",
    "javax/microedition/khronos",
    "org/apache/http/conn",
    "org/apache/http/params",
    "com/kodiak/pttExtensions",
]

第二步:添加服务的实现类

WavePttDrxService,系统里的服务一般都是都是放frameworks/base/services/core/java/com/android/server目录下的,看需求。

在这里通过获取TelephonyManager的服务去调用QcrilHook层和qmi层通信,从而调用modem模块的set和get  drx方法,

在构造方法里直接获取手机默认的drx值并保存在全局,下面4个方法主要是为drx提供

boolean changeDRX (int drx_value, int duration);//修改drx值,duraion指设置新drx值生效的时间,所以在这里需要做个定时器,等生效时间到了,就设置回初始的drx值,当然定时器还没到时间执行任务时,如果再调用到这里,就得关掉之前的定时器。
    int[] getSupportedModes();//获取设备支持的所有drx值
    int getDefaultCycle();//获取默认值
    int getCurrentMode();//获取drx的当前值

package com.kodiak.pttExtensions;
/***Created by Grayson*/import com.kodiak.pttExtensions.WavePttDrx;import android.content.Context;import android.os.RemoteException;import android.util.Log;import android.telephony.TelephonyManager;import java.util.Timer;
import java.util.TimerTask;public class WavePttDrxService extends WavePttDrx.Stub{private static final String TAG = "WavePttDrxService";private TelephonyManager mTelephonyManager;private Context mContext = null;private int drx;//全局存放之前默认DRXprivate Timer timer = null;private TimerTask timerTask = null ;public WavePttDrxService(Context context) {Log.e(TAG,"wave");mTelephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);if(mTelephonyManager !=null){Log.e(TAG,"get mTelephonyManager");drx = mTelephonyManager.getDrx();}mContext = context;}@Overridepublic boolean changeDRX (int drx_value, int duration) throws RemoteException{if(timer != null){stopTimer();}mTelephonyManager = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);if(mTelephonyManager == null){return false;}Log.e(TAG,"changeDRX");boolean status =  mTelephonyManager.setDrx(drx_value);if (status) {Log.e(TAG,"changed DRX");if(duration >= 0 ){statTimer(duration);}}return status;}@Overridepublic int[] getSupportedModes() throws RemoteException{Log.e(TAG,"getSupportedModes");return  new int[]{320,640,1280,2560};//This is the dead value written in the enumeration}@Overridepublic int getDefaultCycle() throws RemoteException{Log.e(TAG,"getDefaultCycle");return drx;}@Overridepublic int getCurrentMode() throws RemoteException{mTelephonyManager = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);if(mTelephonyManager == null){return 0;}Log.e(TAG,"getCurrentMode");return mTelephonyManager.getDrx();}private void statTimer(int duration){// 初始化定时器if(timer != null) {timer = new Timer();}if(timerTask != null ){timerTask = new TimerTask() {@Overridepublic void run() {boolean status1 =  mTelephonyManager.setDrx(drx);//将drx设置回去}};}if(timer !=null && timerTask != null){timer.schedule(timerTask,duration*1000);}}private void stopTimer(){if (timer != null) {timer.cancel();timer = null;}if (timerTask != null) {timerTask.cancel();timerTask = null;}}
}
  • 创建对应的api管理类KNWakeup

frameworks/base/core/java/com/kodiak/pttExtensions/KNWakeup.java

这个管理类主要提供给三方app调用api方法,获取系统服务。

package com.kodiak.pttExtensions;/***created by Grayson*/import android.content.Context;import android.os.RemoteException;import com.kodiak.pttExtensions.WavePttDrx;public class KNWakeup{private static final String TAG = "KNWakeup";private WavePttDrx mService = null;private Context mContext;public KNWakeup(WavePttDrx service, Context context) {mService = service;mContext = context;}public boolean changeDRX(int drx_value, int duration){try{return mService.changeDRX(drx_value,duration);}catch(RemoteException e){e.printStackTrace();    }return false;}public int[] getSupportedModes(){try{return mService.getSupportedModes();}catch(RemoteException e){e.printStackTrace();return new int[]{320,640,1280,2560};//This is the dead value written in the enumeration}}public int getDefaultCycle(){ try{return mService.getDefaultCycle();}catch(RemoteException e){e.printStackTrace();   }return 0;}public int getCurrentMode(){try{return mService.getCurrentMode();}catch(RemoteException e){e.printStackTrace();  }return 0;}}

第三步:注册服务

跟着context.getSystemService代码,就可以知道系统服务的注册流程,实际上ContextImpl也是通过SystemServiceRegistry.getSystemService来获取具体的服务,这些系统服务都是在SystemServiceRegistry的static静态代码块中进行注册的,需要分别在SystemServer.java和SystemServiceRegistry.java中修改。

在SystemServer.java中将WavePttDrxService添加到ServiceManager中管理,这里我添加到了startOtherServices方法中

try {Slog.i(TAG, "WavePttDrx Service");                 ServiceManager.addService(Context.WAVE_PTT_DRX_SERVICE, new WavePttDrxService(context));} catch (Throwable e) {Slog.e(TAG, "Failure starting WAVE_PTT_DRX_SERVICE Service", e) }

在SystemServiceRegistry.java中注册我们的WavePttDrxService服务

import com.kodiak.pttExtensions.KNWakeup;
import com.kodiak.pttExtensions.WavePttDrx;...static {
...registerService(Context.WAVE_PTT_DRX_SERVICE, KNWakeup.class,new CachedServiceFetcher<KNWakeup>() {@Overridepublic KNWakeup createService(ContextImpl ctx) {IBinder b = ServiceManager.getService(Context.WAVE_PTT_DRX_SERVICE);WavePttDrx service = WavePttDrx.Stub.asInterface(b);return new KNWakeup(service,ctx);}});...
}

此处的Context.WAVE_PTT_DRX_SERVICE在Context.java中声明,然后在这里引用,比如系统中的其他服务调用时候的应用,都是在Context.java中定义的,比如 :

第四步:给服务添加SElinux权限

这一步也可以先不添加,等服务跑起的时候,会报错,需要添加啥权限加进去就可以了。我这里是在 system/sepolicy/public/service.te和 system/sepolicy/private/service_contexts 中添加,当然看系统需求,我们系统从26.0到29.0都加了,你们可以照着wifi_service添加。

service.te主要用来定义我们自己服务的类型比如system_api  app_api,不同厂商的定制可能导致该路径不同在该文件中已经定义了很多service类型,只需要依葫芦画瓢就行了。

service.te

service_contexts

第五步:调用QcrilHook层给qmi发送get和set指令

这里借助了telephony的服务,因为telephony里调了QcrilHook,所以我们需要在telephony的服务里加两个方法:get()和set()

frameworks/base/telephony/java/com/android/internal/telephony/ITelephony.aidl添加如下两个方法:

boolean setDrx(int drx_value);
 int getDrx();

在PhoneInterfaceManager.java中实现

packages/services/Telephony/src/com/android/phone/PhoneInterfaceManager.java中调用qcrilHook中的接口

 //add for drx@Overridepublic boolean setDrx(int drx_value){if(mQcRilHook == null){return false;}Log.d(LOG_TAG, "set_drx:"+drx_value);return mQcRilHook.qcRilSetDrx(drx_value);}@Overridepublic int getDrx(){if(mQcRilHook == null){return 0;}Log.d(LOG_TAG, "get_drx:"+1);return mQcRilHook.qcRilGetDrx();}

frameworks/base/telephony/java/android/telephony/TelephonyManager.java

//add for set drxpublic boolean setDrx(int drx_value){try {ITelephony telephony = getITelephony();if (telephony != null){Log.e(TAG, "set");return telephony.setDrx(drx_value);}} catch (RemoteException e) {Log.e(TAG, "Error calling ITelephony#setDrx", e);}return false;}//add for get drxpublic int getDrx(){try {ITelephony telephony = getITelephony();if (telephony != null){Log.e(TAG, "get");return telephony.getDrx();}} catch (RemoteException e) {Log.e(TAG, "Error calling ITelephony#getDrx", e);}return 0;}

vendor/qcom/proprietary/commonsys/qcrilOemHook/src/com/qualcomm/qcrilhook/IQcRilHook.java

定义和qcril_qmi通信的指令,即方法注册代码

int QCRIL_EVT_HOOK_SET_DRX = QCRILHOOK_BASE;
int QCRIL_EVT_HOOK_GET_DRX = QCRILHOOK_BASE;

vendor/qcom/proprietary/commonsys/qcrilOemHook/src/com/qualcomm/qcrilhook/QcRilHook.java中主要是通过sendRilOemHookMsg()方法向RIL发送消息调用接口,并取出返回值,这里传参是以流的形式,因为我们set的时候需要传一个参数value int型,所以需要4个字节,0代表默认卡的ID。

 public boolean qcRilSetDrx(int drx_value){Log.d(LOG_TAG, "QCRIL set_drx");boolean retval = false;int value;switch (drx_value){case 320:value = 0x06;break;case 640:value = 0x07;break;case 1280:value = 0x08;break;case 2560:value = 0x09;break;default:value = 0x00;break;}byte[] request = new byte[mHeaderSize + 4];ByteBuffer reqBuffer = createBufferWithNativeByteOrder(request);addQcRilHookHeader(reqBuffer, QCRIL_EVT_HOOK_SET_DRX, INT_SIZE);reqBuffer.putInt(value);AsyncResult ar = sendRilOemHookMsg(QCRIL_EVT_HOOK_SET_DRX, request,0);if (ar.exception == null){retval = true;} else {Log.e(LOG_TAG, "QCRIL set DRX backoff  cmd returned exception: "+ ar.exception);}return retval;}public int qcRilGetDrx(){Log.d(LOG_TAG, "QCRIL get_drx");byte result = 0;int drx_value = 0;byte[] request = new byte[mHeaderSize];ByteBuffer reqBuffer = createBufferWithNativeByteOrder(request);addQcRilHookHeader(reqBuffer, QCRIL_EVT_HOOK_GET_DRX, INT_SIZE);AsyncResult ar = sendRilOemHookMsg(QCRIL_EVT_HOOK_GET_DRX,request);if (ar.exception == null){drx_value = 1;Log.d(LOG_TAG, "QCRIL get_drx"+drx_value);if (ar.result != null) {drx_value = 2;Log.d(LOG_TAG, "QCRIL get_drx"+drx_value);byte[] response = (byte[]) ar.result;result = ByteBuffer.wrap(response).get();switch (result) {case 0x06:drx_value = 320;break;case 0x07:drx_value = 640;break;case 0x08:drx_value = 1280;break;case 0x09:drx_value = 2560;break;default:drx_value = 0x00;break;}}} else {Log.e(LOG_TAG, "QCRIL get DRX  backoff  cmd returned exception: "+ ar.exception);}Log.d(LOG_TAG, "QCRIL get_drx"+drx_value);return drx_value;}

由于篇幅太长,qmi的c接口以及编译流程放到下一篇文章里。

android 如何在系统为三方应用添加drx api 服务(一)相关推荐

  1. Android 10.0WallpaperPicker2添加动态壁纸服务

    1.概述 在10.0的系统产品开发中,在定制化开发中,由于需要动态壁纸,而系统自带的只有默认的静态壁纸, 所以需要添加动态壁纸的功能 2.WallpaperPicker2添加动态壁纸服务的核心类 pa ...

  2. android系统源码中添加app源码(源码部署移植)

    涉及到系统定制,需要在系统中加入自己的apk工程,但是上网找了很多资料都是不够全面的,或者看了还是没搞懂,我自己也是一点点摸索过来的,花了不少的时间,也是踩了不少的坑,因此特开一文,帮助大家渡河. 申 ...

  3. android中的系统应用

    重点 (Top highlight) Android's underlying kernel is based on Linux, but it has been customized to suit ...

  4. php 7 pcntl扩展,PHP_Linux系统中为php添加pcntl扩展,pcntl扩展可以支持php的多线程 - phpStudy...

    Linux系统中为php添加pcntl扩展 pcntl扩展可以支持php的多线程操作(仅限linux) 原本需要重新编译PHP的后面configrue提示加上--enable-pcntl 由于我的ph ...

  5. Android O限制系统全屏进一步遏制手机勒索

    一.引言 近期谷歌发布了最新手机操作系统Android O的开发者预览版,一如往常,Android O又带来了多项新功能与优化升级,其中一项有关系统窗口管理的优化给Android手机勒索软件带来了严重 ...

  6. Android应用与系统安全防御

    Android应用安全防御 Android应用的安全隐患包括代码安全.数据安全.组件安全.WebView等几个方面. 1. 代码安全 代码安全主要是指Android apk容易被反编译,从而面临软件破 ...

  7. android o测试版,一加手机可升级!谷歌已正式推送Android O测试版系统

    原标题:一加手机可升级!谷歌已正式推送Android O测试版系统 科客点评:怎么和iOS比起来,安卓新系统没什么人玩呢? 谷歌6月9日公布了第三个开发者预览版,同时也是用户测试版本的Android ...

  8. Android 5.x系统nfs挂载系统启动记录 nfs挂载文件记录

    应该有不少开发Android系统的人有这样的感觉,修改好了hal或者jni后,编译,验证的时候需要把编译的文件发到机器上去,那么发送的时候使用什么方式,应该是adb吧,我也是使用该方法.可是实际使用的 ...

  9. Android游戏开发系统控件-Dialog

    Android游戏开发系统控件-Dialog Dialog(对话框)在Android应用开发中经常用到,下面是学习<Android游戏编程从零开始>一书,关于Dialog的初步学习. 创建 ...

最新文章

  1. Android中的Handler
  2. centos 7 安装 google chrome 浏览器 (不是教程,只是为了以后自己可能用到)
  3. java 更改css_CSS样式更改——文本Content
  4. 现实世界的Windows Azure:采访InishTech的销售及市场部主管Andrew O’Connor
  5. nginx-zabbix监控脚本
  6. 最长续航达19小时,Surface Laptop 4商用版发售
  7. CSS3自定义浏览器滚动条样式
  8. 英特尔新任CEO的“开挂”人生
  9. 假如 C++ 是一只箭,你会用它来射哪只雕?
  10. 2019秋季学期第2周Java学习总结
  11. 去掉tomcat日志localhost_access_log修改去掉文件名日期
  12. 电商网站开发设计方案、电商网站开发重要性
  13. java 502错误_Spring Boot连接超时导致502错误的实战案例
  14. 怎么录屏幕视频?教你学会录制屏幕
  15. 周末之个人杂想(十五)
  16. 解决Android Studio Gradle慢的方法
  17. 【数据分析与挖掘(一)】笔试题汇总(附答案)
  18. 【机器学习】聚类分析与主成分分析(附例题源码)
  19. 界面打飞机游戏,C语言
  20. 关于赴日IT,你想知道的那些事儿

热门文章

  1. 求100到999中的水仙花数(两种方法,c语言)
  2. arm嵌入式项目经典15例
  3. 近期计划,让“易写易库(EXEK)”支持“斩月”?
  4. Linux大事记 |Linux发展大事记(转)
  5. 十行Python代码写一个聊天机器人
  6. 学习软件测试需要掌握哪些知识点呢(看这篇就行了)
  7. 如何在JavaScript中将十进制转换为十六进制
  8. iOS开发笔记--iOS应用架构谈 view层的组织和调用方案
  9. LVS-------------------------------
  10. 永远不要以为别人真正明白你的话