公司网站 开源,电子商务热门岗位,域名注册管理中心网站,有哪些做问卷调查给钱的网站需求场景 当上层app需要调用一些系统底层的资源以及属性操作#xff08;比如Settings.system 属性的读写#xff09;#xff0c;甚至驱动节点的读写操作#xff0c;上层app毫无疑问是没有权限的#xff0c;所以就需要我们在framework 系统层做一个中转和代理#xff0c;也…需求场景 当上层app需要调用一些系统底层的资源以及属性操作比如Settings.system 属性的读写甚至驱动节点的读写操作上层app毫无疑问是没有权限的所以就需要我们在framework 系统层做一个中转和代理也就是做一个远程服务AIDL实现开放远程调用接口。这种实现一般有两种思路
framework里实现一个系统级服务开机自启注册到系统服务的启动流程里这种思路针对像对写敏感加了系统级进程用户组的检查的话比如Settings.system的写操作还是会被拦下故不再赘述。 实现一个系统级的app,包装一个服务封装好逻辑后放到系统源码里参与编译即可。实测可行并且由于是做app在AS中直接开发有语法提示高亮错误提醒开发相当友好! 所以下面就讲解实现系统级APP包装远程服务的具体实现的步骤主要就是围绕AIDL的实现 服务端 AIDL服务声明 AS 直接在app 主module 上右键new - AIDL - AIDL File 例如 新建 ITestService.aidl AS 会自动完成AIDL的中间类的创建项目下新建aild 目录与java同级包名路径也保持一致
package com.xxx.server;interface ITestService {int getScreenBrightness();boolean setScreenBrightness(int brightness);
}这里我们实现一个 控制屏幕亮度的设置针对系统Settings属性的读写操作 Java服务实现
继承Service ,实现onBind(Intent intent) 返回IBinder对象。 实现ITestService.Stub(),即ITestService AIDL接口的具体实现 重写实现ITestService接口声明的方法
package com.xxx.server;import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.Settings;
import androidx.annotation.Nullable;public class xxxManagerService extends Service{NullableOverridepublic IBinder onBind(Intent intent) {return testStub;}private final ITestService.Stub testStub new ITestService.Stub() {Overridepublic int getScreenBrightness() throws RemoteException {int result -1;try {result Settings.System.getInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS);} catch (Settings.SettingNotFoundException e) {e.printStackTrace();}return result;}Overridepublic boolean setScreenBrightness(int brightness) throws RemoteException {boolean optResult;int resultBrightness 102;// default brightness 102 40%if (brightness 255 brightness 10) {resultBrightness brightness;}// 自动亮度改为手动亮度try {int mode Settings.System.getInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE);if (mode Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) {Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE,Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);}} catch (Settings.SettingNotFoundException e) {e.printStackTrace();}optResult Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, resultBrightness);return optResult;}}}AndroidManifest.xml的配置
对于只是包装一个服务我们不再需要UI界面不在需要它像普通app那样安装显示在桌面上
manifest根节点添加android:sharedUserId“android.uid.system” 属性即让该app加入系统进程组即变成系统级权限app,拥有对系统级限制的操作有了权限
manifest xmlns:androidhttp://schemas.android.com/apk/res/androidpackagecom.xxx.serverandroid:sharedUserIdandroid.uid.systemxmlns:toolshttp://schemas.android.com/tools去掉activity的注册同时项目内的activity的实现和layout都可以删除掉了。然后注册我们的主角xxxManagerService 注意 enabled 与 exported 必须true ; action为自定义
applicationandroid:allowBackuptrueandroid:iconmipmap/ic_launcherandroid:labelstring/app_nameandroid:supportsRtltruetools:targetApi31!-- 去掉Activity的注册因为不需要UI --
!-- activity--
!-- android:name.MainActivity--
!-- android:exportedtrue--
!-- intent-filter--
!-- action android:nameandroid.intent.action.MAIN /--
!-- category android:nameandroid.intent.category.LAUNCHER /--
!-- category android:nameandroid.intent.category.DEFAULT /--
!-- /intent-filter--
!-- /activity--service android:name.xxxManagerServiceandroid:enabledtrueandroid:exportedtrueintent-filteraction android:nameaction.com.xxx.server/category android:nameandroid.intent.category.DEFAULT//intent-filter/service/application到这里 作为服务端开放给上层的调用的配置基本就算完整了。但是实际需求可能还会涉及到 AIDL 传输非基本数据类型的情况AIDL 里做个对象的声明实现即可具体不再展开 还有可能会涉及到服务端主动回调客户端的情况 服务端回调客户端 同包名下新建ITestCallback.aidl,声明回调接口的方法
package com.xxx.server;interface ITestCallback {void onRemoteCallback(String msg);}然后在ITestService下面加入注册和解注册的方法注意: 这里要把回调接口导包进来尽管他们的包名路径一样
import com.xxx.server.ITestCallback;
interface ITestService {int getScreenBrightness();boolean setScreenBrightness(int brightness);// 加入回调接口的注册和解注册void registerCallBack(ITestCallback callback);void unregisterCallBack(ITestCallback callback);}Java 服务接口实现里加入刚才两个方法的实现
package com.xxx.server;import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.Settings;
import androidx.annotation.Nullable;public class xxxManagerService extends Service{NullableOverridepublic IBinder onBind(Intent intent) {return testStub;}private final ITestService.Stub testStub new ITestService.Stub() {... 省略其他方法实现 ...Overridepublic void registerCallBack(ITestCallback callback) throws RemoteException {CallbackRegisterManager.getInstance().register(callback);}Overridepublic void unregisterCallBack(ITestCallback callback) throws RemoteException {CallbackRegisterManager.getInstance().unRegister(callback);} }}CallbackRegisterManager的实现,封装下RemoteCallbackList主要用来管理AIDL接口回调注册的管理 public class CallbackRegisterManager {private static CallbackRegisterManager instance;private RemoteCallbackListITestCallback remoteCallbackList null;private CallbackRegisterManager() {remoteCallbackList new RemoteCallbackList();}public static CallbackRegisterManager getInstance() {synchronized (CallbackRegisterManager.class) {if (instance null) {instance new CallbackRegisterManager();}}return instance;}public RemoteCallbackListITestCallback getRemoteCallbackList(){return remoteCallbackList;}public void register(ITestCallback callback){if(remoteCallbackList ! null){remoteCallbackList.register(callback);}}public void unRegister(ITestCallback callback){if(remoteCallbackList ! null){remoteCallbackList.unregister(callback);}}
}放在系统下编译 首先把上面编写好的app源码打包成apk AS里Build Variants 选 release ,然后 Build - Build Bundle(s) / APK(s) - Build APK(s) ,打好的未签名的包在 build 目录 outputs 中拷贝出apk 文件修改自定义的名字 例如TestServer.apk 在自己源码三方app或者系统app编译的地方新建脚本LOCAL_MODULE同名文件夹 /TestServer 然后将如下内容 Android.mk 脚本和TestServer.apk一起放入 让这个新增的app参与系统编译不同平台略有不同不在赘述。
LOCAL_PATH: $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE : TestServerLOCAL_MODULE_CLASS : APPS
LOCAL_MODULE_TAGS : optional
LOCAL_MODULE_SUFFIX : $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE : platform
LOCAL_SRC_FILES : $(LOCAL_MODULE).apk
LOCAL_SYSTEM_EXT_MODULE : true
LOCAL_PRIVILEGED_MODULE : trueinclude $(BUILD_PREBUILT)客户端 由于提供三方app使用需要将客户端包装成 Library所以新建 项目 选择 Android Library类型
将服务端的AIDL 原封不动的拷贝到 项目里 即 java同级目录aidl目录下
注意: 包名路径和内部方法名称入参等需要和服务端完全一致不然后面调用就会出现问题所以直接拷贝过来简单安全 开放给外部的管理器的实现
public class TestManager {private Context mContext;private static TestManager mInstance;private ITestService mService;private IBinder b;private boolean connected;private TestCallbackImpl callbackImpl;private ICustomCallback icustomCallback;private TestManager(Context context, ICustomCallback iCallback) {mContext context.getApplicationContext();this.icustomCallback iCallback;// 链接AIDL远程服务bindRemoteService(conn);}private void bindRemoteService(ServiceConnection serviceConnection) {Intent intent new Intent();// 指定包名 指向我们那个前面做服务的做进系统服务的app的包名intent.setPackage(com.xxx.server);// // 这里的action 即 为 前面我们注册服务自定义的actionintent.setAction(action.com.xxx.server); mContext.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);}// 注册获取管理对象,同时传入三方客户调用端接收远程服务回调的接口public static synchronized TestManager register(NonNull Context context, ICustomCallback icustomCallback) {if (mInstance null) {mInstance new TestManager(context, iCallback);}return mInstance;}public void unRegister() {if (connected) {try {if (callbackImpl ! null) {getService().unregisterCallBack(callbackImpl);}} catch (Exception e) {e.printStackTrace();}mContext.unbindService(conn);}}// 获取服务对象private ITestService getService() {if (mService ! null) {return mService;}mService ITestService.Stub.asInterface(b);return mService;}private ServiceConnection conn new ServiceConnection() {Overridepublic void onServiceConnected(ComponentName componentName, IBinder iBinder) {b iBinder;connected true;// 初始化aidl远程回调callbackImpl new TestCallbackImpl(icustomCallback);// 注册aidl远程回调try {getService().registerCallBack(callbackImpl);} catch (RemoteException e) {e.printStackTrace();}}Overridepublic void onServiceDisconnected(ComponentName componentName) {connected false;}};// 这里可以做成扔出自定义异常提醒调用端private void isServiceConnected(String opt) {if (!connected) {Log.e(TAG, opt: opt -- service not connected!);}}// 下面便是对上层直接开放的方法 //public int getScreenBrightness() {isServiceConnected(getScreenBrightness);int result -1;try {result getService().getScreenBrightness();} catch (RemoteException e) {e.printStackTrace();}return result;}public boolean setScreenBrightness(int brightness) {isServiceConnected(setScreenBrightness);boolean optResult true;try {optResult getService().setScreenBrightness(brightness);} catch (RemoteException e) {optResult false;e.printStackTrace();}return optResult;}}下面是服务端回调接口 ITestCallback 的实现入参 ICustomCallback为三方app调用端去实现的接收服务回调数据的接口 public class TestCallbackImpl extends ITestCallback.Stub {private ICustomCallback ICustomCallback null;public TestCallbackImpl(ICustomCallback ICustomCallback) {this.iCallback iCustomCallback;}Overridepublic void onRemoteCallback(String msg) throws RemoteException {if (ICustomCallback ! null) {ICustomCallback.onCustomCallback(msg);}}
}客户端ICustomCallback回调的接口实现也很简单
public interface ICustomCallback {void onCustomCallback(String msg);
}至此这个提供给上层app 使用的封装操作的Library module项目基本已经完成然后将它编译打包获取他的aar库包给到任何客户端即可使用
三方app端调用 private TestManager testManager;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);testManager TestManager.register(this, myCustomCallback);}Overrideprotected void onDestroy() {super.onDestroy();if (testManager ! null) {testManager.unRegister();}}ICustomCallback myCustomCallback new ICustomCallback() {Overridepublic void onCustomCallback(String msg) {// 做相应操作}};