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
---------------------
作者:Gunder
來源:CSDN
原文:https://blog.csdn.net/u013357557/article/details/81482729
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!