iis服务器助手广告广告
返回顶部
首页 > 资讯 > 移动开发 >Android系统服务是如何获取的
  • 214
分享到

Android系统服务是如何获取的

2024-04-02 19:04:59 214人浏览 泡泡鱼
摘要

目录关于获取系统服务的猜想获取系统服务源码实现真正的系统服务提供者关于获取系统服务的猜想 Android获取系统服务一般都需要用getSystemService指定系统服务名称获取

关于获取系统服务的猜想

Android获取系统服务一般都需要用getSystemService指定系统服务名称获取:


val wm = getSystemService(Context.WINDOW_SERVICE) as WindowManager

在实际开发中,当我们需要编写提供某一业务流程处理的Manager,通常会实现为单例。那么上面那行代码背后发生了什么,为什么Android不使用单例模式呢?下面我们观察Android是如何设计获取系统服务的,它如何从应用侧到达系统侧。

可以思考一下,不在每个服务中单独使用单例的原因大概是因为Android提供的系统服务众多,都使用getSystemService方法相当于提供了统一的入口。同时因为方法参数中的服务名称字符串,可以提供一个Map来统一存放各种服务实例,这与单例模式十分接近,相当于统一管理各种单例的变种。那么事实是不是这样呢?(下方源码只保留关键代码,api 30)

获取系统服务源码实现

各种继承或者持有Context的组件的getSystemService方法都会调用ContextImpl的同名方法:


//ContextImpl.java
  public Object getSystemService(String name) {
    return SystemServiceReGIStry.getSystemService(this, name);
  }

SystemServiceRegistry一看就是统一注册系统服务的地方:


//SystemServiceRegistry.java  
  public static Object getSystemService(ContextImpl ctx, String name) {
    final ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
    final Object ret = fetcher.getService(ctx);
    return ret;
  }

这里我们确实发现了Map,可却不是从String到系统服务的Map,SYSTEM_SERVICE_FETCHERS的类型为Map<String, ServiceFetcher<?>>。


//SystemServiceRegistry.java  
  static abstract interface ServiceFetcher<T> {
    T getService(ContextImpl ctx);
  }

这个SystemServiceRegistry中的内部接口ServiceFetcher,看上去像是各种系统服务的工厂接口。我们看它的实现类:


//SystemServiceRegistry.java  
  static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {
    private final int mCacheIndex;

    CachedServiceFetcher() {
      mCacheIndex = sServiceCacheSize++;
    }

    @Override
    public final T getService(ContextImpl ctx) {
      final Object[] cache = ctx.mServiceCache;
      T ret = null;

      T service = (T) cache[mCacheIndex];
      if (service != null) {
        ret = service;
      } else {
        service = createService(ctx);
        cache[mCacheIndex] = service;
        ret = service;
      }
      return ret;
    }

    public abstract T createService(ContextImpl ctx) throws ServiceNotFoundException;
  }

getService方法精简了大量保证线程安全的同步措施,只保留了最核心的逻辑。可以看到另有一个类型为Object[]的数组ctx.mServiceCache,getService从中用下标mCacheIndex获取系统服务,如果服务为空则使用createService方法创建服务并放在数组中。可以说,这个ctx.mServiceCache数组起到了我们最初设想的从String到系统服务的Map的存放所有系统服务的作用。这个映射变为了:


假象的映射(从String到系统服务) <=> SYSTEM_SERVICE_FETCHERS映射(从String到ServiceFetcher)
                    + ctx.mServiceCache数组(ServiceFetcher中的mCacheIndex下标到系统服务)

这个SYSTEM_SERVICE_FETCHERS映射在SystemServiceRegistry的静态初始化快中被统一填充,同时提供了上方没有实现的createService:


//SystemServiceRegistry.java
  static {
    registerService(Context.WINDOW_SERVICE, WindowManager.class,
        new CachedServiceFetcher<WindowManager>() {
      @Override
      public WindowManager createService(ContextImpl ctx) {
        return new WindowManagerImpl(ctx);
      }}); 
  }
  private static <T> void registerService(@NonNull String serviceName,
      @NonNull Class<T> serviceClass, @NonNull ServiceFetcher<T> serviceFetcher) {
    SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
  }

