Android 中的Java跟C/C++的Binder通信

1、大家都知道Android中进程间的通信是通过binder来实现的,这里主要是讲代码中的简单实现。如果想了解binder的通信细节或实现原理,可以参考https://blog.csdn.net/jmq_0000/article/details/7349844。个人觉得这篇博客讲的还是很不错的。现在就开始demo的介绍,该demo主要是通过java传递文件路径给C++来实现删除该路径,目的是为了了解java跟C++是怎么通过binder来通信的。首先是介绍C++端的代码,目录结构如下:

主要是四个文件Android.mk、DeleteFile.cpp、DeleteFile.h、DeleteFileService.cpp。先看一下头文件DeleteFile.h的里面的内容 

 1 #ifndef _DELETE_FILE
  2 #define _DELETE_FILE
  3
  4 #include <utils/RefBase.h>
  5 #include <binder/IInterface.h>
  6 #include <binder/Parcel.h>
  7 #include <utils/threads.h>
  8 #include <stdio.h>
  9 #include <stdbool.h>
 10 #include <android/log.h>
 11
 12 #define LOG_TAG "JPEG_JNI"
 13 #define DEBUG
 14 #define ANDROID_PLATFORM
 15
 16 #ifdef DEBUG
 17         #ifdef ANDROID_PLATFORM
 18                 #define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
 19                 #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
 20                 #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
 21                 #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
 22
 23
 24         #else
 25                 #define LOGD(fmt, ...) printf(fmt"\n", ##__VA_ARGS__)
 26                 #define LOGI(fmt, ...) printf(fmt"\n", ##__VA_ARGS__)
 27                 #define LOGW(fmt, ...) printf(fmt"\n", ##__VA_ARGS__)
 28                 #define LOGE(fmt, ...) printf(fmt"\n", ##__VA_ARGS__)
 29         #endif
 30 #else
 31         #define LOGD(...);
 32         #define LOGI(...);
 33         #define LOGW(...);
 34         #define LOGE(...);
 35 #endif
 36 38 namespace android{
 39         class DeleteFile: public BBinder{
 40         public:
 41                 static int instantiate();
 42                 DeleteFile();
 43                 virtual ~DeleteFile();
 44                 virtual status_t onTransact(uint32_t, const Parcel&, Parcel*, uint32_t);
 45         };
 46 }//namespace
 47
 48 #endif
 37

 头文件里面是主要定义Android的LOG打印及删除文件DeleteFile类的定义及方法声明。DeleteFile类中有四个方法,主要用的是instantiate()跟onTransact()的方法。看一下这两个方法的实现

27 int DeleteFile::instantiate(){
 28         int r = defaultServiceManager()->addService(String16(SERVICE_NAME), new DeleteFile());
 29         return r;
 30 }
 31
 32 status_t DeleteFile::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
 33                 uint32_t flags) {
 34         switch (code) {
 35         case DELETE_FILE:{
 36 //              int keep = data.readInt32();
 37                 String16 path = data.readString16();
 38                 LOGD("[%s(L:%d)] path = %s\n", __FUNCTION__, __LINE__, String8(path).string());
 39                 int result = dealDeleteFiles(String8(path).string());
 40                 reply->writeInt32(result);
 41                 system("sync");
 42                 return 0;
 43         }
 44         break;
 45         default: {
 46                         return BBinder::onTransact(code, data, reply, flags);
 47                 }
 48                         break;
 49         }
 50 }

instantiate() 方法主要是向defaultServiceManager中添加自己定义的服务,服务的名称是chinatsp.autoaction。而onTransact()就是真正通信的方法,在服务启动的情况下,C++中的onTransact()方法跟Java中的binder.transact(cmd, data, reply, 0)进行通信的。方法中code跟data是java中的transact里面的cmd跟data传递过来的,dealDeleteFiles(String8(path).string())方法是实现删除java端传递过来的指定目录的,它的实现非常简单,就是通过rm -rf path 命令删除目录。

12 int dealDeleteFiles(const char* path){
 13         char* cmd = (char*) malloc(16 + strlen(path));
 14         memset(cmd, 0, sizeof(cmd));
 15         sprintf(cmd, "rm -rf %s", path);
 16         int result = system(cmd);
 17         free(cmd);
 18         return result;
 19 }

DeleteFile.cpp完整代码如下:

