安卓6.0系統(tǒng)屬性上層應(yīng)用監(jiān)聽實(shí)現(xiàn)(屬性監(jiān)聽)

原創(chuàng):bpbwan
安卓系統(tǒng)中往往有一些狀態(tài)是靠系統(tǒng)屬性來保存的,linux層的嵌入式應(yīng)用鏈接底層模塊變更某些開關(guān)狀態(tài)時(shí)單靠localsocket傳輸更新給上層嫂拴,或多或少會(huì)比較有延遲,也特別多個(gè)底層應(yīng)用時(shí)贮喧,總不能每個(gè)要給上層通訊都開一個(gè)socket去弄吧筒狠。賴得弄那么煩的就直接靠個(gè)系統(tǒng)屬性來通知上層算了,這時(shí)候需要給framework改的比較多箱沦,以下先給出上層使用方法辩恼。

public class MainActivity extends Activity {
SysPropertiesManager m;
static final int PROPID_1 = 100;
static final int PROPID_2 = 101;
static final int PROPID_3 = 102;
Button button1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
m =  (SysPropertiesManager)getSystemService(Context.PROPERTY_SERVICE);
if (m == null) {
Log.d("bpb", "can not find SysPropertiesManager!");
} else {
m.startPropListener();
try {
m.registeredPropListener(mMyPropListener);
mMyPropListener.addProperty("sss.sss.sss1", PROPID_1);
mMyPropListener.addProperty("sss.sss.sss2", PROPID_2);
mMyPropListener.addProperty("sss.sss.sss3", PROPID_3);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
button1 = (Button)findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Log.d("bpb", "onClick  ");
SystemProperties.set("xxx.xxx.xxx1", "xxx1");
SystemProperties.set("sss.sss.sss2", "sss2");
SystemProperties.set("xxx.xxx.xxx1", "xxx1");
SystemProperties.set("xxx.xxx.xxx1", "xxx1");
SystemProperties.set("sss.sss.sss1", "sss1");
}
});
}
MyPropListener mMyPropListener = new MyPropListener();
class MyPropListener extends BaseSysPropListener {
@Override
public void onPropertiesChanged(SysProperty props) {
super.onPropertiesChanged(props);
Log.d("bpb", "MainActivity onPropertiesChanged name:  "+props.name+" value:  "+props.value+" "+props.mPropId);
switch(props.mPropId) {
case PROPID_1:
break;
case PROPID_2:
break;
case PROPID_3:
break;
}
}
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
try {
m.unRegisteredPropListener(mMyPropListener);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

以上的SysPropertiesManager 和BaseSysPropListener 就是我們等會(huì)實(shí)現(xiàn)的類。
這個(gè)方法的架構(gòu)是這樣


各個(gè)目錄改到的地方有

framework base

framework base下 os目錄都是新增文件谓形,SysPropertiesManager類重點(diǎn)是如下

public SysPropertiesManager() {
mSysPropertiesRegistrar = ISysPropertiesRegistrar.Stub.asInterface(
ServiceManager.getService("syspropserver"));
try {
if ( mSysPropertiesRegistrar != null )
mSysPropertiesRegistrar.asBinder().linkToDeath(mDeathRecipent, 0);
} catch (RemoteException e) {
}
}

通過getService 來獲取底層應(yīng)用的binder服務(wù)灶伊,做個(gè)托管,
BaseSysPropListener extends ISysPropertiesListener.Stub類就是需要繼承來往下注冊(cè)的入口
另外ISysPropertiesListener.aidl 和ISysPropertiesRegistrar.aidl一個(gè)是被注冊(cè)和一個(gè)保持注冊(cè)者的倆個(gè)文件套耕,就是個(gè)觀察者模型谁帕。倆個(gè)的主要實(shí)現(xiàn)binder接口內(nèi)容是在framewrok native里,等會(huì)介紹冯袍。ListeningProps.aidl 和ListeningProps.java 倆個(gè)文件的協(xié)助是為了和framework native對(duì)應(yīng)的ListeningProps結(jié)構(gòu)體實(shí)現(xiàn)序列化傳輸, ListeningProps.java是繼承Parcelable的,因?yàn)槲覀冃枰@個(gè)序列化來傳遞我們參數(shù)數(shù)據(jù)到native層康愤。同理SysProperty.aidl 和SysProperty.java則是單向由native層序列化傳輸?shù)絝ramework base(這里都是由binder來實(shí)現(xiàn)的傳輸)儡循。結(jié)果返回的就是被監(jiān)聽的屬性包含類,可以直接從獲得到的SysProperty實(shí)例里拿出當(dāng)前監(jiān)聽到的屬性名稱和屬性值還有自己原先定義的對(duì)應(yīng)ID征冷。
SystemServiceRegistry文件择膝,就單純的實(shí)例化一個(gè)SysPropertiesManager并托給SystemServer來保存使用。如下做即可