SystemServiceRegistry类初始化时,ctx.mServiceCache系统服务数组还是空的,当某一系统服务需要时,上方CachedServiceFetcher中getService会调用createService创建服务并存放在特定mCacheIndex下标中。

总结一下就是:在Android获取系统服务的流程中,使用工厂模式创建系统服务,使用Map管理工厂,使用数组管理系统服务实例。每种服务在每个ContextImpl中的数组中最多只有一个,且使用前不会提前创建,这点和单例的懒汉式是一致的。

真正的系统服务提供者

我们知道Android Framework中系统服务是运行在系统进程中,需要通过Binder机制与应用进程通信,如果我们不考虑系统侧实现,上面拿到的类真的应用侧的Binder类么?其实并不全是,依旧查看工厂类中的工厂方法:

  • 上面获取到的服务类,有些类的确是系统侧的系统服务对应到应用侧的Binder类,比如AlarmManager:

//SystemServiceRegistry.java    
	registerService(Context.ALARM_SERVICE, AlarmManager.class,
        new CachedServiceFetcher<AlarmManager>() {
      @Override
      public AlarmManager createService(ContextImpl ctx) throws ServiceNotFoundException {
        IBinder b = ServiceManager.getServiceOrThrow(Context.ALARM_SERVICE);
        IAlarmManager service = IAlarmManager.Stub.asInterface(b);
        return new AlarmManager(service, ctx);
      }});
  • 有些则是对这些Binder类的直接封装,比如ActivityManager:

//SystemServiceRegistry.java    
    registerService(Context.ACTIVITY_SERVICE, ActivityManager.class,
        new CachedServiceFetcher<ActivityManager>() {
      @Override
      public ActivityManager createService(ContextImpl ctx) {
        return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
      }});

其中大量的方法使用getService与getTaskService进行委托:


//ActivityManager.java
  public void killUid(int uid, String reason) {
    try {
      getService().killUid(UserHandle.getAppId(uid),
          UserHandle.getUserId(uid), reason);
    } catch (RemoteException e) {
      throw e.rethrowFromSystemServer();
    }
  }
  
  public List<RunningTaskInfo> getRunningTasks(int maxNum)
      throws SecurityException {
    try {
      return getTaskService().getTasks(maxNum);
    } catch (RemoteException e) {
      throw e.rethrowFromSystemServer();
    }
  }
  
  public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
  }

  private static IActivityTaskManager getTaskService() {
    return ActivityTaskManager.getService();
  }

而getService与getTaskService都是单例方法,另外使用ServiceManager获取真正的Binder类。

  • 另外还有些系统服务为了便于使用,封装得更加复杂,比如WindowManager:

    registerService(Context.WINDOW_SERVICE, WindowManager.class,
        new CachedServiceFetcher<WindowManager>() {
      @Override
      public WindowManager createService(ContextImpl ctx) {
        return new WindowManagerImpl(ctx);
      }});

这里的各不同Context的WindowManagerImpl会统一调用到WindowManagerGlobal,而WindowManagerGlobal在addView时会创建ViewRootImpl,并将Binder类windowsession传递给ViewRootImpl,由ViewRootImpl完成与WMS通信的工作。

以上实现了获取系统服务时从应用侧到达系统侧的过程。

以上就是Android系统服务是如何获取的的详细内容,更多关于Android系统服务获取的资料请关注编程网其它相关文章!

--结束END--

本文标题: Android系统服务是如何获取的

