由于Andoid NDK守护进程只适用于5.0的系统以下,所以分开来写。
#include <android/log.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h> // for opendir(), readdir(), closedir()
#include <sys/stat.h> // for stat()
#include <stdarg.h>
#define BUFFER_LENGTH 1024
#define MAX_TIME 15
#define TAG "monitor"
#define PACKET_NAME "应用的包名"
#define PATH "/data/data/应用的包名"
#define RESTART_PATH "/data/data/应用的包名/restart"
#define SERVICE_NAME "应用的包名/应用的包名.service.MonitorService"
#define RUN_SERVICE "am startservice --user 0 -n 应用的包名/应用的包名.service.MonitorService"
#define LOGE(...) __android_log_print(2,TAG,__VA_ARGS__)
#define PROC_DIRECTORY "/proc/"
#define CASE_SENSITIVE 1
#define CASE_INSENSITIVE 0
#define EXACT_MATCH 1
#define INEXACT_MATCH 0
int main(int argc, char* argv[]) {
FILE *fp1;
char ch;
int count = 0;
LOGE("start run");
int pid=fork();
while (1) {
if (access(PATH, 0) == -1) {
LOGE("android unistall,program will quit");
exit(-1);
}
if (access(RESTART_PATH, 0) != -1) {
LOGE("need restart");
exit(-1);
}
if (count > MAX_TIME) {
count = 0;
pid_t pid = GetPIDbyName_Wrapper(PACKET_NAME) ; // If -1 = not found, if -2 = proc fs access error
if(pid!=-1 && pid!=-2)
{
LOGE("process exists ");
}else
{
LOGE("process not exists ");
myexec(RUN_SERVICE);
}
}
count = count + 1;
sleep(1);
}
return 0;
}
int32_t myexec(const char *cmd) {
FILE *pp = popen(cmd, "r");
if (!pp) {
// LOGE("run cmd fail");
return -1;
}
// char tmp[1024];
// while (fgets(tmp, sizeof(tmp), pp) != NULL ) {
// if (tmp[strlen(tmp) - 1] == '\n') {
// tmp[strlen(tmp) - 1] = '\0';
// }
// }
pclose(pp);
LOGE("run cmd success");
return 0;
}
int findProcess(char *processName) {
FILE *ptr;
char buff[512];
char ps[128];
sprintf(ps, "ps | grep -c %s", processName);
strcpy(buff, "ABNORMAL");
if ((ptr = popen(ps, "r")) != NULL) {
while (fgets(buff, 512, ptr) != NULL ) {
if (atoi(buff) >= 2) {
pclose(ptr);
return 1;
}
}
}
if (strcmp(buff, "ABNORMAL") == 0) /*ps command error*/
return 0;
pclose(ptr);
return 2;
}
//是不是数字
int IsNumeric(const char* ccharptr_CharacterList)
{
for ( ; *ccharptr_CharacterList; ccharptr_CharacterList++)
if (*ccharptr_CharacterList < '0' || *ccharptr_CharacterList > '9')
return 0; // false
return 1; // true
}
//intCaseSensitive=0大小写不敏感
int strcmp_Wrapper(const char *s1, const char *s2, int intCaseSensitive)
{
if (intCaseSensitive)
return !strcmp(s1, s2);
else
return !strcasecmp(s1, s2);
}
//intCaseSensitive=0大小写不敏感
int strstr_Wrapper(const char* haystack, const char* needle, int intCaseSensitive)
{
if (intCaseSensitive)
return (int) strstr(haystack, needle);
else
return (int) strcasestr(haystack, needle);
}
pid_t GetPIDbyName_implements(const char* cchrptr_ProcessName, int intCaseSensitiveness, int intExactMatch)
{
char chrarry_CommandLinePath[1000] ;
char chrarry_NameOfProcess[1000] ;
char* chrptr_StringToCompare = NULL ;
pid_t pid_ProcessIdentifier = (pid_t) -1 ;
struct dirent* de_DirEntity = NULL ;
DIR* dir_proc = NULL ;
int (*CompareFunction) (const char*, const char*, int) ;
if (intExactMatch)
CompareFunction = &strcmp_Wrapper;
else
CompareFunction = &strstr_Wrapper;
dir_proc = opendir(PROC_DIRECTORY) ;
if (dir_proc == NULL)
{
perror("Couldn't open the " PROC_DIRECTORY " directory") ;
return (pid_t) -2 ;
}
// Loop while not NULL
while ( (de_DirEntity = readdir(dir_proc)) )
{
if (de_DirEntity->d_type == DT_DIR)
{
if (IsNumeric(de_DirEntity->d_name))
{
strcpy(chrarry_CommandLinePath, PROC_DIRECTORY) ;
strcat(chrarry_CommandLinePath, de_DirEntity->d_name) ;
strcat(chrarry_CommandLinePath, "/cmdline") ;
FILE* fd_CmdLineFile = fopen (chrarry_CommandLinePath, "rt") ; //open the file for reading text
if (fd_CmdLineFile)
{
fscanf(fd_CmdLineFile, "%s", chrarry_NameOfProcess) ; //read from /proc/<NR>/cmdline
fclose(fd_CmdLineFile); //close the file prior to exiting the routine
if (strrchr(chrarry_NameOfProcess, '/'))
chrptr_StringToCompare = strrchr(chrarry_NameOfProcess, '/') +1 ;
else
chrptr_StringToCompare = chrarry_NameOfProcess ;
//printf("Process name: %s\n", chrarry_NameOfProcess);
//这个是全路径,比如/bin/ls
//printf("Pure Process name: %s\n", chrptr_StringToCompare );
//这个是纯进程名,比如ls
//这里可以比较全路径名,设置为chrarry_NameOfProcess即可
if ( CompareFunction(chrptr_StringToCompare, cchrptr_ProcessName, intCaseSensitiveness) )
{
pid_ProcessIdentifier = (pid_t) atoi(de_DirEntity->d_name) ;
closedir(dir_proc) ;
return pid_ProcessIdentifier ;
}
}
}
}
}
closedir(dir_proc) ;
return pid_ProcessIdentifier ;
}
//简单实现
pid_t GetPIDbyName_Wrapper(const char* cchrptr_ProcessName)
{
return GetPIDbyName_implements(cchrptr_ProcessName, 0,0);//大小写不敏感
}
编译此代码生成SO文件,并将SO文件放入资产文件中。
Android Service代码
</pre><p><pre name="code" class="java">import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by liyan on 15/3/9.
*/
public class MonitorService extends Service {
private static final String PROCESS_NAME = "monitor";
@Override
public void onCreate() {
super.onCreate();
restartMonitor();
}
private void restartMonitor() {
final File file = new File("/data/data/" + getPackageName() + "/restart");
if (!file.exists()) {
file.mkdir();
}
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
try {
file.delete();
// //运行监控程序
runMonitor();
} catch (Exception e) {
}
}
}, 1500);
}
private void runMonitor() {
try {
copy();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
runWatcher();
}
private void runWatcher() {
String path = "/data/data/" + getPackageName() + "/files";
String cmd2 = path + "/" + PROCESS_NAME;
String cmd3 = "chmod 777 " + cmd2;
rootCommand(cmd3);
rootCommand(cmd2);
}
public void copy() throws IOException {
// 看这里,设置你要copy到的路径,下面是我举的一个例子
File file = new File("/data/data/" + getPackageName() + "/files");
file.mkdir();
InputStream is = this.getAssets().open(PROCESS_NAME);
// 打开文件
FileOutputStream os = new FileOutputStream(
"/data/data/" + getPackageName() + "/files/" + PROCESS_NAME);
byte[] buffer = new byte[1024];
int count = 0;
// 将文件拷贝到目的地
while ((count = is.read(buffer)) > 0) {
// 写入即拷贝
os.write(buffer, 0, count);
}
is.close();
os.close();
}
public boolean rootCommand(String command) {
boolean result = false;
java.lang.Process process = null;
DataOutputStream outputStream = null;
try {
process = Runtime.getRuntime().exec("sh"); //获得shell.
outputStream = new DataOutputStream(process.getOutputStream());
outputStream.writeBytes("cd /data/data/" + getPackageName() + "\n"); //保证在command在自己的数据目录里执行,才有权限写文件到当前目录
outputStream.writeBytes(command + " &\n"); //让程序在后台运行,前台马上返回
outputStream.writeBytes("exit\n");
outputStream.flush();
process.waitFor();
result = true;
} catch (Exception e) {
e.printStackTrace();
result = false;
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
return result;
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
原理就是MonitorService 从资产文件中复制出守护程序到FILES目录,并启动守护Monitor,Monitor负责15秒检查一下主进程是否被杀死,如果被杀死,则重新启动MonitorService