//add bpb 2017.7
registerService(Context.PROPERTY_SERVICE, SysPropertiesManager.class,                new StaticServiceFetcher() {
@Override
public SysPropertiesManager createService() {
return new SysPropertiesManager();
}});

在SystemServiceRegistry.java的static初始化區(qū)添加這個(gè)就可以了检激。最后的Android.mk由于我們?cè)黾恿瞬簧賏idl文件肴捉,所以得修改編譯和導(dǎo)出到全局framework環(huán)境空間,修改如下:

LOCAL_SRC_FILES += \...
...........................................
core/java/android/os/ISysPropertiesListener.aidl \
core/java/android/os/ISysPropertiesRegistrar.aidl \ 

添加到末尾也可叔收。還有

aidl_files := \...
............................................
frameworks/base/core/java/android/os/SysProperty.aidl \
frameworks/base/core/java/android/os/ListeningProps.aidl \

這里ok齿穗,需要編譯framework base之前,別忘了饺律,make updateapi 先窃页。


framework native

framework native層級(jí),全是C++來實(shí)現(xiàn)ISysPropertiesListener.aidl 和ISysPropertiesRegistrar.aidl复濒,這里說說我對(duì)bnInterface 和bpInterface的理解脖卖,bnInterface繼承BBinder模板,主要是由remote方代碼塊所transact對(duì)應(yīng)的<int>code走的程序內(nèi)容巧颈, 而bpInterface則是本地想要條用remote方某接口前走的程序塊畦木,再在該代碼塊里面?zhèn)鬏攖ransaction內(nèi)容到remote方來判斷<int>code 來走onTransatc.理解流程下圖表示

bninterface和bpinterface理解

以上的ISysPropertiesListener,ISysPropertiesRegistrar都有實(shí)現(xiàn)client方的bpinterface砸泛,ISysPropertiesRegistrar還實(shí)現(xiàn)好bnInterface就形成了雙向binder綁定的局面馋劈。而真正在運(yùn)行的監(jiān)聽?wèi)?yīng)用時(shí)由一個(gè)init通過配置init.rc來啟動(dòng)的sysprobin來運(yùn)用這些native syspropservice庫。


system core和external修改地方

init目錄需要修改的地方不多晾嘶,就property_service.cpp如下代碼段

...........................................
void initPropFiFo() {
if (gFifoFd < 0) {
gFifoFd =  open("/data/myfifo", O_RDWR|O_NONBLOCK);
ERROR("open myfifo %d\n", gFifoFd);
if (gFifoFd < 0) {
mkfifo("/data/myfifo",0777);
gFifoFd =  open("/data/myfifo", O_RDWR|O_NONBLOCK);
ERROR("open myfifo %d\n", gFifoFd);
}
}
}
//==============bpbp
void start_property_change_service() {
propFiFo_ready = true;
//initPropFiFo();
}
void stop_property_change_service() {
propFiFo_ready = false;
close(gFifoFd);
gFifoFd = -1;
}
//定義屬性開關(guān) "sys.prop.listen" value 1 開妓雾, 0 關(guān)
void property_change_to_fifo(const char *name, const char *value)
{
//ERROR("property_change_ctl.to_fifo fd:%d  name:[%s] [%s]\n", gFifoFd, name, value);
if( memcmp(name,"sys.prop.listen", 15) == 0 ) {
if (memcmp(value,"1", 1) == 0 ) {
start_property_change_service();
} else {
stop_property_change_service();
}
}
if(gFifoFd > 0) {
char buf[100];
memset(buf, 0, 100);
int allLen = strlen(name)+strlen(value);
sprintf(buf, "%d%d%s:%s", allLen/10, allLen%10, name,value);
write(gFifoFd, buf, strlen(buf));
} else if (propFiFo_ready){
initPropFiFo();
}
}

