引言
我司項(xiàng)目中會(huì)頻繁用到persist.sys.xxx的屬性值,系統(tǒng)中預(yù)埋接口,通過屬性值控制,以應(yīng)對(duì)客戶多樣化的需求定制。
以往都是先設(shè)置屬性值,再重啟設(shè)備使能生效,抽空研究一下實(shí)時(shí)監(jiān)聽屬性值變化,最后在csdn上查到監(jiān)聽SystemProperties變化 這篇文章。
博主的實(shí)現(xiàn)方法給了我很大的啟發(fā),在該基礎(chǔ)上,分別在第三方應(yīng)用的Activity和Service中實(shí)現(xiàn)了SystemProperties屬性值的實(shí)時(shí)監(jiān)聽,app需要系統(tǒng)簽名。
注:閱讀本博客前,請(qǐng)先閱讀監(jiān)聽SystemProperties變化這篇博客。
Activity
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();
}
Service
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;
}
總結(jié)+分析
1.監(jiān)聽方需要添加回調(diào)函數(shù)
SystemProperties.addChangeCallback()設(shè)置監(jiān)聽回調(diào)函數(shù):非源碼環(huán)境下,通過反射實(shí)現(xiàn);源碼環(huán)境下,直接調(diào)用addChangeCallback()方法即可。
2.設(shè)置屬性值后,需要通知監(jiān)聽方
通知監(jiān)聽方的方式其實(shí)大同小異,遍歷所有的Activity和Service,獲取到它們的IBinder對(duì)象,調(diào)用onTransact()方法,通過Binder實(shí)現(xiàn)跨進(jìn)程通信,最終調(diào)用SystemProperties的callChangeCallbacks()方法,遍歷所有的callbacks的run()方法,通知監(jiān)聽方。
IBinder.SYSPROPS_TRANSACTION的值請(qǐng)查找自己的項(xiàng)目源碼獲取。
此處有兩點(diǎn)需要說明:一是這里涉及到的Binder原理,博主的理解程度還達(dá)不到完全講解清楚的程度(僅意會(huì)不會(huì)言傳),請(qǐng)自行查閱Binder相關(guān)原理;二是addChangeCallback()不可執(zhí)行多次,否則回調(diào)也會(huì)回調(diào)多次。
ActivityManagerService的onTransact()方法如下:文章來源:http://www.zghlxwxcb.cn/news/detail-453262.html
@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文章來源地址http://www.zghlxwxcb.cn/news/detail-453262.html
/*
* 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;
}
}
}
到了這里,關(guān)于Android 如何優(yōu)雅地監(jiān)聽SystemProperties屬性值變化的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!