jQuery鼠标指针特效

Settings.System数据监听/prop&SystemProperties数据监听

Settings.System数据监听

利用ContentObserver来实现

//Android 11 

import android.database.ContentObserver;

private ContentObserver mScreenshotShowObserver;
private ContentResolver mContentResolver;

mContentResolver = getContext().getContentResolver();

//数据变化之后做啥
mScreenshotShowObserver = new ContentObserver( getContext().getMainThreadHandler()) {
            @Override
            public void onChange(boolean selfChange) {
                boolean isShow = Settings.System.getInt(getContext().getContentResolver(), Settings.System.SCREENSHOT_BUTTON_SHOW, 1) == 1;
                ButtonDispatcher screenshotButton = mNavigationBarView.getScreenshotButton();
                screenshotButton.setVisibility(isShow ? View.VISIBLE : View.GONE);
            }
        };

//注册监听器        
mContentResolver.registerContentObserver(
                Settings.System.getUriFor(Settings.System.SCREENSHOT_BUTTON_SHOW), true,
                mScreenshotShowObserver, UserHandle.USER_ALL);        

prop&SystemProperties数据监听

prop属性设置和获取

  • adb
adb shell getprop <key>
adb shell setprop <key> <value>
  • C++
/system/core/libcutils/properties.cpp

int property_get(const char* key, char* value, const char* default_value)
int property_set(const char* key, const char* value)
  • java
/frameworks/base/core/java/android/os/SystemProperties.java

public static String get(@NonNull String key)
public static void set(@NonNull String key, @Nullable String val)

SystemPropPoker 监听

frameworks/base/packages/SettingsLib/src/com/android/settingslib/development/SystemPropPoker.java

    private static final SystemPropPoker sInstance = new SystemPropPoker();

    @NonNull
    public static SystemPropPoker getInstance() {
        return sInstance;
    }
    
    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;
        }
    }

监听SystemProperties的变化,查看SystemPropPoker类可知,它会监听所有SystemProperties属性值的变化,
而且会通过obj.transact(IBinder.SYSPROPS_TRANSACTION, data, null, 0);,
通知所有的服务.

所以使用SystemPropPoker监听,需要在代码下做些判断.

demo:

它并不能具体指定监听某一系统属性,只要有系统属性发生变化并poke,注册的回调函数就会被调用.
在调用SystemProperties.set时poke,通知监听方:

import com.android.settingslib.development.SystemPropPoker;

SystemProperties.set("persist.xxx.is_drop_down","false");
SystemPropPoker.getInstance().poke();

监听回调函数:

    //SystemProperties.addChangeCallback只添加一次,不要多次重复添加,不然回调多次
    static boolean register = false;
    
    if (!register) {
        register = true;
        SystemProperties.addChangeCallback(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG,"SystemProperties prop changed");
                boolean newState = SystemProperties.getBoolean("persist.xxx.is_drop_down",true);
                if(newState != oldState){
                    //to do
                }
            }
        });
    }
    

ystemProperties属性变化监听
安卓prop/SystemProperties如何监听值变化

PS:上面的demo我在源码中测试过,只能在同进程(同一个app)中使用,不能跨进程通信.
我感觉很鸡肋的函数,然后我搜索源码,发现SystemPropertiesTest源码内有类似的用法:

./frameworks/base/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java

    @SmallTest
    public void testCallbacks() {
        ...
        Runnable r1 = new Runnable() {
            boolean done = false;
            @Override
            public void run() {
                if (done) {
                    return;
                }
                done = true;

                wait1.countDown();
                throw new RuntimeException("test");
            }
        };

        Runnable r2 = new Runnable() {
            @Override
            public void run() {
                wait2.countDown();
            }
        };

        SystemProperties.addChangeCallback(r1);
        SystemProperties.addChangeCallback(r2);

        SystemProperties.reportSyspropChanged();
        ...
    
    }
    
    @SmallTest
    public void testProperties() throws Exception {
        String value;

        SystemProperties.set(KEY, "");
        value = SystemProperties.get(KEY, "default");
        assertEquals("default", value);
        
        ...
    }   

为什么不能跨进程通信?
那只能跟踪源码分析了.原因在下面链接:

能否监听system property值

分析能否监听system property值

/frameworks/base/core/java/android/os/SystemProperties.java

