IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 22-08-04 Android 开机开启一个系统服务SystemService,里面含有Handler handleMessage、发送和接收Broadcast、Thread、静态注册jni 实例 -> 正文阅读

[移动开发]22-08-04 Android 开机开启一个系统服务SystemService,里面含有Handler handleMessage、发送和接收Broadcast、Thread、静态注册jni 实例

前言:这个实例源于读写serial串口设备数据的需求,开机后开启一个系统服务SystemService,里面含有Handler handleMessage、发送和接收Broadcast、Thread、静态注册jni 实例,对理解service和jni有所帮助。

一、添加 SystemService文件,里面含有Handler handleMessage、发送和接收Broadcast、Thread、jni静态注册和service连接frameworks\base\services\core\java\com\android\server\power\GiadaService.java

/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.power;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.BatteryManagerInternal;
import android.os.OsProtoEnums;
import android.os.PowerManager;
import android.util.Slog;
import android.util.Log;

import com.android.internal.os.CachedDeviceState;
import com.android.server.SystemService;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.IOException;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.*;
import android.net.wifi.WifiManager;
import android.os.SystemProperties;
import android.os.Handler;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Looper;
import android.os.Message;
import android.annotation.NonNull;


public final class GiadaService extends SystemService {

    private static final String TAG = "GiadaService";

	private static final int TIME_MESSAGE = 100;
	private ReadThread mReadThread;
	int timeCount = 0;

	private Handler timeHandler = new Handler() {
			@Override
			public void handleMessage(@NonNull Message msg) {
				super.handleMessage(msg);
				switch (msg.what) {
					case TIME_MESSAGE:
				          final int number = (int) msg.obj;
						  Slog.d(TAG, "Received message-TIME_MESSAGE number="+number);
					      if(number == 100){
				             Intent tempwarning = new Intent("PNW.clickedTempWarning");
                             getContext().sendBroadcast(tempwarning);
					      }
						break;
					default:
						break;
				}
			}
	};

	private class ReadThread extends Thread {
		@Override
		public void run() {
			super.run();
			while(!isInterrupted()) {
				  try {
						Thread.sleep(1000);
						timeCount++;
						Message msg = timeHandler.obtainMessage(TIME_MESSAGE, timeCount);
						msg.setAsynchronous(true);
						msg.sendToTarget();
						Slog.d(TAG, "obtainMessage sendToTarget,timeCount:" + timeCount);
					   } catch (InterruptedException e) {
						 e.printStackTrace();
						 break;
					 }
				  }
			}
	}

    //final EthernetServiceImpl mImpl;
	private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
		 @Override
		 public void onReceive(Context context, Intent intent) {
			 Slog.wtf(TAG, "BroadcastReceiver onReceive action:"+intent.getAction());
		     switch (intent.getAction()) {
				 case "android.intent.giada.sendbroadcast":
	                     Intent tempwarning = new Intent("PNW.clickedTempWarning");
                         getContext().sendBroadcast(tempwarning);
					 break;
				 case "android.intent.giada.stopthread":
					     if (mReadThread != null)
			              mReadThread.interrupt();
						  Slog.wtf(TAG, "BroadcastReceiver getString():"+getString());
						  Slog.wtf(TAG, "BroadcastReceiver setString():"+setString("SHIT"));
					 break;
		 	  }
 
		 }
	 };
	
    public GiadaService(Context context) {
        super(context);
		Log.i(TAG, "GiadaService context!" );
        //mImpl = new EthernetServiceImpl(context);
    }

    @Override
    public void onStart() {
        Log.i(TAG, "onStart,creat thread!" );
		mReadThread = new ReadThread();
		mReadThread.start();
			
        //publishBinderService(Context.ETHERNET_SERVICE, mImpl);
    }

    @Override
    public void onBootPhase(int phase) {
        Log.i(TAG, "onBootPhase" );
	    if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY){
	        Log.i(TAG, "onBootPhase PHASE_SYSTEM_SERVICES_READY" );
			final IntentFilter filter = new IntentFilter();
	        filter.addAction("android.intent.giada.sendbroadcast");
			filter.addAction("android.intent.giada.stopthread");
	        getContext().registerReceiver(mBroadcastReceiver, filter);
	    }
    }

	public static native String getString();
    public static native String setString(String str);
}

二、开启服务,在frameworks\base\services\java\com\android\server\SystemServer.java startBootstrapServices函数里面添加下面内容开机服务

t.traceBegin("StartGiadaService");
mSystemServiceManager.startService(GiadaService.class);
t.traceEnd();

?三、JNI 部分,在 frameworks/base/services/core/jni/下面添加 两个文件com_android_server_power_GiadaService.c和com_android_server_power_GiadaService.h

? ? ? ?3.1、com_android_server_power_GiadaService.c

