Android 守护进程 (NDK Service 单工机制)

个人笔记,学习于腾讯课堂

(1.模拟器7.0系统成功保活  2.真机小米8 8.0android系统 无效)

0.项目结构

1.在项目中配置ndk(略)

CMakeList.txt

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
             native-lib

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             native-lib.cpp )

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
                       native-lib

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

2.jni调用类 Watcher.kt

class Watcher {

    init {
        System.loadLibrary("native-lib")
    }

    public external fun createWatcher(userId: String)

    public external fun  connectMonitor()

}

3.后台服务 ProcessService.kt

package com.example.socketprocess

import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.os.Process
import android.util.Log
import java.util.*

/**
 * Just :
 * @author by Zian
 * @date on 2019/07/02 10
 */
class ProcessService : Service() {

    override fun onBind(p0: Intent?): IBinder? {
        return null
    }

    override fun onCreate() {
        super.onCreate()
        val watcher = Watcher()
        watcher.createWatcher(Process.myUid().toString())
        watcher.connectMonitor()
        var i = 0
        val timer = Timer()
        timer.scheduleAtFixedRate(object : TimerTask() {
            override fun run() {
                i++
                Log.w("ProcessService:", "服务开启中 $i")
            }
        }, 0, 1000 * 3)
    }
}

3.1头文件配置 native-lib.h

//
// Created by Zian on 2019/7/2.
//

#ifndef SOCKETPROCESS_NATIVE_LIB_H
#define SOCKETPROCESS_NATIVE_LIB_H

#endif //

#include <sys/select.h>
#include <unistd.h>
#include <sys/socket.h>
#include <pthread.h>
#include <signal.h>
#include <sys/wait.h>
#include <android/log.h>
#include <sys/types.h>
#include <errno.h>
#include <stdlib.h>
#include <linux/signal.h>
#include <android/log.h>
#include <unistd.h>
#include <sys/un.h>
#define LOG_TAG "tuch"
#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)


void child_do_work();
int child_create_channel();
void child_listen_msg();

3.2 ndk代码 native-lib.cpp

#include <jni.h>
#include <string>
#include "native-lib.h"

const char *userId;
int m_child;
const char *PATH = "data/data/com.example.socketprocess/my.sock";

void child_do_work() {
    //开启socket 服务端
    if (child_create_channel()) {
        child_listen_msg();
    }
    //等待连接
    //读取消息

}

/**
 * 服务端读取信息
 */
void child_listen_msg() {
    fd_set rfds;
    struct timeval timeout = {3, 0};
    while (1) {
        //清空内容
        FD_ZERO(&rfds);
        //设值
        FD_SET(m_child, &rfds);
        //选择监听 一般是最大文件号+1
        int r = select(m_child + 1, &rfds, NULL, NULL, &timeout);

        if (r > 0) {
            //缓冲区
            char pkg[256] = {0};
            //保证所读apk 是指定apk
            if (FD_ISSET(m_child, &rfds)) {
                //阻塞式函数
                int result = read(m_child, pkg, sizeof(pkg));
                LOGE("userId %s", userId);
                //如果socket 断开 便不再阻塞
                //开启服务 (com.example.socketproces为应用包名)
                execlp("am", "am", "startservice", "--user", userId,
                       "com.example.socketprocess/com.example.socketprocess.ProcessService",
                       (char *) NULL);
                break;
            }
        }
    }
}


/**
 * 创建服务店Socker
 * 客户端 apk进程
 * @return
 */
int child_create_channel() {
    //创建一个socker 协议 类型
    //socket 通过文件端口读写 可以跨进程
    int listenfd = socket(AF_LOCAL, SOCK_STREAM, 0);
    unlink(PATH);
    //绑定 socket标识 流体
    //addr ---< 内存区域
    struct sockaddr_un addr;

    //清空内存 =
    memset(&addr, 0, sizeof(sockaddr_un));
    //指定协议
    addr.sun_family = AF_LOCAL;

    int connfd = 0;
    strcpy(addr.sun_path, PATH);

    if (bind(listenfd, reinterpret_cast<const sockaddr *>(&addr), sizeof(sockaddr_un)) < 0) {
        LOGE("绑定错误");
        return 0;
    }

    listen(listenfd, 5);
    while (1) {
        //返回值 客户端的地址 阻塞式函数
        if (connfd = accept(listenfd, NULL, NULL) < 0) {
            if (errno == EINTR) {
                continue;
            } else {
                LOGE("读取错误");
                return 0;
            }
        }
        m_child = connfd;
        LOGE("APK 父进程连接上了 %d ", m_child);
        break;
    }

    return 1;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_example_socketprocess_Watcher_createWatcher(
        JNIEnv *env,
        jobject instance,
        jstring userId_) {
    userId = env->GetStringUTFChars(userId_, 0);
    //开双进程
    pid_t pid = fork();
    if (pid < 0) {
    } else if (pid == 0) {
        //子进程 : 当前进程的守护进程
        child_do_work();
    } else {
        //父进程
    }

}

extern "C"
JNIEXPORT void JNICALL
Java_com_example_socketprocess_Watcher_connectMonitor(
        JNIEnv *env,
        jobject instance) {
    LOGE("开始连接客户端...");
    //apk进程 客户端sock
    int socked;
    struct sockaddr_un addr;
    while (1) {
        socked = socket(AF_LOCAL, SOCK_STREAM, 0);
        if (socked < 0) {
            return;
        }
        //清空内存 =
        memset(&addr, 0, sizeof(sockaddr));
        //指定协议
        addr.sun_family = AF_LOCAL;
        strcpy(addr.sun_path, PATH);

        if (connect(socked, reinterpret_cast<const sockaddr *>(&addr), sizeof(sockaddr_un)) < 0) {
            LOGE("连接失败");
            close(socked);
            sleep(1);
            //再来下一次连接
            continue;
        }
        LOGE("连接成功");
        break;
    }

}

4.配置及开启服务 AndroidManifest.xml 及 MainActivity.kt

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.socketprocess">

    <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <service android:name=".ProcessService"/>
    </application>

</manifest>
package com.example.socketprocess

import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val intentService = Intent(this, ProcessService::class.java)
        startService(intentService)
    }

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章