本文链接: https://www.lsjlt.com/news/122406.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Android系统服务是如何获取的
    目录关于获取系统服务的猜想获取系统服务源码实现真正的系统服务提供者关于获取系统服务的猜想 Android获取系统服务一般都需要用getSystemService指定系统服务名称获取...
    99+
    2024-04-02
  • Android应用中是如何获取系统语言的
    Android应用中是如何获取系统语言的?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。获取系统当前语言是一个比较常用的功能,在 Android 7.0 系统上旧函数获取到的当前...
    99+
    2023-05-31
    android roi
  • Android获取系统版本
    Android获取系统版本 在Android开发中,我们经常需要获取设备的系统版本信息。可以通过以下代码获取当前Android设备的系统版本: String version = Build.VERSI...
    99+
    2023-10-22
    android Android
  • Android中是如何获取手机联系人的
    这篇文章给大家介绍Android中是如何获取手机联系人的,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Android 获取系统联系人信息的实例一、获取手机联系人姓名及手机号//跳转到系统联系人应用 Inten...
    99+
    2023-05-30
    android
  • 如何在Android中获取系统储存信息
    这篇文章给大家介绍如何在Android中获取系统储存信息,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。获取SD卡上的储存信息:    private String&nb...
    99+
    2023-05-30
    android
  • android中是如何获取联系人所有信息的
    这篇文章将为大家详细讲解有关android中是如何获取联系人所有信息的,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。工具类:package com.example.test;imp...
    99+
    2023-05-30
    android
  • Android 10系统及以上IMEI的获取
    IMEI是一个15位的数字标识,用于唯一标识移动通信设备,例如手机、平板电脑和调制解调器等。每个移动设备都有一个独特的IMEI号码,它不随SIM卡的更换而改变。IMEI通常被用于跟踪设备的状态、维...
    99+
    2023-10-26
    android
  • android 获取当前系统选择的语言
    获取当前系统选择的语言的Java代码: Locale currentLocale = Locale.getDefault(); String currentLanguage = currentLocale.getLanguage();...
    99+
    2023-09-05
    android java 语言
  • Java中如何获取系统时间
    Java中获取系统时间的方法:1、通过Date类来获取当前时间;2、通过System类中的currentTimeMillis方法来获取当前时间;3、通过Calendar类来获取当前时间;具体操作示例:通过Date类来获取当前时间。Date ...
    99+
    2024-04-02
  • python如何获取当前系统的日期
    目录获取当前系统的日期datetime包获得当前日期时间datetime类strftime按指定格式输出字符获取当前系统的日期 python获取当前系统时间,主要通过Python中的...
    99+
    2024-04-02
  • Android 如何获取有效的DeviceId
    目录 前言官方唯一标识符建议使用广告 ID使用实例 ID 和 GUID不要使用 MAC 地址标识符特性常见用例和适用的标识符 解决方案DeviceIdANDROID_IDMac地址UUI...
    99+
    2023-09-03
    android
  • Linux系统是如何从终端获取命令帮助
    Linux系统是如何从终端获取命令帮助,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。Linux系统主要是以命令行的方式进行工作,所以有许多的命令需要用到,而且命令中还包含着...
    99+
    2023-06-28
  • MySQL如何获取系统当前时间
    小编给大家分享一下MySQL如何获取系统当前时间,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!获取系统当前时间SELECT CURTIME() ...
    99+
    2023-06-17
  • sql server中如何获取系统时间
    sql server中如何获取系统时间,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Sql Server 中一个非常强大的日期格式化函数: 获...
    99+
    2024-04-02
  • c语言如何获取系统时间
    要在C语言中获取系统时间,可以使用 <time.h> 头文件中的函数。以下是一些获取系统时间的常用函数: time()...
    99+
    2024-04-02
  • oracle如何获取系统当前日期
    在Oracle中,可以使用以下方法获取系统的当前日期:1. 使用SYSDATE函数:SYSDATE函数返回一个包含当前日期和时间的日...
    99+
    2023-08-12
    oracle
  • android如何获取经纬度
    android 定位的两种方式:GPS_PROVIDER and NETWORK_PROVIDER定位的可以借助LocationManager来实现MainActivity代码static final String TAG = "MainA...
    99+
    2023-05-31
    android 经纬度 roi
  • Android如何获取IP和UA
    本篇内容主要讲解“Android如何获取IP和UA”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Android如何获取IP和UA”吧!获取IP最近接入了一个新的SDK,初始化接口需要传入当前设备...
    99+
    2023-07-05
  • Android如何获取root权限
    要在Android设备上获取root权限,您需要进行以下步骤:1. 解锁设备的引导加载程序(bootloader)。2. 安装一个定...
    99+
    2023-10-11
    Android
  • android如何获取当前activity
    要获取当前activity,可以使用以下方式:1. 在Activity类中,可以使用`this`关键字来获取当前activity的实...
    99+
    2023-08-12
    android activity
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作