我的第一个Android 驱动程序,驱动层 到framworks层

对于未知的技术我们心里总是比较忐忑,当你走进发现原来并不是你想象中那么难,关键是我们需要勇敢迈出第一步----------Bill  2019.08.23 

      本文分两部分:一、驱动层的添加

                              二、framworks层的代码添加,以及应用层的调用。

一、驱动层的添加

         1.向内核添加我的驱动程序

             kernel-3.18\drivers\misc\mediatek\Kconfig     

                  增加:source "drivers/misc/mediatek/word_count/Kconfig"       word_count/Kconfig:我的驱动配置信息

              kernel-3.18\drivers\misc\mediatek\Kconfig\Makefile     

               增加:obj-$(CONFIG_WORD_COUNT) += word_count/     CONFIG_WORD_COUNT 在cofig文件中配置:                                                                                                                                  CONFIG_WORD_COUNT =y

         需要特别说明一下:obj-y 表示程序编译到内核,obj-c 表示只是编译驱动程序,而没有加载到内核

        2.编写驱动程序

         

#include 
#include 
#include 
#include 
#include 
#include 


//  定义设备文件名
#define DEVICE_NAME "wordcount"
static unsigned char mem[10000]; // 保存向设备文件写入的数据
static int word_count = 0;
#define TRUE 255
#define FALSE 0

//  判断指定字符是否为空格(包括空格符、制表符、回车符和换行符)
static unsigned char is_spacewhite(char c)
{
	if (c == 32 || c == 9 || c == 13 || c == 10)
		return TRUE;
	else
		return FALSE;
}

static int get_word_count(const char *buf)
{
	int n = 1;
	int i = 0;
	char c = ' ';

	char flag = 0; // 处理多个空格分隔的情况,0:正常情况,1:已遇到一个空格
	if (*buf == '\0')
		return 0;
	//  第1个字符是空格,从0开始计数
	if (is_spacewhite(*buf) == TRUE)
		n--;

	//  扫描字符串中的每一个字符
	for (; (c = *(buf + i)) != '\0'; i++)
	{
		//  只由一个空格分隔单词的情况
		if (flag == 1 && is_spacewhite(c) == FALSE)
		{

			flag = 0;
		}
		//  由多个空格分隔单词的情况,忽略多余的空格
		else if (flag == 1 && is_spacewhite(c) == TRUE)
		{

			continue;
		}
		//  当前字符为空格是单词数加1
		if (is_spacewhite(c) == TRUE)
		{
			n++;
			flag = 1;
		}
	}
	//  如果字符串以一个或多个空格结尾,不计数(单词数减1)
	if (is_spacewhite(*(buf + i - 1)) == TRUE)
		n--;
	return n;
}

static ssize_t word_count_read(struct file *file, char __user *buf,
        size_t count, loff_t *ppos)
{
	unsigned char temp[4];
	printk("xiaoshuilin word count read");
	temp[0] = word_count >> 24;
	temp[1] = word_count >> 16;   
	temp[2] = word_count >> 8;
	temp[3] = word_count;
//由于驱动程序是运行在内核空间,而我们的android程序是运行在用户空间,他们之间是不能直接交互的需要借助一些接口来实现数据的交互copy_to_user copy_from_user 这两个方法就linux提供的接口
	if (copy_to_user(buf, (void*) temp, 4))
	{
		return -EINVAL;
	}
	printk("xiaoshuilin word count read:%d", (int) count);

	return count;
}

static ssize_t word_count_write(struct file *file, const char __user *buf,
        size_t count, loff_t *ppos)
{
	ssize_t written = count;
		printk("xiao word count write");

	if (copy_from_user(mem, buf, count))
	{
		return -EINVAL;
	}
	mem[count] = '\0';
	word_count = get_word_count(mem);
	printk("xiao write:word count:%d\n", (int) word_count);

	return written;
}

//  描述与设备文件触发的事件对应的回调函数指针
static struct file_operations dev_fops =
{ .owner = THIS_MODULE, .read = word_count_read, .write = word_count_write };

//  描述设备文件的信息   
static struct miscdevice misc =
{ .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops };


//  初始化Linux驱动
static int __init word_count_init(void)
{
	int ret; 

	//  建立设备文件
	ret = misc_register(&misc);

	//  输出日志信息
	printk("xiao word_count_init_success  ret=%d\n",ret);


	return ret;
}