@SuppressWarnings("unused")  // Called from native code.//从native层被回调
    private static void callChangeCallbacks() {
        ArrayList<Runnable> callbacks = null;
        synchronized (sChangeCallbacks) {
            //Log.i("foo", "Calling " + sChangeCallbacks.size() + " change callbacks!");
            if (sChangeCallbacks.size() == 0) {
                return;
            }
            callbacks = new ArrayList<Runnable>(sChangeCallbacks);
        }
        final long token = Binder.clearCallingIdentity();
        try {
            for (int i = 0; i < callbacks.size(); i++) {
                try {
                    callbacks.get(i).run();//循环调用callback
                } catch (Throwable t) {
                    // Ignore and try to go on. Don't use wtf here: that
                    // will cause the process to exit on some builds and break tests.
                    Log.e(TAG, "Exception in SystemProperties change callback", t);
                }
            }
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

跟踪callChangeCallbacks(),它是被native层被回调.

frameworks/base/core/jni/android_os_SystemProperties.cpp

jmethodID sCallChangeCallbacks;

void do_report_sysprop_change() {
  ...
  env->CallStaticVoidMethod(sClazz, sCallChangeCallbacks);
  ...
}

void SystemProperties_add_change_callback(JNIEnv *env, jobject clazz)
{
  ...
   sCallChangeCallbacks = env->GetStaticMethodID(sClazz, "callChangeCallbacks", "()V");
   ...
}

callChangeCallbacks是在Native层中被do_report_sysprop_change回调的

system/core/libutils/misc.cpp

void report_sysprop_change() {
    do_report_sysprop_change();
}

do_report_sysprop_changereport_sysprop_change被回调

整个流程:

report_sysprop_change ---> do_report_sysprop_change ---> 
callChangeCallbacks ---> callbacks.get(i).run();

遍历源码,看哪里调用了report_sysprop_change,然后一个个分析.我直接用了王小二的技术栈的分析

第1处调用点

frameworks/base/core/java/android/os/SystemProperties.java
/**
* Notifies listeners that a system property has changed
* @hide
*/
public static void reportSyspropChanged() {
        //调用native层的SystemProperties_report_sysprop_change
        native_report_sysprop_change();
}


frameworks/base/core/jni/android_os_SystemProperties.cpp

void SystemProperties_report_sysprop_change(JNIEnv /**env*/, jobject /*clazz*/)
{
    report_sysprop_change();
}

int register_android_os_SystemProperties(JNIEnv *env)
{
    const JNINativeMethod method_table[] = {
        ...
        { "native_report_sysprop_change", "()V",
          (void*) SystemProperties_report_sysprop_change },
    };
    return RegisterMethodsOrDie(env, "android/os/SystemProperties",
                                method_table, NELEM(method_table));
}

流程:可能修改完system property之后主动调用SystemProperties.reportSyspropChanged()才能回调我们设置的callback.

第2处调用点

./frameworks/native/libs/binder/Binder.cpp

// NOLINTNEXTLINE(google-default-arguments)
status_t BBinder::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t /*flags*/)
{
    switch (code) {
        ...
        case SYSPROPS_TRANSACTION: {
            report_sysprop_change();
            return NO_ERROR;
        }
        ...
    }

发现一个关于SYSPROPS_TRANSACTION的Binder通信,来触发report_sysprop_change().
既然是Binder通信,有server端,就应该有client端.

client——1

//ANR 守护进程
./system/extras/ANRdaemon/ANRdaemon.cpp

/*
 * Force the userland processes to refresh their property for logging.
 * 强制用户区进程刷新其属性以进行日志记录
 */
static void dfs_poke_binder(void) {
    sp<IServiceManager> sm = defaultServiceManager();
    Vector<String16> services = sm->listServices();
    for (size_t i = 0; i < services.size(); i++) {
        sp<IBinder> obj = sm->checkService(services[i]);
        if (obj != NULL) {
            Parcel data;
            obj->transact(IBinder::SYSPROPS_TRANSACTION, data, NULL, 0);
        }
    }
}

client——2

./frameworks/native/cmds/atrace/atrace.cpp

// Poke all the binder-enabled processes in the system to get them to re-read
// their system properties.
//戳入系统中所有启用粘合剂的进程,让它们重新读取其系统属性
static bool pokeBinderServices()
{
    sp<IServiceManager> sm = defaultServiceManager();
    Vector<String16> services = sm->listServices();
    for (size_t i = 0; i < services.size(); i++) {
        sp<IBinder> obj = sm->checkService(services[i]);
        if (obj != NULL) {
            Parcel data;
            if (obj->transact(IBinder::SYSPROPS_TRANSACTION, data,
                    NULL, 0) != OK) {
                if (false) {
                    // XXX: For some reason this fails on tablets trying to
                    // poke the "phone" service.  It's not clear whether some
                    // are expected to fail.
                    String8 svc(services[i]);
                    fprintf(stderr, "error poking binder service %s\n",
                        svc.string());
                    return false;
                }
            }
        }
    }
    return true;
}

上述代码解析:
循环遍历注册在SM(ServiceManager)的实名Binder,
然后发起SYSPROPS_TRANSACTION的Binder通信,这样子所有注册在SM中注册实名Binder的进程可以触发report_sysprop_change.

可以看出需要监听修改system property的地方主动执行client-1和client-2类似的代码,
才能通知到其他进程system property发生了变化然后触发callback.

如果自己写的App中并没有注册实名Binder到SM,那App如何接收system property的变化?

client——3

./frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

    @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) {
                            //遍历所有的ProcessRecord,获得每个ProcessRecord中保存thread,
                            //thread是每个应用中ApplicationThread这个Binder对象的Client端。
                            procs.add(app.thread.asBinder());
                        }
                    }
                }
            }

            int N = procs.size();
            for (int i=0; i<N; i++) {
                Parcel data2 = Parcel.obtain();
                try {
                    //发送SYSPROPS_TRANSACTION到每个应用,通知它们
                    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)) {
                Slog.wtf(TAG, "Activity Manager Crash."
                        + " UID:" + Binder.getCallingUid()
                        + " PID:" + Binder.getCallingPid()
                        + " TRANS:" + code, e);
            }
            throw e;
        }
    }

