浅谈Cfork子进程

首先,来谈一谈这个技术适用的场合吧。当一个用户把我们开发的APP卸载的时候,我们可能需要进行问卷调查,或者是进行一些推广。还有一种情况,就是像QQ,微信这样的实时通讯软件,需要实时占用着进程,可是Android有个特性,就是当内存不够的时候,会杀死一些进程,可能,这个被杀死的进程就是我们需要一直生存的进程。那么,这个时候C语言的fork函数就登场了,我们可以用JNI调用fork函数,然后通过返回值,进行我们想要的操作。具体我们来看看代码实现。

首先我们创一个工程就命名为Cfork。

MainActivity

public class MainActivity extends Activity {
    static{
        System.loadLibrary("cfork");
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public void fork(View v){
        cfork();
    }
    public native void cfork();
}

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="fork"
        android:text="分叉子进程" />
</RelativeLayout>

为了可以调试,我们加上这样一个头文件eben_hpc_log.h

#ifndef _Included_hpc_Log
#define _Included_hpc_Log
#ifdef __cplusplus
extern "C" {
#endif
#include <android/log.h>
// 宏定义类似java 层的定义,不同级别的Log LOGI, LOGD, LOGW, LOGE, LOGF。 对就Java中的 Log.i log.d
#define LOG_TAG    "hpc -- JNILOG" // 这个是自定义的LOG的标识
//#undef LOG // 取消默认的LOG
#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG, __VA_ARGS__)
#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG, __VA_ARGS__)
#define LOGW(...)  __android_log_print(ANDROID_LOG_WARN,LOG_TAG, __VA_ARGS__)
#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG, __VA_ARGS__)
#define LOGF(...)  __android_log_print(ANDROID_LOG_FATAL,LOG_TAG, __VA_ARGS__)

#ifdef __cplusplus
}
#endif
#endif

cfork.c

#include <jni.h>
#include <unistd.h>
#include <stdio.h>
#include "eben_hpc_log.h"
int ppid;
JNIEXPORT void JNICALL Java_com_mengxin_cfork_MainActivity_cfork
  (JNIEnv * env, jobject obj){
    int pid = fork();
    //fork成功的分叉出一个子进程 会返回当前进程的id 但是只能在主进程中fork成功
    //在子进程中运行fork 会返回0 但是不能再分叉出新的进程
    //fork的返回值可能三种  >0  == 0 <0
    FILE* file;
    if(pid>0){
        LOGD("pid = %d",pid);

    }else if(pid == 0){
        //拿到父进程的进程编号

        LOGD("pid == 0");
        while(1){
            ppid = getppid();
            //如果父进程的进程编号为1 说明父进程被杀死了
            if(ppid == 1){
                LOGD("ppid =%d",ppid);
                file = fopen("/data/data/com.mengxin.cfork","r");
                if(file == NULL){
                    //打开网页 调用am命令
                    //如果API16以上加上"--user","0",以下不用加
                    execlp("am", "am", "start", "--user","0", "-a", "android.intent.action.VIEW", "-d", "http://www.baidu.com", (char *) NULL);
                }else{
                    execlp("am", "am", "start", "--user","0", "-n", "com.mengxin.cfork/com.mengxin.cfork.MainActivity",(char *) NULL);

                }
                break;
            }
                    LOGD("sub process is running");
                    sleep(2);
        }
    }else{
        LOGD("pid<0 ");
    }
}

这里补充一点 am 命令

  • am命令 :在adb shell里可以通过am命令进行一些操作 如启动activity Service 启动浏览器等等
  • am命令的源码在Am.java中, 在adb shell里执行am命令实际上就是启动一个线程执Am.java的main方法,am命令后面带的参数都会当作运行时的参数传递到main函数中
  • am命令可以用start子命令,并且带指定的参数
  • 常见参数: -a: action -d data -t 表示传入的类型 -n 指定的组件名字
  • 举例: 在adb shell中通过am命令打开网页
  • am start –user 0 -a android.intent.action.VIEW -d http://www.baidu.com
  • 通过am命令打开activity
  • am start –user 0 -n com.itheima.fork/com.itheima.fork.MainActivity
  • (系统sdk版本>16 需要加上–user 0 , <16不需要加)

  • execlp c语言中执行系统命令的函数

  • execlp() 会从PATH环境变量所指的目录中查找符合参数file的文件找到后就执行该文件, 第二个参数开始就是执行这个文件的 args[0],args[1] 最后一个参数用(char*)NULL结束
  • android开发中 execlp函数对应android的path路径为system/bin/目录
  • 调用格式

    execlp("am", "am", "start", "--user","0","-a", "android.intent.action.VIEW", "-d", "http://www.baidu.com", (char *) NULL);
    

    最后修改build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.2"

    defaultConfig {
        applicationId "com.mengxin.cfork"
        minSdkVersion 15
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
        ndk {
            ldLibs "log"
            moduleName "cfork"         //生成的so名字
            //abiFilters "armeabi"  //输出指定三种abi体系结构下的so库。目前可有可无。
            abiFilters "armeabi", "armeabi-v7a", "x86"  //输出指定三种abi体系结构下的so库。目前可有可无。
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:24.2.0'
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值