Android JNI 分支C进程

来源:互联网 发布:韩端机器人编程软件 编辑:程序博客网 时间:2024/06/03 12:07

项目简介:

该项目在Android中分支出C进程

详细介绍:

点击按钮后个,调用C函数,在后台不断的 log 输出。当前的应用不会堵塞。即使杀死当前应用,后台仍然在不断的输出。除非杀死C所在的进程。
分支C进程应用的场景十分多,用这个准没好事,例如:
流氓软件:即关闭应用后,杀死Java进程,C程序再自动调用java启动应用,即使卸载了,C也可以自动调用代码下载。更为流氓的是,开启两个C进程,两个互相监控,只要其中任意一个被杀死就立即重启另一个,子子孙孙无穷尽。所以,手机一旦root后会开启最高权限,原本Android会禁止这种代码运行,root后就全可以了,风险大大的。

该应用涉及到的知识有:

  • 1.应用原理
    当前Activity调用C函数后,实际上Activity所在的进程与C所在的进程不是同一个进程(此时Java代码的作用就是启动C进程,启动后就没关系了),即使关闭了Activity所在进程,C进程活的好好的(实际上java进程很容易被杀死,C进程很难)。所以,随便在C进程中执行耗时操作,Java进程也不会阻塞。

  • 2.如何分支出C进程
    使用fork分支处一个C进程

  • 3.杀死C进程
    系统不会帮你杀,手动的图形界面也杀死不来(比如,直接在eclipse上的Device界面点击stop,没用).所以,只能使用dos窗口命令杀死这个进程

步骤:

1.创建一个Android项目

涉及到Java调用C代码,所以需要NDK。Add Native Support后,更改C++文件后缀名为C,更改Android.mk文件。

2.布局文件

编写activity_main.xml文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context="hhh.exercise.ujni_h_fork.MainActivity" >    <Button        android:onClick="click"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="点击开始" /></RelativeLayout>

布局文件仅仅只有一个按钮,用来启动C代码

3.Activity

编写MianActivity.Java文件:

import android.app.Activity;import android.os.Bundle;import android.view.View;public class MainActivity extends Activity {    static {        System.loadLibrary("Call");    }    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    }    /* 点击按钮,调用C语言 */    public void click(View view) {        callC();    }    public native void callC();}

4.JNI

编写Call.c文件:

#include <jni.h>#include <android/log.h>#define LOG_TAG    "HHH"#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG, __VA_ARGS__)JNIEXPORT void JNICALL Java_hhh_exercise_ujni_1h_1fork_MainActivity_callC(JNIEnv * env, jobject obj){    //  分支处C进程    int pid =fork();    //  如果为0,说明分支成功    if(pid==0){        while(1){            //  开启一个死循环。            //  在MainActivity中,当前C函数是直接被调用的,即与UI线程处于同一个进程中,死循环会导致堵塞            //  但是,当前C进程与已经被分支出来了,即UI线程与C线程所在的进程都不是同一个进程了,所以不会堵塞了            LOGI("Dead loop");            sleep(1);        }    }}

更改Android.mk文件:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_LDLIBS += -llogLOCAL_MODULE    := CallLOCAL_SRC_FILES := Call.cinclude $(BUILD_SHARED_LIBRARY)

5.杀死C进程

整个Demo已经完成了,安装在手机上后,点击按钮就会不断的输入Log日志,如下所示:

这里写图片描述

利用eclipse的ddms杀死当前进程,发现没有任何效果,即使到模拟器上去强制停止该应用,应用的确停止了,但是Log仍然在不断的输出。

这里写图片描述

这里是因为本地方法所在的进程与当前应用所在的线程不是同一个线程,可以看到应用所在进程的的ID有两个(8618和8700),所以杀死应用线程是没用的,应为只能杀死8618这个进程(即应用所在进程),而C进程(8700)没法杀死。

祭出绝招:通过在dos窗口下通过命令删除了

打开dos窗口,输入adb shell,等到下面出现#的时候,再输入ps:

这里写图片描述

确定后,dos窗口显示出当前模拟器所有正在运行的进程:

这里写图片描述

找到应用所在的PID(黄色箭头),然后输入kill 2782即可

这里写图片描述

再去看看Log日志,发现已经停止输出了

0 0
原创粉丝点击