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
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
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
3 #include
4 #include
5 #include
6 #include
7 #include
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
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
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 proc(ProcessState::self());
16 sp 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。
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{
@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