/*
 * Copyright 2009-2011 Cedric Priscal
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <jni.h>


#include "android/log.h"
#include "com_android_server_power_GiadaService.h"

static const char *TAG="SERIAL-PORT_JNI";
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)


JNIEXPORT jstring JNICALL Java_com_android_server_power_GiadaService_getString(JNIEnv *env, jclass cls)
{
    LOGD("Java_com_android_server_power_GiadaService_getString\r\n");
    return (*env)->NewStringUTF(env, "getString,return hello from jni");
}

JNIEXPORT jstring JNICALL Java_com_android_server_power_GiadaService_setString(JNIEnv *env, jclass cls, jstring str)
{
     const char *g_str = (*env)->GetStringUTFChars(env,str, NULL);
     LOGD("Java_com_android_server_power_GiadaService_setString jni string=%s \r\n",g_str);
	 if (g_str != NULL) {
        (*env)->ReleaseStringUTFChars(env, str, g_str);
     }
     return (*env)->NewStringUTF(env, "setString,return hi from jni");
}

? ? ? ?3.2、com_android_server_power_GiadaService.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_android_server_power_GiadaService */

#ifndef _Included_com_android_server_power_GiadaService
#define _Included_com_android_server_power_GiadaService
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_android_server_power_GiadaService
 * Method:    getString
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_android_server_power_GiadaService_getString
  (JNIEnv *, jclass);



/*
 * Class:     com_android_server_power_GiadaService
 * Method:    setString
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_android_server_power_GiadaService_setString
  (JNIEnv *, jclass, jstring);

#ifdef __cplusplus
}
#endif
#endif

3、在 frameworks/base/services/core/jni/Android.mk 里面添加"com_android_server_power_GiadaService.c" 去编译编译com_android_server_power_GiadaService.c

4、这里jni中的写法是

JNIEXPORT jstring JNICALL Java_com_android_server_power_GiadaService_getString
? (JNIEnv *, jclass);这种写法不需要再手动注册native方法,如果是其他写法,需要在.c中添加手动注册方法,并在onload.cpp中注册。

四、烧录真机测试,通过adb shell am broadcast -a "android.intent.giada.sendbroadcast"命令发从广播,服务里面接受到该广播后再发一个广播调出提示窗口;通过adb shell am broadcast -a "android.intent.giada.stopthread" 发送一个广播,服务里面接收到该广播后会通过interrupt退出线程,并且调用jni接口getString和setString,通过log上看有SERIAL-PORT_JNI的相关打印,说明已经成功调用到jni接口,这种事静态注册jni,相对动态注册jni比较简单。

?

五、整个过程中涉及到的文件

六、非常有价值的参考文章

1、SystemService与jni的静态注册连接,用于串口通信

android 系统添加jni,注册本地方法_王不六的博客-CSDN博客_android 系统服务jni

2、SystemService里面publishBinderService的栗子

android 10 添加系统服务步骤_青春给了狗的博客-CSDN博客_android 系统服务

1.编写.aidl文件
存放位置:frameworks/base/core/java/android/os

package android.os;
interface ITEST {   
    //此处注意 如果参数中有数组类型记得加入out 和in关键字
    // int test(in byte【】 a)
    void test();
}

---------------------------------------------------------------------------------------------------------------------------------
2、将.aidl文件添加到 frameworks/base/Android.mk下的 LOCAL_SRC_FILES
(此处先make update-api生成对应的文件 Frameworks/base/api/current.txt中查看是否存在对应ITEST接口)
注意:Android 9以上是添加到frameworks/base/ Android.bp
存放位置:framework/base

java_defaults {
    name: "framework-defaults",
    installable: true,
    srcs: [
         ...省略
        "core/java/android/os/ITEST.aidl",
        ...省略

---------------------------------------------------------------------------------------------------------------------------------
3、Context.java添加服务注册名称, 添加该服务名称, 用于快捷注册和快捷引用
修改位置:frameworks/base/core/java/android/content/

  /**
     * Use with {@link #getSystemService(String)} to retrieve a
     * {@link android.app.TestManager} for controlling power management,
     * including "wake locks," which let you keep the device on while
     * you're running long tasks.
     */
 public static final String ITEST_SERVICE = "itest";

/** @hide */
    @StringDef(suffix = { "_SERVICE" }, value = {
            POWER_SERVICE,
            ITEST_SERVICE 
       ....,}

---------------------------------------------------------------------------------------------------------------------------------

4、新建TestService.java和TestManager.java
存放位置:frameworks\base\services\core\java\com\android\server\TestService.java
frameworks\base\core\java\android\app\TestManager.java

//TestManager 类
package android.app;
import android.content.Context;
import android.os.IFan;
import android.os.RemoteException;
import android.annotation.SystemService;

@SystemService(Context.ITEST_SERVICE )
public class TestManager {
    public static final String TAG = "TestManager";

    private Context mContext;
    private TestService mService;

    public FanManager(Context mContext, TestService mService) {
        this.mContext = mContext;
        this.mService = mService;
    }
    pubic void test(){
       try {
               mService.test();
             } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
            }
    }
}


