val connectivityManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManagerИ вот если вдуматься в синтаксис, ну абсурд же происходит! Вроде достаем сервис, а получаем менеджер. Да и системный же сервис работает в другом процессе, что за дичь вообще? Сейчас все раскидаем. Наше приключение начинается с Context. Два основных факта про Context. Первый – Context это God object умеющий все на свете и вообще связующий класс через который мы общаемся с системой. Второй – сам по себе Context это абстрактный класс.
У Context куча наследников, в том числе основные компоненты: Application, Activity, Service и т.д. В Context 200 методов и реализовывать их в каждом наследнике, учитывая то, что они делают примерно одно и тоже, это сизифов труд. Поэтому разработчики сделали класс ContextImpl, который реализует основные методы. Вспоминаем шаблон декоратор. Activity наследует Context, после Activity переопределяет методы Context которые ей нужны, а все остальные методы просто вызывают методы класса ContextImpl. Аналогично и во всеми остальными наследниками Context.
Нас сейчас интересует конкретный метод Context
getSystemService. Каждый раз при вызове этого метода он идет в SystemServiceRegistry, который по сути: Map<String, (Context) -> Any>. И getSystemService делает примерно вот что:fun getSystemService(str:Stiring): Any {
val fetcher = systemServiceRegistry[str]
return fetcher(this)
}SystemServiceRegistry это класс, в котором огромный блок static наполняющий эту саму
Map. Суть – есть имя сервиса и логика как его получить, обращаемся к SystemServiceRegistry по имени сервиса, и он нам его собирает. Точнее говоря, собирает не сам сервис, а некоторого клиента или менеджера который умеет работать с каким-то системным сервисом. Именно так мы и получаем ConnectivityManager, однако это только начало.При старте системы, она запускает SystemServer, который в свою очередь запускает системные сервисы, прям все. Сервисов много, но нас сейчас интересует ConnectivityServiceInitializer. ConnectivityServiceInitializer это системный сервис, основная задача которого просто создать объект класса ConnectivityService и сохранить его у себя. Хоть ConnectivityService и называется сервисом, это просто обычный класс, в котором скрыта логика по общению с netd. С тем самым демоном о котором говорили ранее.
Если ты дочитал до сюда и все еще легко ставь❤️. В системе есть AIDL интерфейс с названием IConnectivityManager. ConnectivityService это Stub интерфейса IConnectivityManager. Или по другому, к ConnectivityService кто-то может стучаться через Binder и вызывать его методы из другого процесса. И этот кто-то ConnectivityManager, который при создании получает Proxy интерфейса IConnectivityManager. Получив proxy, можно вызывать методы ConnectivityManager, который крутится в ConnectivityServiceInitializer и имеющий доступ к netd, а тем самым к информации о сети.
Жестко, я понимаю сам офигивал от такой картины. Главное тут это то, что во многих аспектах работает связка Manager–Service. Складываем все части мозаики воедино получаем что, есть системные сервисы и есть всякие менеджеры которые мы получаем из Context. Через эти менеджеры мы можем общаться с системными сервисами и общение это происходит через Binder. Разумеется не все что мы получаем через getSystemService обязательно общается с каким-то системным сервисом. Есть например LayoutInflator который ни с кем не общается и просто создается как обычный объект в SystemServiceRegistry.
В этом посте описана суть на примере ConnectivityManager. Есть некоторые сервисы, которые построены сложнее, где по 10 слоев абстракций между менеджером и системным сервисом. Однако основа у всех одна.