1 #include "DeleteFile.h"
  2 #include <binder/IServiceManager.h>
  3 #include <binder/IPCThreadState.h>
  4 #include <cutils/log.h>
  5 #include <sys/types.h>
  6 #include <sys/stat.h>
  7 #include <fcntl.h>
  8
  9 #define DELETE_FILE 0x01
 10 #define SERVICE_NAME "chinatsp.autoaction"
 11
 12 int dealDeleteFiles(const char* path){
 13         char* cmd = (char*) malloc(16 + strlen(path));
 14         memset(cmd, 0, sizeof(cmd));
 15         sprintf(cmd, "rm -rf %s", path);
 16         int result = system(cmd);
 17         free(cmd);
 18         return result;
 19 }
 20
 21 namespace android{
 22 DeleteFile::DeleteFile(){
 23 }
 24 DeleteFile::~DeleteFile(){
 25
 26 }
 27 int DeleteFile::instantiate(){
 28         int r = defaultServiceManager()->addService(String16(SERVICE_NAME), new DeleteFile());
 29         return r;
 30 }
 31
32 status_t DeleteFile::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
 33                 uint32_t flags) {
 34         switch (code) {
 35         case DELETE_FILE:{
 36 //              int keep = data.readInt32();
 37                 String16 path = data.readString16();
 38                 LOGD("[%s(L:%d)] path = %s\n", __FUNCTION__, __LINE__, String8(path).string());
 39                 int result = dealDeleteFiles(String8(path).string());
 40                 reply->writeInt32(result);
 41                 system("sync");
 42                 return 0;
 43         }
 44         break;
 45         default: {
 46                         return BBinder::onTransact(code, data, reply, flags);
 47                 }
 48                         break;
 49         }
 50 }
 51
 52 }//namespace

接下来再看一下DeleteFileService.cpp的代码实现:

 1 #include <sys/types.h>
  2 #include <unistd.h>
  3 #include <grp.h>
  4 #include <binder/IPCThreadState.h>
  5 #include <binder/ProcessState.h>
  6 #include <binder/IServiceManager.h>
  7 #include <private/android_filesystem_config.h>
  8 #include "DeleteFile.h"
  9
 10 using namespace android;
 11 int main(int argc, char** argv)
 12 {
 13         LOGD("main begin.....");
 14         LOGD("[%s(L:%d)] \n", __FUNCTION__, __LINE__);
 15         sp<ProcessState> proc(ProcessState::self());
 16         sp<IServiceManager> sm = defaultServiceManager(); //取得 ServiceManager
 17         DeleteFile::instantiate();
 18         ProcessState::self()->startThreadPool(); //启动缓冲池
 19         IPCThreadState::self()->joinThreadPool(); //这里是把服务添加到 Binder闭合循环进程中
 20         LOGD("main end.....");
 21 }

可以看到main函数里面只有5行的关键代码,15-19中只有17行是自己定义的方法,其他都是binder绑定服务需要调用的。最后一个文件Android.mk也很简单 ,就不做介绍了,代码如下:

 1 LOCAL_PATH:= $(call my-dir)
  2
  3 include $(CLEAR_VARS)
  4
  5 LOCAL_SRC_FILES:= DeleteFile.cpp DeleteFileService.cpp
  6 LOCAL_C_INCLUDES := \
  7         DeleteFile.h \
  8         $(JNI_H_INCLUDE)
  9 LOCAL_SHARED_LIBRARIES := \
 10         liblog \
 11         libutils \
 12         libandroid_runtime \
 13         libbinder \
 14         libcutils
 15 LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog
 16 LOCAL_MODULE:= tspautoservice
 17 include $(BUILD_EXECUTABLE)

到这里C++端的代码就介绍完了,接下在就是Java端的代码了,主要涉及两个java类及一个布局文件:

java端的界面布局backup_log_fragment.xml很简单,只有一个Button。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <Button 
        android:id="@+id/delelte_log"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/delete_log"/>

</LinearLayout>

BackupLogsFragment.java类主要是点击事件及 DeleteLogsTask异步实现删除目录路径传递,这里要删除的是/data/media目录(data目录下的medai目录)

package com.gunder.tool.fragment;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;

import com.gunder.tool.R;
import com.gunder.tool.utils.Logger;
import com.gunder.tool.utils.TLogUtils;

public class BackupLogsFragment extends Fragment implements OnClickListener{
	Button deleteLog;
	@Override
	public View onCreateView(LayoutInflater inflater,
			 ViewGroup container,  Bundle savedInstanceState) {
		return inflater.inflate(R.layout.backup_log_fragment, container, false);
	}
	
	@Override
	public void onViewCreated(View view,  Bundle savedInstanceState) {
		super.onViewCreated(view, savedInstanceState);
		
		initView(view);
		
	}

