赞
踩
我司项目中会频繁用到persist.sys.xxx的属性值,系统中预埋接口,通过属性值控制,以应对客户多样化的需求定制。
以往都是先设置属性值,再重启设备使能生效,抽空研究一下实时监听属性值变化,最后在csdn上查到监听SystemProperties变化 这篇文章。
博主的实现方法给了我很大的启发,在该基础上,分别在第三方应用的Activity和Service中实现了SystemProperties属性值的实时监听,app需要系统签名。
注:阅读本博客前,请先阅读监听SystemProperties变化这篇博客。
Parcel _data = Parcel.obtain(); try { final Class<?> systemPropertyClass = Class.forName("android.os.SystemProperties"); final Method addChangeCallback = systemPropertyClass.getDeclaredMethod( "addChangeCallback", Runnable.class); final Method getMethod = systemPropertyClass.getDeclaredMethod( "get", String.class, String.class); final Method setMethod = systemPropertyClass.getDeclaredMethod( "set", String.class, String.class); addChangeCallback.invoke(null, new Runnable() { @Override public void run() { Log.e("DebugUtil", "SystemProperties change"); try { String result = (String) getMethod.invoke( null, "persist.sys.test", "77777"); Log.e("DebugUtil", "SystemProperties change to " + result); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }); setMethod.invoke(null, "persist.sys.test", "88888"); IBinder amsBinder = getService(Context.ACTIVITY_SERVICE); _data.writeInterfaceToken("android.app.IActivityManager"); Boolean result = amsBinder.transact( ('_'<<24)|('S'<<16)|('P'<<8)|'R'/*IBinder.SYSPROPS_TRANSACTION*/, _data, null, 0); Log.e("DebugUtil", "result = " + result); } catch (RemoteException | IllegalAccessException | InvocationTargetException | ClassNotFoundException | NoSuchMethodException e) { e.printStackTrace(); } finally { _data.recycle(); }
try { Class<?> systemPropertyClass = Class.forName("android.os.SystemProperties"); Method addChangeCallback = systemPropertyClass.getDeclaredMethod( "addChangeCallback", Runnable.class); Method getMethod = systemPropertyClass.getDeclaredMethod( "get", String.class, String.class); Method setMethod = systemPropertyClass.getDeclaredMethod( "set", String.class, String.class); addChangeCallback.invoke(null, new Runnable() { @Override public void run() { DebugUtil.e(TAG, "SystemProperties change"); try { String result = (String) getMethod.invoke(null, "persist.sys.test", "123"); DebugUtil.e(TAG, "SystemProperties change to " + result); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }); setMethod.invoke(null, "persist.sys.test", "456"); String[] services = DeviceManagerUtil.listServices(); if (services == null) { DebugUtil.e(TAG, "There are no services, how odd"); } for (String service : services) { IBinder obj = DeviceManagerUtil.checkService(service); if (obj != null) { Parcel data = Parcel.obtain(); try { obj.transact( ('_'<<24)|('S'<<16)|('P'<<8)|'R'/*IBinder.SYSPROPS_TRANSACTION*/, data, null, 0); } catch (RemoteException e) { // Ignore } catch (Exception e) { DebugUtil.e(TAG, e.getMessage()); } data.recycle(); } } } catch (IllegalAccessException | InvocationTargetException | ClassNotFoundException | NoSuchMethodException e) { e.printStackTrace(); }
DeviceManagerUtil.java
public static String[] listServices() { try { Class<?> serviceManagerClass = Class.forName("android.os.ServiceManager"); Method listServices = serviceManagerClass.getDeclaredMethod("listServices"); return (String[]) listServices.invoke(null); } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } return null; } public static IBinder checkService(String service) { try { Class<?> serviceManagerClass = Class.forName("android.os.ServiceManager"); Method listServices = serviceManagerClass.getDeclaredMethod( "checkService", String.class); return (IBinder) listServices.invoke(null, service); } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } return null; }
1.监听方需要添加回调函数
SystemProperties.addChangeCallback()设置监听回调函数:非源码环境下,通过反射实现;源码环境下,直接调用addChangeCallback()方法即可。
2.设置属性值后,需要通知监听方
通知监听方的方式其实大同小异,遍历所有的Activity和Service,获取到它们的IBinder对象,调用onTransact()方法,通过Binder实现跨进程通信,最终调用SystemProperties的callChangeCallbacks()方法,遍历所有的callbacks的run()方法,通知监听方。
IBinder.SYSPROPS_TRANSACTION的值请查找自己的项目源码获取。
此处有两点需要说明:一是这里涉及到的Binder原理,博主的理解程度还达不到完全讲解清楚的程度(仅意会不会言传),请自行查阅Binder相关原理;二是addChangeCallback()不可执行多次,否则回调也会回调多次。
ActivityManagerService的onTransact()方法如下:
@Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { if (code == SYSPROPS_TRANSACTION) { // We need to tell all apps about the system property change. ArrayList<IBinder> procs = new ArrayList<IBinder>(); synchronized (this) { final int NP = mProcessList.mProcessNames.getMap().size(); for (int ip = 0; ip < NP; ip++) { SparseArray<ProcessRecord> apps = mProcessList.mProcessNames.getMap().valueAt(ip); final int NA = apps.size(); for (int ia = 0; ia < NA; ia++) { ProcessRecord app = apps.valueAt(ia); if (app.thread != null) { procs.add(app.thread.asBinder()); } } } } int N = procs.size(); for (int i=0; i<N; i++) { Parcel data2 = Parcel.obtain(); try { procs.get(i).transact(IBinder.SYSPROPS_TRANSACTION, data2, null, Binder.FLAG_ONEWAY); } catch (RemoteException e) { } data2.recycle(); } } try { return super.onTransact(code, data, reply, flags); } catch (RuntimeException e) { // The activity manager only throws certain exceptions intentionally, so let's // log all others. if (!(e instanceof SecurityException || e instanceof IllegalArgumentException || e instanceof IllegalStateException)) { /// M: Enhance wtf excetpion @{ if (mAmsExt.IsBuildInApp()) { Slog.wtf(TAG, "Activity Manager Crash." + " UID:" + Binder.getCallingUid() + " PID:" + Binder.getCallingPid() + " TRANS:" + code, e); } else { Slog.e(TAG, "Activity Manager Crash." + " UID:" + Binder.getCallingUid() + " PID:" + Binder.getCallingPid() + " TRANS:" + code, e); } /// @} } throw e; } }
SystemPropPoker.java
/* * Copyright (C) 2017 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.settingslib.development; import android.os.AsyncTask; import android.os.IBinder; import android.os.Parcel; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; public class SystemPropPoker { private static final String TAG = "SystemPropPoker"; private static final SystemPropPoker sInstance = new SystemPropPoker(); private boolean mBlockPokes = false; private SystemPropPoker() {} @NonNull public static SystemPropPoker getInstance() { return sInstance; } public void blockPokes() { mBlockPokes = true; } public void unblockPokes() { mBlockPokes = false; } public void poke() { if (!mBlockPokes) { createPokerTask().execute(); } } @VisibleForTesting PokerTask createPokerTask() { return new PokerTask(); } public static class PokerTask extends AsyncTask<Void, Void, Void> { @VisibleForTesting String[] listServices() { return ServiceManager.listServices(); } @VisibleForTesting IBinder checkService(String service) { return ServiceManager.checkService(service); } @Override protected Void doInBackground(Void... params) { String[] services = listServices(); if (services == null) { Log.e(TAG, "There are no services, how odd"); return null; } for (String service : services) { IBinder obj = checkService(service); if (obj != null) { Parcel data = Parcel.obtain(); try { obj.transact(IBinder.SYSPROPS_TRANSACTION, data, null, 0); } catch (RemoteException e) { // Ignore } catch (Exception e) { Log.i(TAG, "Someone wrote a bad service '" + service + "' that doesn't like to be poked", e); } data.recycle(); } } return null; } } }
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。