比較簡(jiǎn)單的單純往安卓data目錄下的myfifo寫入屬性數(shù)據(jù),然后同時(shí)也用系統(tǒng)屬性來控制這個(gè)開關(guān)垒迂。
最后是property_change_to_fifo接口放置的地方械姻,

static void handle_property_set_fd(){
..............................................
if(r != sizeof(prop_msg)) {
ERROR("sys_prop: mis-match msg size received: %d expected: %zu: %s\n",
r, sizeof(prop_msg), strerror(errno));
close(s);
return;
}
property_change_to_fifo(msg.name, (char*) msg.value);
.....................................
}

這個(gè)是epoll有event數(shù)據(jù)回調(diào)的函數(shù)地方。但在init進(jìn)程里寫myfifo管道需要se安全策略配置机断,在sepoliy目錄里的init.te 末尾加入這段防止執(zhí)行寫入失敗報(bào)錯(cuò)問題楷拳。必須的!

#add bpb create /data/myfifo
#allow init proc_security:fifo_file rw_file_perms;
allow init system_data_file:fifo_file rw_file_perms;
allow init system_file:file execute;

在rootdir目錄里面的init.rc配置啟動(dòng)的syspropbin服務(wù)吏奸,配置如下
service syspropbin /sbin/syspropbin
class core
critical
seclabel u:r:syspropbin:s0
group root system

最后的重頭戲欢揖,就是我們的syspropbin服務(wù)的編寫,要實(shí)現(xiàn)不阻塞的監(jiān)聽管道和監(jiān)聽注冊(cè)應(yīng)用發(fā)來的ISysPropertiesListener奋蔚,主要利用好一個(gè)linux系統(tǒng)里的epoll機(jī)制就好了她混。
Android.mk文件直接mmm -B ./該目錄即可烈钞,這里面的過程仿照安卓原生的healthd電池充電服務(wù)來完成的。
重要的代碼段:

static void healthd_mainloop(void) {
while (1) {
struct epoll_event events[eventct];
int nevents;
int timeout = awake_poll_interval;
int mode_timeout;
healthd_mode_ops->preparetowait();
nevents = epoll_wait(epollfd, events, eventct, -1);
if (nevents == -1) {
if (errno == EINTR)
continue;
KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
break;
}
for (int n = 0; n < nevents; ++n) {
if (events[n].data.ptr)
(*(void (*)(int))events[n].data.ptr)(events[n].events);
}
}
return;
}

syspropbin有時(shí)間再添加講坤按。這個(gè)方法已經(jīng)在我目前做的項(xiàng)目用上了的毯欣。
需要的人士可先下載來看即可。

下載鏈接:
https://github.com/bpbwan/syspropListener

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末臭脓,一起剝皮案震驚了整個(gè)濱河市酗钞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌来累,老刑警劉巖砚作,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異嘹锁,居然都是意外死亡葫录,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門兼耀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來压昼,“玉大人,你說我怎么就攤上這事瘤运∏舷迹” “怎么了?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵拯坟,是天一觀的道長(zhǎng)但金。 經(jīng)常有香客問我,道長(zhǎng)郁季,這世上最難降的妖魔是什么冷溃? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮梦裂,結(jié)果婚禮上似枕,老公的妹妹穿的比我還像新娘。我一直安慰自己年柠,他們只是感情好凿歼,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著冗恨,像睡著了一般答憔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上掀抹,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天虐拓,我揣著相機(jī)與錄音,去河邊找鬼傲武。 笑死蓉驹,一個(gè)胖子當(dāng)著我的面吹牛城榛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播戒幔,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼吠谢,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼土童!你這毒婦竟也來了诗茎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤献汗,失蹤者是張志新(化名)和其女友劉穎敢订,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體罢吃,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡楚午,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了尿招。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片矾柜。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖就谜,靈堂內(nèi)的尸體忽然破棺而出怪蔑,到底是詐尸還是另有隱情,我是刑警寧澤丧荐,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布缆瓣,位于F島的核電站,受9級(jí)特大地震影響虹统,放射性物質(zhì)發(fā)生泄漏弓坞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一车荔、第九天 我趴在偏房一處隱蔽的房頂上張望渡冻。 院中可真熱鬧,春花似錦忧便、人聲如沸族吻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽呼奢。三九已至,卻和暖如春切平,著一層夾襖步出監(jiān)牢的瞬間握础,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工悴品, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留禀综,地道東北人简烘。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像定枷,于是被迫代替她去往敵國(guó)和親孤澎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容