	private void initView(View root) {
		deleteLog = (Button) root.findViewById(R.id.delelte_log);
		deleteLog.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.delelte_log:
			deleteLogs();
			break;

		default:
			break;
		}
	}
	
	//开始删除日志
	private void deleteLogs(){
		 final String delete_path = "/data/media";
		 new DeleteLogsTask().execute(delete_path);
	}
	
	private class DeleteLogsTask extends AsyncTask<String, String, String>{
		
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			Toast.makeText(getActivity(), "delete file ...", Toast.LENGTH_LONG).show();
		}

		@Override
		protected String doInBackground(String... params) {
			boolean result = true;
			String path = params[0];
			Logger.d("path = " + path);
			boolean ret = deleteLog(path);
			result = result && ret;
			return result ? "success" : "failed";
		}
		protected boolean deleteLog(String path){
			Logger.d();
			return TLogUtils.deleteLog(path);
		}
		
		@Override
		protected void onPostExecute(String result) {
			super.onPostExecute(result);
			Toast.makeText(getActivity(), "delete " + result, Toast.LENGTH_LONG).show();
		}
	}
}

 BackupLogsFragment.java类中的实行流程大概如下onClick-->deleteLogs-->doInBackground-->deleteLog-->TLogUtils.deleteLog,发现最后会执行TLogUtils类中的deleteLog静态方法,现在来看一下TLogUtils类中的代码:

package com.gunder.tool.utils;

import java.io.File;

import android.os.IBinder;
import android.os.Parcel;
import android.os.ServiceManager;
import android.os.SystemProperties;

public class TLogUtils {
	//向C++中传递cmd命令,C++对应的参数是code
	private final static int DELETE_FILES = 0x1;
	//如果文件存在,就执行deleteLog方法
	public static boolean deleteLog(String src){
		Logger.d("src = " + src);
		if (null == src){
			return false;
		}
		String path = src;
		while ((!path.isEmpty()) && path.charAt(path.length() - 1) == '/')
		{
			path = path.substring(0, path.length() - 1);
		}
		path = path.trim();
		Logger.d("path = " + path);
		if (path.isEmpty()){
			Logger.d("path is empty");
			return true;
		}
		boolean result = false;
		File file = new File(path);
		if (file.exists()){
			result = deleteLogFiles(file);
		}else {
			result = true;
		}
		if (!result){
			Logger.d("delete log failed: " + src);
		}
		return result;
	}

	//如果文件是目录,执行deleteLogFilesUseRoot,否则直接file.delete()
	private static boolean deleteLogFiles(File file) {
		Logger.d();
		if (file != null && file.exists()){
			Logger.d();
			if (file.isDirectory()){
				Logger.d();
				return deleteLogFilesUseRoot(file.getAbsolutePath());
			}
		}else {
			Logger.d();
			return file.delete();
		}
		return true;
	}

	//对要删除的路径进行Parcel写入
	private static boolean deleteLogFilesUseRoot(String absolutePath) {
		Logger.d("absolutePath = " + absolutePath);
		Parcel data = Parcel.obtain();
		data.writeString(absolutePath);
		return dealUseRoot(DELETE_FILES, data);
	}

	/**
	 * 启动chinatsp.autoaction服务,并且调用binder.transact向C++中的onTransact进行通信
	 * @param cmd 传递命令,这里是DELETE_FILES = 0x1,跟C++端的定义是一样的
	 * @param data 传递路径,这里是/data/media
	 * @return
	 */
	private static boolean dealUseRoot(int cmd, Parcel data) {
		IBinder binder = null;
		final int MAX_WAIT = 9; //最多获取service 10次
		int index = 0;
		SystemProperties.set("ctl.start", "tsp_auto_service");
		do {
			Logger.d("get service : chinatsp.autoaction");
			binder = ServiceManager.getService("chinatsp.autoaction");
			if (null == binder){
				try {
					Thread.sleep(100);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}while ((null == binder) && ((index++) < MAX_WAIT));
		if (null == binder){
			Logger.d("get service of autoaction failed");
			data.recycle();
			SystemProperties.set("ctl.stop", "tsp_auto_service");
			return false;
		}
		Parcel reply = Parcel.obtain();
		int result = -1;
		try {
			Logger.d("cmd = " + cmd);
			binder.transact(cmd, data, reply, 0);
			result = reply.readInt();
		} catch (Exception e) {
			Logger.d("send cmd to autoaction service : error");
		}
		data.recycle();
		reply.recycle();
		SystemProperties.set("ctl.stop", "tsp_auto_service");
		return result == 0;
	}
}

 TLogUtils类中实行流程是这样的:deleteLog-->deleteLogFiles-->deleteLogFilesUseRoot-->dealUseRoot。具体代码相信大家可以看懂。最后需要在init.rc中配置一下自定义的服务chinatsp.autoaction的对应的可执行文件tspautoservice,不然调用SystemProperties.set("ctl.start", "tsp_auto_service")不会启动服务。init.rc配置如下:

245 service tsp_auto_service /system/bin/tspautoservice
246     class main
247     disabled

好了,到这里就介绍完了。

项目的编译可以参考:https://blog.csdn.net/u013357557/article/details/81411686

完整的代码路径:https://github.com/gunder1129/android-tool/tree/master/ToolTemplate 

猜你喜欢

转载自blog.csdn.net/u013357557/article/details/81482729