این صفحه تغییرات درایور بایندر را در اندروید 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)درایور کلاسور همیشه از وراثت با اولویت خوب پشتیبانی کرده است. از آنجایی که تعداد فزایندهای از پردازشها در Android با اولویت بلادرنگ اجرا میشوند، در برخی موارد اکنون منطقی است که اگر یک رشته بلادرنگ تماس بایندر برقرار کند، رشته در فرآیندی که آن تماس را مدیریت میکند نیز در اولویت زمان واقعی اجرا میشود. برای پشتیبانی از این موارد استفاده، اندروید 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;