//TestService 类
package com.android.server;
import android.app.TestManager;
import android.content.Context;
import android.os.ITEST;
import android.os.RemoteException;
import com.android.server.SystemService;
import com.android.internal.app.IAppOpsService;

public class TestService extends SystemService {
    private Context mContext;
    private IAppOpsService mAppOps;
    private TestManager mManager;
    public TestService(Context context) {
        super(context);
        this.mContext = context;
    }
    public void systemReady(IAppOpsService appOps) {
      //TODO
    }
    @Override
    public void onStart() {
        publishBinderService(Context.ITEST_SERVICE, new BinderService());
    }
    private final class BinderService extends ITEST.Stub {
        @Override
        public void test() throws RemoteException {
           //TODO 具体操作在这里面实现
        }
    }
}

---------------------------------------------------------------------------------------------------------------------------------

5、SystemServer.java 中注册该service
修改位置: frameworks\base\services\java\com\android\server

import com.android.server.TestService ;//导包

private TestService  mTestService; //定义

 在SystemServer.java 中的startBootstrapServices()方法添加

 traceBeginAndSlog("StartTestManager");
 mTestService= mSystemServiceManager.startService(TestService.class);
 traceEnd();

traceBeginAndSlog("MakeTestManagerServiceReady");
 try {
            // TODO: use boot phase
  mTestService.systemReady(mActivityManagerService.getAppOpsService());
      } catch (Throwable e) {
   reportWtf("making Test Manager Service ready", e);
      }
 traceEnd();

---------------------------------------------------------------------------------------------------------------------------------

6、SystemServiceRegistry的static{}, 并在其中注册该service
修改位置:frameworks\base\core\java\android\app
import android.os.ITEST;//导包
//TestManager在同一目录下所以不用导包

   registerService(Context.ITEST_SERVICE, TestManager.class,ew CachedServiceFetcher() {
     @Override
     public I2CManager createService(ContextImpl ctx)throws ServiceNotFoundException {
                        IBinder b = ServiceManager.getServiceOrThrow(            Context.ITEST_SERVICE);
                        return new TestManager(
                                ctx.getOuterContext(),ITEST.Stub.asInterface(b));
        }});


以上步骤完成我们的自定义系统服务就完成了90%   但是我们还有最后一步,也是最重要的一步:

---------------------------------------------------------------------------------------------------------------------------------

7、 设置selinux规则
然后我们只需要添加这个自定义服务TestService相关的 SELinux 规则。为了方便之后验证,打开selinux
要记住这个命令  adb shell setenforce 1   # 1为打开  #0为关闭
Android 10 的 selinux 规则是放在 system/sepolicy 目录下的:
 service.te 和 service_contexts 都要加上 TestService的配置:

./prebuilts/api/27.0/public/service.te   # 需要
./prebuilts/api/28.0/public/service.te   # 需要
./prebuilts/api/29.0/public/service.te    # 需要
./prebuilts/api/26.0/public/service.te   # 需要
./public/service.te                 # 需要


./prebuilts/api/27.0/private/service_contexts   # 需要
./prebuilts/api/28.0/private/service_contexts   # 需要
./prebuilts/api/29.0/private/service_contexts       # 需要
./prebuilts/api/26.0/private/service_contexts   # 需要
./private/service_contexts         # 需要


在上述文件中
service_contexts文件添加配置 itest   u:object_r:itest_service:s0
service.te  中添加type  itest_service , system_server_service, service_manager_type
总结出一个规律 :就是service.te 文件在public目录下需要添加,private目录下不需要
                           service_contexts文件在private目录下的需要添加,public目录不需要
到此系统服务已经添加完成
itest                                    u:object_r:itest_service:s0

---------------------------------------------------------------------------------------------------------------------------------
8、验证:
    编译完成后,输入adb shell
                           #service  list 
    查看服务列表中 是否存在有添加服务 :itest        
    如果不存在 逐步排查 参照上一步看哪一步错误
    如果存在 就在代码中验证
    找到编译最新生成的class.jar文件,导入Androidstudio(如何导入自行百度)
   编译后的class.jar目录\out\target\common\obj\JAVA_LIBRARIES\framework_intermediates

  如果未生成  执行下make javac-check-framework 这个命令 就会生成!!!

觉得我写的好的兄弟 动动你发财的小手 点个赞 !!!

你们的认同将是我继续写下去的动力 !!

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-08-06 10:55:38  更:2022-08-06 11:00:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/18 7:50:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码