总结
如果system property监听在同一个进程内,可以用SystemProperties.addChangeCallback()监听,
在Settings源码内添加过(Android 11),演示监听成功.

还有另一种说法,
在修改system property的地方,主动调用SystemProperties.reportSyspropChanged或者类似前面的client1和client2处的代码.
前者只能通知当前进程,后者可以通知所有注册实名Binder到SM的进程和保存在AMS的ProcessRecord对应的App.

在Android 11 内没有搜索到这个函数,不知道是那个版本有. 它模仿类似与client1/client2的通信java版.

   /**
     * Notifies {@link #getRunningAppProcesses app processes} that the system properties
     * have changed.
     *
     * @see SystemProperties#addChangeCallback
     *
     * @hide
     */
    @TestApi
    public void notifySystemPropertiesChanged() {
        // Note: this cannot use {@link ServiceManager#listServices()} to notify all the services,
        // as that is not available from tests.
        final var binder = ActivityManager.getService().asBinder();
        if (binder != null) {
            var data = Parcel.obtain();
            try {
                binder.transact(IBinder.SYSPROPS_TRANSACTION, data, null /* reply */,
                        0 /* flags */);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
            data.recycle();
        }
    }


如何使用:

//App1进程
+        SystemProperties.set("xy.test.callback","true");
+        ActivityManager am = (ActivityManager) getSystemService(
+                Context.ACTIVITY_SERVICE);
+        am.notifySystemPropertiesChanged();

//App2进程

static  boolean register = false;

+        if (!register) {
+            register = true;
+            SystemProperties.addChangeCallback(new Runnable() {
+                @Override
+                public void run() {
+                    android.util.Log.i("text","SystemProperties ChangeCallback testxxxxxxxx);
+                }
+            });
+        }

App1进程setprop,然后通知 ---> system_server利用ams通知进程system property改变 ---> App2进程收到通知,addChangeCall执行

.rc 监听system property值

利用on property 触发器,启动某个服务

./frameworks/native/cmds/atrace/atrace.rc

on property:persist.debug.atrace.boottrace=1
    start boottrace
    

rc文件中是如何监听system property?
原来是通过hook了PropertySet方法来监听system property值的变化

./system/core/init/property_service.cpp

static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
    ...
    property_changed(name, value);
    return PROP_SUCCESS;
}

void property_changed(const std::string& name, const std::string& value) {
    ...
    if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value);
    ...
}

./system/core/init/property_service.cpp

posted @   僵小七  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
历史上的今天:
2022-02-17 关于笔记本电脑--软件
点击右上角即可分享
微信分享提示