// 卸载Linux驱动
static void __exit word_count_exit(void)
{
	//  删除设备文件  
	misc_deregister(&misc);

	//  输出日志信息
	printk("word_count_init_exit_success\n");
} 

//  注册初始化Linux驱动的函数,驱动程序的入口,相当于activity里面的oncreate
module_init( word_count_init);
//  注册卸载Linux驱动的函数   驱动程序的出口,相当activity里面的destroy
module_exit( word_count_exit);

MODULE_AUTHOR("lining");
MODULE_DESCRIPTION("statistics of word count.");
MODULE_ALIAS("word count module.");
MODULE_LICENSE("GPL");

至此驱动程序添加完成,不过我们还需要为其添加读写权限:

system\core\rootdir\eventd.rc    ## xiao
/dev/wordcount            0666   root       root

至此驱动部分添加完成。

二、framworks层的代码添加,以及应用层的调用

     思路:添加一个类似activityManager的服务,来完成应用层调用驱动。

 1.添加服务

   frameworks\base\services\java\com\android\server\SystemServer.java

   private void startOtherServices() {

......省略不相关的代码

  WordCountManagerService WordCountManager = null;

    //add  worcountManaerService
            try{
             traceBeginAndSlog("WordCountManagerService");
             Slog.e(TAG, "start WordCountManagerService now");
            WordCountManager = new WordCountManagerService(context);
             ServiceManager.addService(Context.WORDCOUNT_SERVICE, WordCountManager);//把实例保存起来为应用层调用做准备
            traceEnd();
            }catch(Throwable e){
                Slog.e(TAG, "start WordCountManagerService fail:"+e.toString());
                 reportWtf("starting WordCountManagerService fail", e);
                }

 }

WordCountManagerService 代码:

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server;


import android.util.Log;
import android.content.Context;
import android.app.IWordCountManager;

    //M: change default to public as DataShapingService
public class WordCountManagerService extends IWordCountManager.Stub {
	private final String TAG="XIAO-WordCountManagerService";
    private final Context mContext;
    public WordCountManagerService(Context context){
    	mContext=context;
    	Log.d(TAG,"init WordCountManagerService");
    	}  	
    	@Override
    	public String read(){
    		String readOpen=readFromEvent();
    		Log.d(TAG,"readOpen form jni: "+readOpen);
    		return readOpen;
    		}
    		
    		
    	@Override
    	public void writer(String data){
    		Log.d(TAG,"writer to jni: "+data);
    		writerToEvent(data);
    		}	
    		
    private native String readFromEvent();
    private native void writerToEvent(String writer);
}

frameworks\base\core\java\android\app\SystemServiceRegistry.java

 static {
............省略不相关代码
//通过这个代码的实现,后续在应用层中通过getSystemService(WordCountManager.class),就可以获取到WordCountManager 

			 registerService(Context.WORDCOUNT_SERVICE, WordCountManager.class,
                new CachedServiceFetcher() {
            @Override
            public WordCountManager createService(ContextImpl ctx) throws ServiceNotFoundException {
                IBinder b = ServiceManager.getServiceOrThrow(Context.WORDCOUNT_SERVICE);
                IWordCountManager service = IWordCountManager.Stub.asInterface(b);
                return new WordCountManager(service);
            }});
}

frameworks\base\core\java\android\app\IWordCountManager.aidl

interface IWordCountManager {
  String read();
  void writer(String data);

frameworks\base\core\java\android\app\WordCountManager.java



package android.app;
import android.os.RemoteException;
public class WordCountManager {
    private  final String TAG = "XIAO-WordCountManager";
   private final IWordCountManager mService;

    public WordCountManager(IWordCountManager mService) {
        this.mService = mService;
    }

    public String read() {
    	String data=null;
        try {
           data= mService.read();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        } 
        return data;        
    }

    public void writer(String data) {
        try {
            mService.writer(data);
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }
    
}

此处服务添加完成,不过还需要Android.mk上做修改否则会出现找不到类的情况。

frameworks\base\Android.mk 

LOCAL_SRC_FILES += \

                                 core/java/android/app/IWordCountManager.aidl 

2.增加服务与驱动的交互,服务是java层代码,驱动是C/C++。所以我们需要增加一个JNI。

