android系统setting中的location&security选项下有一个“Use GPS satellites”选项框,这个选项框的是否勾选从软件上决定系统是否提供gps服务,但它并不能对硬件gps模块的开关起到作用,无论它勾选与否gps芯片实际上一直是处在运行状态的。笔者对android setting中的代码进行了一些改动,效果是可以通过“Use GPS satellites”选项的勾选与否控制gps模块的电源开关,以此降低系统能耗,提高性能。大体上的方法是在setting的代码包中加入了一个自己编写的简单的jni,由它调用内核中的电源控制gps的硬开关。
一java部分
“Use GPS satellites”的勾选决定了android 系统api中的locationmanager类是否加载gps服务,表现在代码中就是是否接受“gps”这个字符串作为参数。我们在这里要做的就是在setting的代码发送“gps”参数的同时,加入一个通过jni实现的开关gps电源的函数。
实现代码:
/packages/apps/Settings/src/com/android/settingsSecuritySettings.java->onPreferenceTreeClick
1)
……
} else if (preference == mGps) {
boolean enabled = mGps.isChecked();
Settings.Secure.setLocationProviderEnabled(getContentResolver(),
LocationManager.GPS_PROVIDER, enabled);
//++++++++++++++++此处调用gps开关电的功能函数
Native.switch_to(enabled);
//++++++++++++++++ add by chris
if (mAssistedGps != null) {
2)
……
//+++++++++++++此处声明jni的本地库,以及所需要调用的功能函数,在这里将功能函数封装在自定义的Native类中,关于jni调用的具体//规则具体规则请研究//development/samples/SimpleJNI
class Native {
static {
// The runtime will add "lib" on the front and ".o" on the end of the name supplied to loadLibrary.
System.loadLibrary("gps_power");
}
static native int switch_to(boolean a);
}
//+++++++++++++++++++++++++++++++ add by chris
二JNi部分
Java代码中只涉及到jni的调用,这里我们新建一个名叫jni的文件夹在/packages/apps/Settings路径下以用于存放c++代码。(只要代码内容和编译路径正确,文件名的位置和名称可以自行设定,不必非要放在setting下),这个文件夹内包含一个c++源文件gps_power.cpp和一个android.mk
Gps_power.cpp代码可以参考/development/samples/SimpleJNI/native.cpp,这里我们把gps开关功能的实现放在 switch_to函数中。
实现代码:
/packages/apps/Settings/jni/gps_power.cpp
/ packages/apps/Settings/jni/android.mk
static jint switch_to(JNIEnv *env, jobject thiz, jboolean enable) {
int fd;
char buf[256];
fd= open("/dev/device-pm",O_RDWR|O_CREAT);//打开负责控制gps电源的硬件节点
LOGI("fd=%d,gps power switch to %d", fd,enable);
ioctl(fd,3,enable); // 此处调用kernel代码中相关部分实现gps模块电源的控制
close(fd);
return fd;
}
下面的这个函数用于向android注册jni函数,左侧是在java调用中用的函数名,右侧是c或cpp中实际的函数名,中间的“(Z)”代表java调用时只有一个布尔型参数,I代表函数返回值为整型。
……
static JNINativeMethod methods[] = {
{"switch_to", "(Z)I", (void*)switch_to },
};
需要注意的是”static int registerNativeMethods” 函数中的第二个参数char* className,用于标识引用本段代码的java类,如笔者所用的java类即为com/android/settings/Native
三kernel部分
Kernel部分负责直接控制寄存器实现gps硬件系统的电源开关,笔者这里用到的硬件节点为/dev/device-pm,相关的系统调用功能号是3.由于不同开发板硬件设置不同,kernel中的实现代码也不尽相同。所以笔者在这里不做详细介绍,具体实现过程无非是向控制gps电源的端口发0或者发1。与那上层相对应的调用关系请查看有关驱动开发的书籍中ioctl相关章节。
最后一定要注意的是,gps模块的完全关电将会导致gps冷启动,从而大大延长gps定位时间。笔者所用的gps模块有一个Vbak引脚一直保持供电状态(耗电相比主电引脚低很多),所以可以保证主电关闭后不至于每次都冷启动。因此如果目标板gps模块上面没有这样一个备用电源引脚保持连接,不建议采用上述方法来给自己的板子省电。