Android အတွင်းပိုင်းကို လေ့လာခြင်း
Android application တွေကို run လိုက်ပြီးရင် LogCat လေးမှာ တက်လာတာတွေကို ကြည့်ဖူးကြ မှာပါနော် (ဘာတွေမှန်း မသိဘူး ဟူ:P) ဒီနေ့တော့ Android ရဲ့ အတွင်းပိုင်းကို နည်းနည်း ကြည့်လိုက်ကြရအောင်။
Bionic
Android မှာ Linux kernel အတွက် C system interface ရအောင် Google ကနေ Bionic ဆိုတဲ့ Custom C library ကို develop လုပ်ခဲ့ပါတယ်။ သူ့ထဲမှာ thread creation တို့ synchronization တို့ အတွက် ရယ် ပြီးတော့ Android အတွက် သီးသန့် system properties တို့ logging တို့ကို implement လုပ်ထားတဲ့ pthreads ပါရှိပါတယ်။ ဒီလို ထပ်ထည့်ထားတာတွေရှိပေမယ့်လဲ Bionic က GNU libc ကို မယှဉ်နိုင်သေးပါဘူး။ Google အနေနဲ့ embedded hardware အတွက်သင့်တော်တဲ့ ပိုသေးပြီး မြန်နိုင်မယ့် library ဖြစ်ဖို့ မျှော်လင့်ပါတယ်။ GNU libc ကို arm-unknown-linux-gnueabi-4.2.4 toolchain နဲ့ compiled လုပ်ထားတာက 1.11 MiB ရှိပြီး Bionic ကတော့ 238KiB ဘဲရှိပါတယ်။ ဘာလို့လဲဆိုတော့ desktop machines တွေထက်စာရင် mobile phones တွေက memory နေရာနည်းနည်းဘဲ ယူမှ အဆင်ပြေမှာပါ။
Dalvik VM
Dalvik VM ကတော့ Google က engineer ဖြစ်တဲ့ Dan Bornstein ကရေးသားထားတာဖြစ်ပြီး၊ Dalvik byte-code တွေကို execute လုပ်ပါတယ်။ compiled လုပ်ထားတဲ့ Java code တွေကို တနည်းအားဖြင့် Java class file တွေကို Dalvik dex file အဖြစ်ပြောင်းရပါတယ်။ နောက်ဆုံးရလာဒ်ကတော့ Dalvik VM က Java နဲ့ ရေးထားတာကို execute လုပ်နိုင်ပါတယ်။ Dalvik ရဲ ့ လက်ရှိ implementation ကတော့ just-in-time compiler မဟုတ်ပါဘူး။ Dalvik applicatons တွေကို interpret လုပ်နေရတဲ့ အတွက် native code တွေထက်စာရင် အချိန် ပိုကြာပါတယ်။ ဒါပေမယ့် Dalvik မှာတော့ ကောင်းကွက် တစ်ချို ့ ရှိပါသေးတယ်။
ပထမတစ်ချက်က standard Java jar format ထက်စာရင် dex file format ကပိုကောင်းပါတယ်။ ဘာလို့လဲဆိုတော့ jar ကို compress လုပ်ထားတဲ့ size နဲ့ dex file ကို uncompress လုပ်ထားရင်တော့ file size ကတူတူနီးပါလောက်ရှိလို့ပါဘဲ။ ဒီအတွက် system memory ဆီကို decompress မလုပ်ဘဲနဲ့ကို execute လုပ်နိုင်မယ်၊ memory-mapped file ကနေ execute လုပ်နိုင်မယ် စတဲ့ အကျိုး ကျေးဇူးတွေ ရနိုင်ပါတယ်။ ပြီးတော့ နောက်တချက်က dex file ရဲ ့ အသုံးနဲ့တဲ့ portion တွေကို memory ကနေ ခဏဖယ်ထားပြီး လိုအပ်မှ ပြန်ပြီး reload လုပ်နိုင်ပါတယ်။
Android မှာ နောက်ထပ်ကောင်းတဲ့ တချက်က Zygote process ပါ။ Zygote ဆိုတာက Dalvik VM ရဲ ့ process တစ်ခုဖြစ်ပြီး core Java libraries တွေကို ဆွဲတင်ပေးပြီး byte-code တွေကို execute လုပ်ဖို့ ready ဖြစ်စေပါတယ်။ သူ့ရဲ ့ တာဝန်ကတော့ application အသစ်တစ်ခုကို launch လုပ်လိုက်တယ်ဆိုရင် Dalvik VM instances အသစ်တစ်ခု ပေါ်လာဖို့ တာဝန်ယူပါတယ်။ ဒီနေရာမှာ Zygote က copy-on-write semantics နဲ့ အလုပ်လုပ်ပါတယ်။ အဲ့ဒီလိုလုပ်ပေးတဲ့ အတွက် new application တွေမှာ ကြိုပြီး ခေါ်တင်ထားတဲ့ core libraries တွေရှိတဲ့ အတွက် ချက်ချင်း execute လုပ်နိုင်တဲ့ အတွက် start-up time ပိုမြန်စေပါတယ်။
နောက်ပြီးတော့ child process တွေက Dalvik text တွေ၊ data တွေကို Zygote နဲ့ share လုပ်ပြီးသုံးတဲ့ အတွက် memory စားသက်သာပါတယ်။ ဒီလို Zygote ရဲ ့ ကောင်းကွက်လေးတွေကတော့ process တိုင်းက ကိုယ်ပိုင် VM instance မှာ executes လုပ်စေမယ်ဆိုတဲ့ Dalvik ရဲ ့ ဒီဇိုင်းကြောင့်ပါ။ ဒီလို idea ကြောင့် Java application တစ်ခု crash ဖြစ်သွားရင် တခြား Java application မထိခိုက် နိုင်တော့ဘူးပေါ့။
Binder IPC
System Server ကတော့ system ရဲ ့ service တွေဖြစ်ကြတဲ့ Package Manager နဲ့ Power Manager တို့ ကို access လုပ်နိုင်ပါတယ်။ ဒီ service တွေကြောင့်ဘဲ user ကနေ input ထည့်လိုက်ရင် application တွေကို notify လုပ်တာတွေ စတာတွေလုပ်နိုင်ကြပါတယ်။ ဒီ process တွေကို Java နဲ့ ရေးသားထားတာဖြစ်ပြီး Dalvik VM ရဲ ့ instance အနေနဲ့ လုပ်ဆောင်ပါတယ်။ အဲ့ဒီ လို system ရဲ ့ service တွေကို access လုပ်ဖို့ ကိုယ့်ရဲ ့ user application သာဆိုရင်တော့ System Server ဆီကို Inter-Process Communication (IPC) သွားလုပ်ရပါတယ်။ Google ရဲ ့ Linux kernel ကို ထပ်ဖြည့်ထားတဲ့ Binder IPC ကြောင့်ဒီလို ကိစ္စမျိုးတွေ လုပ်နိုင်တာပါ။
Android ထဲက Binder ကတော့ Be နဲ့ Palm အဖွဲ့စည်းက developed လုပ်ထားတဲ့ OpenBinder ကို reduce လုပ်ပြီးမှ implementation လုပ်ထားတာပါ။ OpenBinder ကဘယ်လို ရည်ရွယ်ချက်နဲ့ လုပ်ထားလဲဆိုရင် သူ့ရဲ ့ ကိုယ်ပိုင် shell ကမှတဆင့် Binder environment ကို access လုပ်ဖို့ပါ။
Android မှာ သုံးထားတဲ့ Binder ကတော့ RMI(Remote Method Invocation) လိုမျိုး operation တွေလုပ်နိုင်ဖို့နဲ့ process တွေကြားမှာ security ကောင်းကောင်းနဲ့ တစ်ခုနဲ့တစ်ခု communicate လုပ်နိုင်ဖို့ပါ။ အမှန်တကယ်တော့ RMI ဆိုတာ remote application ဆီကို function arguments တွေပေးပြီး လှမ်းလုပ်ခိုင်းတာပါ။ ဒီလိုလှမ်းလုပ်ခိုင်းဖို့ ပေးလိုက်တဲ့ data တွေကို transmit လုပ်ဖို့ format တစ်ခုခုအဖြစ်သို့ ပြောင်းရပါတယ်။ အဲ့ဒီလိုလုပ်တာကိုတော့ marshalling လုပ်တယ်လို့ခေါ်ပါတယ်။ Android မှာတော့ marshalling ကို Android interface definition language (AIDL) ကနေတဆင့်လုပ်ဆောင်ပါတယ်။ အဲ့ဒီလိုမျိုး remote function calls တွေကို ကောင်းကောင်း အလုပ်လုပ်ပေးနိုင်ဖို့ marshalling အတွက် လိုအပ်တဲ့ code တွေကိုတော့ server အတွက်ရော client အတွက်ကော auto generate လုပ်ပေးပါတယ်။
ဒီတော့ ၀င်လာမယ့် incoming request တွေကို လက်ခံဖို့ register လုပ်ထားတဲ့ service တိုင်းက thread pool တစ်ခုကို run ထားရပါတယ်။ အကယ်လို့သာ threads run ထားတာ မရှိဘူးဆိုရင်တော့ Binder driver ကနေပြီးတော့ thread အသစ်တစ်ခုကို ဖန်တီးခိုင်းပါလိမ့်မယ်။ ဒီလိုမျိုး service တစ်ခုတည်းကိုဘဲ multiple request လာနေလည်း DOS (Denial-of-service) ဖြစ်မှာမဟုတ်ပါဘူး။
Process တွေကြားမှာ memory share သုံးတဲ့ကိစ္စတွေမှာလည်း Binder ကိုသုံးရပါတယ်။ Linux kernel ကိုမှ ashmen ဆိုတဲ့ device driver တစ်ခုထပ်ထည့်ထားပါတယ်။ ashmem ကိုသုံးပြီး file descriptor ကနေ memory location ကဘယ် region လို့ဆိုလိုက်ရင် သွားပြီး လှမ်းယူနိုင်စွမ်း ရှိတာပါ။ ဒီတော့ တခြား process တွေကို file descriptor လေးကို Binder ကတဆင့်ပို့ပေးနိုင်ပါတယ်။ အဲ့ဒီ file descriptor လေးကို လက်ခံရရှိတဲ့ process က ashmem file ကို mmap system call ဆီကို pass လုပ်ချင်းအားဖြင့် share memory region ကို access လုပ်လာနိုင်တာပါ။
Ps. အားလုံး ဘဲပျော်ရွှင်ပါစေ…
Ref: Android Stack by Michael Hills
Facebook comments:


