این صفحه تغییرات درایور بایندر را در اندروید 8 توضیح میدهد، جزئیاتی در مورد استفاده از IPC کلاسور ارائه میکند و خطمشی SELinux مورد نیاز را فهرست میکند.
تغییرات در درایور کلاسور
با شروع اندروید 8، فریم ورک اندروید و HAL ها اکنون با استفاده از کلاسور با یکدیگر ارتباط برقرار می کنند. از آنجایی که این ارتباط ترافیک بایندر را به طور چشمگیری افزایش می دهد، اندروید 8 شامل چندین پیشرفت است که برای سریع نگه داشتن IPC کلاسور طراحی شده است. فروشندگان SoC و OEM ها باید مستقیماً از شاخه های مربوطه Android-4.4، android-4.9 و بالاتر از پروژه هسته/مشترک ادغام شوند.
چندین دامنه بایندر (زمینه ها)
مشترک-4.4 و بالاتر، از جمله بالادستبرای تقسیم شفاف ترافیک بایندر بین کد چارچوب (مستقل از دستگاه) و کد فروشنده (مخصوص دستگاه)، اندروید 8 مفهوم یک زمینه کلاسور را معرفی کرد. هر زمینه بایندر گره دستگاه و مدیر زمینه (سرویس) خود را دارد. شما می توانید به مدیر زمینه فقط از طریق گره دستگاهی که به آن تعلق دارد دسترسی داشته باشید و هنگام عبور یک گره بایندر از یک زمینه خاص، از همان زمینه فقط با فرآیند دیگری قابل دسترسی است، بنابراین دامنه ها به طور کامل از یکدیگر جدا می شوند. برای جزئیات بیشتر در مورد استفاده، به vndbinder و vndservicemanager مراجعه کنید.
پراکنده کردن
مشترک-4.4 و بالاتر، از جمله بالادستدر نسخه های قبلی اندروید، هر قطعه داده در تماس بایندر سه بار کپی شد:
- یک بار آن را به صورت سریال در یک
Parcel
در فرآیند تماس قرار دهید - یک بار در درایور هسته برای کپی کردن
Parcel
به فرآیند هدف - یک بار برای غیر سریالی کردن
Parcel
در فرآیند هدف
اندروید 8 از بهینهسازی جمعآوری پراکنده برای کاهش تعداد کپیها از 3 به 1 استفاده میکند. بهجای سریالسازی دادهها در یک Parcel
ابتدا، دادهها در ساختار اصلی و چیدمان حافظه خود باقی میمانند و راننده بلافاصله آنها را در فرآیند هدف کپی میکند. پس از اینکه داده ها در فرآیند هدف قرار گرفتند، ساختار و چیدمان حافظه یکسان است و می توان داده ها را بدون نیاز به کپی دیگری خواند.
قفل ریز دانه
مشترک-4.4 و بالاتر، از جمله بالادستدر نسخه های قبلی اندروید، درایور بایندر از یک قفل جهانی برای محافظت در برابر دسترسی همزمان به ساختارهای داده حیاتی استفاده می کرد. در حالی که کمترین مشاجره برای قفل وجود داشت، مشکل اصلی این بود که اگر یک نخ با اولویت پایین قفل را بدست آورد و سپس پیش دستی کرد، میتوانست رشتههای با اولویت بالاتری را که نیاز به بدست آوردن قفل مشابه دارند به طور جدی به تأخیر بیندازد. این باعث jank در پلت فرم شد.
تلاشهای اولیه برای حل این مشکل شامل غیرفعال کردن پیشپرداخت در حین نگه داشتن قفل جهانی بود. با این حال، این بیشتر یک هک بود تا یک راه حل واقعی، و در نهایت توسط بالادست رد شد و کنار گذاشته شد. تلاشهای بعدی بر روی ریزدانهتر کردن قفل متمرکز شد، نسخهای از آن از ژانویه 2017 در دستگاههای Pixel اجرا میشود. در حالی که اکثر این تغییرات عمومی شدند، بهبودهای اساسی در نسخههای بعدی انجام شد.
پس از شناسایی مشکلات کوچک در اجرای قفل ریز دانه، ما یک راه حل بهبود یافته با معماری قفل متفاوت ابداع کردیم و تغییرات را در تمام شاخه های هسته رایج ارائه کردیم. ما همچنان به آزمایش این پیاده سازی بر روی تعداد زیادی از دستگاه های مختلف ادامه می دهیم. از آنجایی که ما از هیچ مشکلی باخبر نیستیم، این پیاده سازی توصیه شده برای دستگاه هایی است که با اندروید 8 ارسال می شوند.
ارث بری با اولویت بلادرنگ
Common-4.4 و common-4.9 (به زودی upstream)درایور کلاسور همیشه از وراثت با اولویت خوب پشتیبانی کرده است. از آنجایی که تعداد فزایندهای از پردازشها در اندروید با اولویت بلادرنگ اجرا میشوند، در برخی موارد اکنون منطقی است که اگر یک رشته بلادرنگ تماس بایندر برقرار کند، رشتهای در فرآیندی که آن تماس را مدیریت میکند نیز در اولویت زمان واقعی اجرا میشود. . برای پشتیبانی از این موارد استفاده، اندروید 8 اکنون ارث بری اولویت بلادرنگ را در درایور بایندر پیادهسازی میکند.
علاوه بر وراثت اولویت در سطح تراکنش، وراثت اولویت گره به یک گره (شیء سرویس بایندر) اجازه می دهد تا حداقل اولویتی را مشخص کند که در آن فراخوانی ها به این گره باید اجرا شوند. نسخههای قبلی اندروید قبلاً از وراثت اولویت گره با مقادیر خوب پشتیبانی میکردند، اما اندروید 8 پشتیبانی از سیاستهای زمانبندی بلادرنگ وراثت گره را اضافه میکند.
فضای کاربری تغییر می کند
Android 8 شامل تمام تغییرات فضای کاربر مورد نیاز برای کار با درایور بایندر فعلی در هسته مشترک با یک استثنا است: پیاده سازی اصلی برای غیرفعال کردن ارث بری اولویت بلادرنگ برای /dev/binder
از ioctl استفاده می کرد. توسعه بعدی، کنترل وراثت اولویت را به روشی با دانه بندی دقیق تر تغییر داد که در هر حالت بایندر (و نه در هر زمینه) است. بنابراین، ioctl در شاخه مشترک Android نیست و در عوض در هستههای مشترک ما ارسال میشود.
اثر این تغییر این است که وراثت اولویت بلادرنگ به طور پیشفرض برای هر گره غیرفعال میشود. تیم عملکرد اندروید فعال کردن وراثت اولویت در زمان واقعی برای همه گرهها در دامنه hwbinder
مفید است. برای رسیدن به همان اثر، این تغییر را در فضای کاربری انتخاب کنید.
SHA برای هسته های معمولی
برای به دست آوردن تغییرات لازم در درایور بایندر، با SHA مناسب همگام سازی کنید:
- مشترک-3.18
cc8b90c121de ANDROID: binder: مجوزهای prio را در بازیابی بررسی نکنید. - مشترک-4.4
76b376eac7a2 ANDROID: binder: مجوزهای prio را در بازیابی بررسی نکنید. - مشترک-4.9
ecd972d4f9b5 ANDROID: binder: مجوزهای prio را در بازیابی بررسی نکنید.
با بایندر IPC کار کنید
از لحاظ تاریخی، فرآیندهای فروشنده از ارتباطات بین فرآیندی بایندر (IPC) برای برقراری ارتباط استفاده میکنند. در اندروید 8، گره دستگاه /dev/binder
منحصر به فرآیندهای فریمورک می شود، به این معنی که فرآیندهای فروشنده دیگر به آن دسترسی ندارند. فرآیندهای فروشنده می توانند به /dev/hwbinder
دسترسی داشته باشند، اما باید رابط های AIDL خود را برای استفاده از HIDL تبدیل کنند. برای فروشندگانی که می خواهند به استفاده از رابط های AIDL بین فرآیندهای فروشنده ادامه دهند، Android از IPC بایندر همانطور که در زیر توضیح داده شده است پشتیبانی می کند. در اندروید 10، Stable AIDL به همه فرآیندها اجازه می دهد تا از /dev/binder
استفاده کنند در حالی که حل برای ثبات، HIDL و /dev/hwbinder
حل شده را نیز تضمین می کند. برای نحوه استفاده از AIDL پایدار، به AIDL برای HAL مراجعه کنید.
vndbinder
اندروید 8 از یک دامنه جدید بایندر برای استفاده توسط سرویسهای فروشنده پشتیبانی میکند که با استفاده از /dev/vndbinder
به جای /dev/binder
قابل دسترسی است. با اضافه شدن /dev/vndbinder
، اندروید اکنون دارای سه دامنه IPC زیر است:
دامنه IPC | توضیحات |
---|---|
/dev/binder | IPC بین فرآیندهای چارچوب/برنامه با رابط های AIDL |
/dev/hwbinder | IPC بین فرآیندهای چارچوب/فروشنده با رابط های HIDL IPC بین فرآیندهای فروشنده با رابط های HIDL |
/dev/vndbinder | IPC بین فرآیندهای فروشنده/فروشنده با رابط های AIDL |
برای اینکه /dev/vndbinder
ظاهر شود، مطمئن شوید که مورد پیکربندی هسته CONFIG_ANDROID_BINDER_DEVICES
روی "binder,hwbinder,vndbinder"
تنظیم شده است (این پیش فرض در درختان هسته رایج اندروید است).
به طور معمول، فرآیندهای فروشنده مستقیماً درایور بایندر را باز نمیکنند و به جای آن به کتابخانه فضای کاربر libbinder
پیوند میخورند که درایور بایندر را باز میکند. افزودن متد برای ::android::ProcessState()
درایور بایندر را برای libbinder
انتخاب می کند. فرآیندهای فروشنده باید این متد را قبل از فراخوانی به ProcessState,
IPCThreadState
یا به طور کلی قبل از برقراری تماس بایندر فراخوانی کنند. برای استفاده، فراخوانی زیر را بعد از main()
یک فرآیند فروشنده (مشتری و سرور) قرار دهید:
ProcessState::initWithDriver("/dev/vndbinder");
vndservicemanager
پیش از این، خدمات بایندر در servicemanager
ثبت می شد، جایی که می توانستند توسط فرآیندهای دیگر بازیابی شوند. در اندروید 8، servicemanager
اکنون منحصراً توسط فرآیندهای فریمورک و برنامه استفاده می شود و فرآیندهای فروشنده دیگر نمی توانند به آن دسترسی داشته باشند.
با این حال، سرویسهای فروشنده اکنون میتوانند از vndservicemanager
استفاده کنند، یک نمونه جدید از servicemanager
که از /dev/vndbinder
به جای /dev/binder
استفاده میکند و از همان منابعی که Framework servicemanager
ساخته شده است. فرآیندهای فروشنده برای صحبت با vndservicemanager
نیازی به ایجاد تغییرات ندارند. هنگامی که یک فرآیند فروشنده / dev/vndbinder
باز می شود، جستجوهای سرویس به طور خودکار به vndservicemanager
می روند.
باینری vndservicemanager
در فایل های پیش فرض دستگاه اندروید گنجانده شده است.
خط مشی SELinux
فرآیندهای فروشنده که می خواهند از عملکرد بایندر برای برقراری ارتباط با یکدیگر استفاده کنند، به موارد زیر نیاز دارند:
- دسترسی به
/dev/vndbinder
. - Binder
{transfer, call}
بهvndservicemanager
متصل می شود. -
binder_call(A, B)
برای هر دامنه فروشنده A که می خواهد به دامنه فروشنده B از طریق رابط بایندر فروشنده فراخوانی کند. - اجازه
{add, find}
سرویسها درvndservicemanager
.
برای برآوردن الزامات 1 و 2، از ماکرو vndbinder_use()
استفاده کنید:
vndbinder_use(some_vendor_process_domain);
برای برآورده کردن شرط 3، binder_call(A, B)
برای فرآیندهای فروشنده A و B که نیاز به صحبت در مورد binder دارند، میتواند در جای خود باقی بماند و نیازی به تغییر نام ندارد.
برای برآورده کردن شرط 4، باید در نحوه استفاده از نامهای سرویس، برچسبهای سرویس و قوانین تغییراتی ایجاد کنید.
برای جزئیات بیشتر در مورد SELinux، به Linux Enhanced Security در Android مراجعه کنید. برای جزئیات بیشتر در مورد SELinux در Android 8.0، SELinux برای Android 8.0 را ببینید.
نام خدمات
قبلاً، فروشنده نامهای سرویس ثبتشده را در یک فایل service_contexts
پردازش میکند و قوانین مربوطه را برای دسترسی به آن فایل اضافه میکند. فایل نمونه service_contexts
از device/google/marlin/sepolicy
:
AtCmdFwd u:object_r:atfwd_service:s0 cneservice u:object_r:cne_service:s0 qti.ims.connectionmanagerservice u:object_r:imscm_service:s0 rcs u:object_r:radio_service:s0 uce u:object_r:uce_service:s0 vendor.qcom.PeripheralManager u:object_r:per_mgr_service:s0
در اندروید 8، vndservicemanager
به جای آن فایل vndservice_contexts
را بارگیری می کند. سرویس های فروشنده که به vndservicemanager
مهاجرت می کنند (و قبلاً در فایل service_contexts
قدیمی هستند) باید به فایل vndservice_contexts
جدید اضافه شوند.
برچسب های خدمات
قبلاً برچسب های سرویس مانند u:object_r:atfwd_service:s0
در یک فایل service.te
تعریف شده بودند. مثال:
type atfwd_service, service_manager_type;
در اندروید 8 باید نوع را به vndservice_manager_type
تغییر دهید و قانون را به فایل vndservice.te
منتقل کنید. مثال:
type atfwd_service, vndservice_manager_type;
قوانین مدیر سرویس
قبلاً، قوانین به دامنهها اجازه دسترسی برای افزودن یا یافتن خدمات از servicemanager
را میداد. مثال:
allow atfwd atfwd_service:service_manager find; allow some_vendor_app atfwd_service:service_manager add;
در اندروید 8، چنین قوانینی می توانند باقی بمانند و از همان کلاس استفاده کنند. مثال:
allow atfwd atfwd_service:service_manager find; allow some_vendor_app atfwd_service:service_manager add;