sysprop变化通知native层面实现[验证通过]

背景:

前面文章 安卓prop/SystemProperties如何监听值变化 已经详细介绍了prop如何监听接受prop变化通知。但是也有学员反馈文章只是介绍了有apk的和有java代码的情况,如果是完全一个native进程呢?是否有办法实现native层面也进行prop属性变化后的通知和prop变化的回调。
java相关进程通知流程如下:
在这里插入图片描述native通知流程应该如何做呢?
在这里插入图片描述

native端实现通知调研

java端可以,那么可以先分析java端的代码情况:
frameworks/base/core/java/android/os/SystemProperties.java

    /**
     * Add a callback that will be run whenever any system property changes.
     *
     * @param callback The {@link Runnable} that should be executed when a system property
     * changes.
     * @hide
     */
    @UnsupportedAppUsage
    public static void addChangeCallback(@NonNull Runnable callback) {
        synchronized (sChangeCallbacks) {
            if (sChangeCallbacks.size() == 0) {
                native_add_change_callback();
            }
            sChangeCallbacks.add(callback);
        }
    }

可以看到这里有调native_add_change_callback方法
frameworks/base/core/jni/android_os_SystemProperties.cpp

void SystemProperties_add_change_callback(JNIEnv *env, jobject clazz)
{
    // This is called with the Java lock held.
    if (sVM == nullptr) {
        env->GetJavaVM(&sVM);
    }
    if (sClazz == nullptr) {
        sClazz = (jclass) env->NewGlobalRef(clazz);
        sCallChangeCallbacks = env->GetStaticMethodID(sClazz, "callChangeCallbacks", "()V");
        //这里是核心,把这个do_report_sysprop_change方法放入回调
        add_sysprop_change_callback(do_report_sysprop_change, -10000);
    }
}

来看看add_sysprop_change_callback方法实现
system/core/libutils/misc.cpp

void add_sysprop_change_callback(sysprop_change_callback cb, int priority) {
    pthread_mutex_lock(&gSyspropMutex);
    if (gSyspropList == nullptr) {
        gSyspropList = new Vector<sysprop_change_callback_info>();
    }
    sysprop_change_callback_info info;//构造sysprop_change_callback_info对象
    info.callback = cb;//传递来的sysprop_change_callback赋值给info
    info.priority = priority;
    bool added = false;
    for (size_t i=0; i<gSyspropList->size(); i++) {
        if (priority >= gSyspropList->itemAt(i).priority) {
            gSyspropList->insertAt(info, i);
            added = true;
            break;
        }
    }
    if (!added) {
        gSyspropList->add(info);
    }
    pthread_mutex_unlock(&gSyspropMutex);
}

上面就已经完成了cb的保存,下面就该看通知情况了。
这里就可能主要看跨进程通讯的情况

status_t BBinder::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t /*flags*/)
{
        case SYSPROPS_TRANSACTION: {
        //跨进程调用到这里,会触发report_sysprop_change方法
            if (!binder::os::report_sysprop_change()) return INVALID_OPERATION;
            return NO_ERROR;
        }

        default:
            return UNKNOWN_TRANSACTION;
    }
}

这里可以看调用到了report_sysprop_change

void report_sysprop_change() {
    do_report_sysprop_change();
}
void do_report_sysprop_change() {
#if !defined(_WIN32)
    pthread_mutex_lock(&gSyspropMutex);
    Vector<sysprop_change_callback_info> listeners;
    if (gSyspropList != nullptr) {
        listeners = *gSyspropList;
    }
    pthread_mutex_unlock(&gSyspropMutex);

    //ALOGI("Reporting sysprop change to %d listeners", listeners.size());
    for (size_t i=0; i<listeners.size(); i++) {
        listeners[i].callback();//这里会进行相关的native回调
    }
#endif
}

明显可以得出如下结论:

1、无论java还是native,通知prop变化其实都是通过跨进程通讯调用SYSPROPS_TRANSACTION

2、prop变化回调部分,native其实本质就是放入了一个方法指针既可以,有prop变化通知后,会执行传递进来的方法

所以实现native端的prop变化通知只需要如下两个步骤:
1、通知部分只需要跨进程调用一下既可以,code为SYSPROPS_TRANSACTION
2、接受部分只需要native代码中调用
add_sysprop_change_callback(sysprop_change_callback cb, int priority)
这里的sysprop_change_callback其实就是个方法类型
system/core/libutils/include/utils/misc.h

typedef void (*sysprop_change_callback)(void);

实战开发:

通知端代码:
这里可以通知端其实可以native代码,也可以java代码,都可以起到通知作用,因为跨进程最后都会通过native的代码,这里只展示native端代码:

void testBinderProp() {
	android::sp<android::IServiceManager> sm = android::defaultServiceManager();
	//这里最重要要寻找相关的通知进程,需要有一个服务,apk一般都是ams服务,这里native用audio进程作为接收端
	android::sp<android::IBinder> binder = sm->checkService(android::String16("media.audio_flinger"));
	android::Parcel _aidl_data;
	_aidl_data.markForBinder(binder);
	_aidl_data.writeInterfaceToken(android::String16("android.media.IAudioFlingerService"));


	android::Parcel _aidl_reply;
	android::status_t _aidl_ret_status = binder->transact(IBinder::SYSPROPS_TRANSACTION, _aidl_data, NULL);

}

接受prop变化通知相关的代码:
frameworks/av/media/audioserver/main_audioserver.cpp
在这里插入图片描述整体非常非常简单,只需要调用add_sysprop_change_callback既可以,参数就是callback方法。

结果打印如下:
运行通知端:

130|emu64x:/data/local/tmp # ./android_thread                                                                                                                                                                     
Number of displays: 1
Display ID: 0
Error in response or non-zero resultCode.

通过日志看接收端情况

130|emu64x:/ # logcat | grep propVhangeCallback                                                                                                                                                               
02-08 20:34:38.977   362   609 E audioserver: ---------------- propVhangeCallback 1------------- 

可以看到有propVhangeCallback的相关打印,说明已经正常回调到了。

如果换成java代码进行通知:

    SystemProperties.set("debug.test.callback","true");
    SystemPropPoker.getInstance().poke();

也可以接受到,可以看看相关打印:

test@test:~/aosp15$ adb  logcat | grep propVhangeCallback

02-08 20:46:54.467   374   605 E audioserver: ---------------- propVhangeCallback 1------------- 
02-08 20:46:54.468   374   605 E audioserver: ---------------- propVhangeCallback 1------------- 

可以看到确实有相关的,不过这里会有连续两次回调打印,哈哈,这个你知道为啥吗?这个留给大家的思考作业哈

更多framework实战干货,请关注下面“千里马学框架”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值