   frameworks\base\services\core\jni\com_android_server_WordCountManagerService.cpp

/* //device/libs/android_runtime/android_server_AlarmManagerService.cpp
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/

#define LOG_TAG "WordCountManagerService"

#include 
#include "jni.h"
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

namespace android {

	char* jstring_to_pchar(JNIEnv* env, jstring str)
		{
		char* pstr = NULL;
		jclass clsstring = env->FindClass("java/lang/String");
		jstring strencode = env->NewStringUTF("utf-8");
		jmethodID mid = env->GetMethodID(clsstring, "getBytes",
			        "(Ljava/lang/String;)[B");
		jbyteArray byteArray = (jbyteArray)(
			        (env)->CallObjectMethod(str, mid, strencode));
		jsize size = (env)->GetArrayLength( byteArray);
		jbyte* pbyte = (env)->GetByteArrayElements(byteArray, JNI_FALSE);
		if (size > 0)
		{
			pstr = (char*) malloc(size);
			memcpy(pstr, pbyte, size);
		}
		 env->DeleteLocalRef(clsstring);
		return pstr;
	}


static void android_server_WordCountManagerService_writerToEvent(JNIEnv* env, jobject obj, jstring data)
{
   

    int dev;
	dev = open("/dev/wordcount", O_WRONLY);
	char* pstr = jstring_to_pchar(env, data);
	ALOGD("XIAO-android_server_WordCountManagerService_writerToEvent dev=%d ,pstr=%s\n",dev,pstr);
	//const char* pstr = env->GetStringUTFChars(data, NULL);
	if (pstr != NULL)
	{
	ssize_t write_size=	write(dev,pstr, strlen(pstr));
	ALOGD("XIAO-android_server_WordCountManagerService_writerToEvent write_size=%d \n",write_size);
	}
	close(dev);   

   
}

static jstring android_server_WordCountManagerService_readFromEvent(JNIEnv* env, jobject obj)
{
   int dev;
   int size;
	char* buf=NULL;
  struct stat statbuf;
	dev = open("/dev/wordcount", O_RDONLY);
	if(dev!=-1){	
    fstat(dev,&statbuf);
    size=statbuf.st_size;
		}else{
			size=50;
			}
			size=50;
		char bufs[size];
     buf=bufs;
	 ssize_t read_size=read(dev, buf, size);	
	 ALOGD("XIAO-android_server_WordCountManagerService_readFromEvent dev=%d ,size=%d\n",dev,size);
	ALOGD("XIAO-android_server_WordCountManagerService_readForEvent buf=%s, read_size=%d \n",buf,read_size);
	if(buf!=NULL){
	jstring data=env->NewStringUTF(buf);
	ALOGD("XIAO-android_server_WordCountManagerService_readForEvent data=%s \n",data);
		close(dev);
	return data;
 }

	close(dev);
	return NULL;
}
/// M: added for powerOffAlarm feature @{


static const JNINativeMethod sMethods[] = {
     /* name, signature, funcPtr */
    {"writerToEvent", "(Ljava/lang/String;)V", (void*)android_server_WordCountManagerService_writerToEvent},
    {"readFromEvent", "()Ljava/lang/String;", (void*)android_server_WordCountManagerService_readFromEvent},
};

int register_android_server_WordCountManagerServic(JNIEnv* env)
{
    return jniRegisterNativeMethods(env, "com/android/server/WordCountManagerService",
                                    sMethods, NELEM(sMethods));
}

} /* namespace android */

frameworks\base\services\core\jni\Android.mk

LOCAL_SRC_FILES += \ 

                                       $(LOCAL_REL_DIR)/com_android_server_WordCountManagerService.cpp

 

frameworks\base\services\core\jni\onload.cpp

 namespace android {
int register_android_server_WordCountManagerServic(JNIEnv* env);//添加动态注销JNI的方法。

}

extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
    JNIEnv* env = NULL;
    jint result = -1;

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        ALOGE("GetEnv failed!");
        return result;
    }
    ALOG_ASSERT(env, "Could not retrieve the env!");

    register_android_server_WordCountManagerServic(env);//调用注册方法

}

 

你可能感兴趣的:(#,驱动,#,JNI)