android——关于不被杀掉的service

             不被杀掉的service如果不root的话,我觉得是不现实的。因为各个系统之间的差异,还有各种安全软件的存在。这里说一下目前为止,可以想到的方法。

             1、尽量提高优先级

            android:priority = "1000"

            android:persistent="true"

           设置成前台服务

           返回START_STICKY

           销毁时自启

           监听开机,锁屏,电量改变广播

        

           2、自身使用aidl进行双服务守护

                 这个时候在正在运行设置中强行结束一个,另一个还可以起来。但是如果从任务管理强行停止就没办法


          3、无launch图标的app,运行守护服务

                这样可以保证从任务管理强行停止中恢复

                

          4、在守护应用的服务中,自身通过jni层面双线程进行守护


         其实做到这一步,问题就出在jni守护的服务还是会被系统自己回收掉,貌似是因为现在的android系统是杀线程组来实现的,而不是以前杀单一线程


        关于ndk的双线程守护,网上也有不少,但是缺少必要的头文件清单,可能有人对C++不熟,这里记录一个从网上寻找,自己调试成功的代码

     

#include <string.h>
#include <jni.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <fcntl.h>
#include <android/log.h>
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "keymatch", __VA_ARGS__)

extern "C"{
	//jstring转string
	char* jstringTostring(JNIEnv* env, jstring jstr)
	{
		   LOGD("字符串转换");
	       char* rtn = 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 barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
	       jsize alen = env->GetArrayLength(barr);
	       jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
	       if (alen > 0)
	       {
	                 rtn = (char*)malloc(alen + 1);
	                 memcpy(rtn, ba, alen);
	                 rtn[alen] = 0;
	       }
	       env->ReleaseByteArrayElements(barr, ba, 0);
	       return rtn;
	}

	//执行linux命令行
	void ExecuteCommandWithPopen(char* command, char* out_result, int resultBufferSize) {
	    FILE * fp;
	    out_result[resultBufferSize - 1] = '\0';
	    fp = popen(command, "r");
	    if (fp) {
	        fgets(out_result, resultBufferSize - 1, fp);
	        out_result[resultBufferSize - 1] = '\0';
	        pclose(fp);
	    } else {
	        LOGD("popen null,so exit");
	        exit(0);
	    }
	}

	//重启服务
	void check_and_restart_service(char* service) {
	    LOGD("当前所在的进程pid=%d,%s",getpid(),service);
	    char cmdline[200];
	    sprintf(cmdline, "am startservice --user 0 -n %s", service);
	    char tmp[200];
	    sprintf(tmp, "cmd=%s", cmdline);
	    ExecuteCommandWithPopen(cmdline, tmp, 200);
	}

	//该线程用来轮询检查服务状态
	void* thread(void* srvname) {
		LOGD("loop thread start!\n");
	    while(1){
	        check_and_restart_service((char*) srvname); // 应该要去判断service状态,这里一直restart 是不足之处
	        sleep(10000);
	    }
	    return NULL;
	}

	int start(int argc, char* srvname, char* sd) {
		LOGD("服务名%s",srvname);
		//linux的线程,在pthread.h中声明,实际是一个long变量
	    pthread_t id;
	    int ret;
	    struct rlimit r;

	    //linux中通过fork创建子线程,需要头文件为sys/types.h,unistd.h
	    int pid = fork();
	    LOGD("fork pid: %d", pid);
	    if (pid < 0) {
	    	LOGD("first fork() error pid %d,so exit", pid);
	    	//结束进程,包含在stdlib.h头文件中
	        exit(0);
	    } else if (pid != 0) {
	    	LOGD("first fork(): I'am father pid=%d", getpid());
	        //exit(0);
	    } else { //  第一个子进程
	    	LOGD("first fork(): I'am child pid=%d", getpid());
	        setsid();
	        LOGD("first fork(): setsid=%d", setsid());
	        umask(0); //为文件赋予更多的权限,因为继承来的文件可能某些权限被屏蔽,包含在sys/types.h和sys/stat.h头文件中

	        int pid = fork();
	        if (pid == 0) { // 第二个子进程
	            // 这里实际上为了防止重复开启线程,应该要有相应处理

	        	LOGD("I'am child-child pid=%d", getpid());
	            chdir("/"); //<span style="font-family: Arial, Helvetica, sans-serif;">修改进程工作目录为根目录,chdir(“/”)</span>
	            //关闭不需要的从父进程继承过来的文件描述符。
	            //RLIM_INFINITY表示无穷大,包含在sys/resource.h头文件中,实质是无符号长整型最大位数个1,0xffffff... ~0UL
	            if (r.rlim_max == RLIM_INFINITY) {
	                r.rlim_max = 1024;
	            }
	            int i;
	            for (i = 0; i < r.rlim_max; i++) {
	                close(i);
	            }

	            umask(0);
	            LOGD("创建守护线程");
	            ret = pthread_create(&id, NULL,thread, srvname); // 开启线程,轮询去监听启动服务
	            if (ret != 0) {
	                printf("Create pthread error!\n");
	                exit(1);
	            }
	            //O_RDWR包含在fcntl.h头文件中
	            int stdfd = open ("/dev/null", O_RDWR);
	            dup2(stdfd, STDOUT_FILENO);
	            dup2(stdfd, STDERR_FILENO);
	        } else {
	            exit(0);
	        }
	    }
	    return 0;
	}

	void Java_com_xf_ztimeGuid_receiver_Receiver_startServer(JNIEnv* env,jobject thiz,
			jstring cchrptr_ProcessName, jstring sdpath){
		LOGD("jni start!!!!!!\n");
		//得到进程名称
		char * rtn = jstringTostring(env, cchrptr_ProcessName);
		LOGD("complete convert jstring %s!\n",rtn);
		//得到文件路径
		char * sd = jstringTostring(env, sdpath);
		LOGD("Java_com_xf_ztime_base_activity_AlarmActivity_startServer run....ProcessName:%s", rtn);
		start(1, rtn, sd);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值