Как получить сервис от ServiceManager в Android?

У меня есть сомнения относительно услуг, зарегистрированных ServiceManager и не зарегистрированных SystemServiceRegistry.

В комментариях SystemServiceRegistry

/**
 * Manages all of the system services that can be returned by {@link Context#getSystemService}.
 * Used by {@link ContextImpl}.
 */

Это означает, что сервисы, зарегистрированные Системой, могут быть получены из контекста.

Что касается ServiceManager, как я могу получить доступ к услуге, добавленной ServiceManager в приложении, которое не было зарегистрировано SystemServiceRegistry?

2 ответа

Решение

Этот ответ действительно поздно, но другой способ доступа к методам в скрытом классе ServiceManager - это использование отражения. Поскольку все методы в классе являются статическими, вам не требуется ссылка на объект для передачи в метод invoke. Вы можете просто передать экземпляр класса. Чтобы получить экземпляр класса в скрытом классе, вы можете использовать немного больше отражения. Пример:

Class localClass = Class.forName("android.os.ServiceManager");
Method getService = localClass.getMethod("getService", new Class[] {String.class});
if(getService != null) {
   Object result = getService.invoke(localClass, new Object[]{Context.AUDIO_SERVICE});
   if(result != null) {
      IBinder binder = (IBinder) result;
      // DO WHAT EVER YOU WANT AT THIS POINT, YOU WILL
      // NEED TO CAST THE BINDER TO THE PROPER TYPE OF THE SERVICE YOU USE.
   }
}

Это почти все, что вам нужно сделать, чтобы получить доступ к скрытым или закрытым методам (хотя и с закрытыми методами, вам нужно изменить доступ к методу). Я знаю, что отражение в Android плохо, и это, как правило, веские причины, по которым некоторые API не раскрыты, но есть несколько допустимых сценариев использования. Если вы не часто вызываете отраженный код, снижение производительности не так уж страшно, а если это так, вы можете кэшировать методы, чтобы вам не приходилось выполнять поиск при каждом вызове. При этом будьте внимательны и анализируйте, действительно ли вам нужен доступ к закрытым API.

Как правильно упомянуто @CommonsWare, вам нужно использовать getSystemService() в контексте. например. для получения услуги определения местоположения:

LocationManager mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);

Для использования вашего пользовательского сервиса (при условии, что ваш сервис зарегистрирован в AndroidManifest.xml):

startService(new Intent(this, YourServiceClass.class));
Другие вопросы по тегам