Android内核 ServiceManager

getSystemService很尽职,你知道吗?

那个…嗯…曾记否上篇的Android Binder中留下的疑问?就是在Context的实现类中使用
getSystemService(String serviceName)方法获取一个系统服务,那么这些系统服务的Binder
引用时如何传递给客户端的呢?其实这里有个关键点,就是系统服务并不是通过startService()启
动的。

getSystemService函数的实现是在Context的实现类中,该函数返回的Service比较多。那
么就让我们看一下Activity、ContextThemeWrapper的部分源代码吧:

Activity:

@Override
public Object getSystemService(@ServiceName @NonNull String name) {
    if (getBaseContext() == null) {
        throw new IllegalStateException(
                "System services not available to Activities before onCreate()");
    }

    if (WINDOW_SERVICE.equals(name)) {
        return mWindowManager;
    } else if (SEARCH_SERVICE.equals(name)) {
        ensureSearchManager();
        return mSearchManager;
    }
    return super.getSystemService(name);
}

1.首先, if (getBaseContext() == null)判断 mBase(Context类型)是否为空。如果为空则 ,提
示Context没创建前调用了getSystemService的错误。至于,我为什么能准确地mBase这个名字呢?让
我们再看一段关于ContextWrapper(Activity的父类、Context的子类)的源代码:

Context mBase;

public ContextWrapper(Context base) {
    mBase = base;
}

/**
 * Set the base context for this ContextWrapper.  All calls will then be
 * delegated to the base context.  Throws
 * IllegalStateException if a base context has already been set.
 *
 * @param base The new base context for this wrapper.
 */
protected void attachBaseContext(Context base) {
    if (mBase != null) {
        throw new IllegalStateException("Base context already set");
    }
    mBase = base;
}

/**
 * @return the base context as set by the constructor or setBaseContext
 */
public Context getBaseContext() {
    return mBase;
}

以上很简单,也就是从父类继承下来的Context mBase属性。

2.if (WINDOW_SERVICE.equals(name)) {……}elseif(SEARCH_SERVICE.equals(name)){……}。这个
就是判断要取的服务是Window类型还是Search类型的。这个在Activity里有对应的WindowManager类
型和SearchManager类型属性,并且做了对应的实例化。

3.return super.getSystemService(name):当要取的服务不是Window类型也不是Search类型的时候,就
调用了父类(ContextThemeWrapper)的getSystemService(String name)帮你找服务。那么就让我们顺便看看
ContextThemeWrapper的源代码:

@Override public Object getSystemService(String name) {
    if (LAYOUT_INFLATER_SERVICE.equals(name)) {
        if (mInflater == null) {
            mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
        }
        return mInflater;
    }
    return getBaseContext().getSystemService(name);
}

4.这里也做了个Activity里类似的判断是否为 layout Inflater 服务,然后返回相应的layout Inflater 服务。

5.return getBaseContext().getSystemService(name):这里的话就回到了Context 这个抽象的基类。 我
们就再看看Context的源代码:

/**
 * Return the handle to a system-level service by name. The class of the
 * returned object varies by the requested name. Currently available names
 * are:
 *
 * <dl>
 *  <dt> {@link #WINDOW_SERVICE} ("window")
 *  <dd> The top-level window manager in which you can place custom
 *  windows.  The returned object is a {@link android.view.WindowManager}.
 *  <dt> {@link #LAYOUT_INFLATER_SERVICE} ("layout_inflater")
 *  <dd> A {@link android.view.LayoutInflater} for inflating layout resources
 *  in this context.
 *  <dt> {@link #ACTIVITY_SERVICE} ("activity")
 *  <dd> A {@link android.app.ActivityManager} for interacting with the
 *  global activity state of the system.
 *  <dt> {@link #POWER_SERVICE} ("power")
 *  <dd> A {@link android.os.PowerManager} for controlling power
 *  management.
 *  <dt> {@link #ALARM_SERVICE} ("alarm")
 *  <dd> A {@link android.app.AlarmManager} for receiving intents at the
 *  time of your choosing.
 *  <dt> {@link #NOTIFICATION_SERVICE} ("notification")
 *  <dd> A {@link android.app.NotificationManager} for informing the user
 *   of background events.
 *  <dt> {@link #KEYGUARD_SERVICE} ("keyguard")
 *  <dd> A {@link android.app.KeyguardManager} for controlling keyguard.
 *  <dt> {@link #LOCATION_SERVICE} ("location")
 *  <dd> A {@link android.location.LocationManager} for controlling location
 *   (e.g., GPS) updates.
 *  <dt> {@link #SEARCH_SERVICE} ("search")
 *  <dd> A {@link android.app.SearchManager} for handling search.
 *  <dt> {@link #VIBRATOR_SERVICE} ("vibrator")
 *  <dd> A {@link android.os.Vibrator} for interacting with the vibrator
 *  hardware.
 *  <dt> {@link #CONNECTIVITY_SERVICE} ("connection")
 *  <dd> A {@link android.net.ConnectivityManager ConnectivityManager} for
 *  handling management of network connections.
 *  <dt> {@link #WIFI_SERVICE} ("wifi")
 *  <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of
 * Wi-Fi connectivity.
 *  <dt> {@link #WIFI_P2P_SERVICE} ("wifip2p")
 *  <dd> A {@link android.net.wifi.p2p.WifiP2pManager WifiP2pManager} for management of
 * Wi-Fi Direct connectivity.
 * <dt> {@link #INPUT_METHOD_SERVICE} ("input_method")
 * <dd> An {@link android.view.inputmethod.InputMethodManager InputMethodManager}
 * for management of input methods.
 * <dt> {@link #UI_MODE_SERVICE} ("uimode")
 * <dd> An {@link android.app.UiModeManager} for controlling UI modes.
 * <dt> {@link #DOWNLOAD_SERVICE} ("download")
 * <dd> A {@link android.app.DownloadManager} for requesting HTTP downloads
 * <dt> {@link #BATTERY_SERVICE} ("batterymanager")
 * <dd> A {@link android.os.BatteryManager} for managing battery state
 * <dt> {@link #JOB_SCHEDULER_SERVICE} ("taskmanager")
 * <dd>  A {@link android.app.job.JobScheduler} for managing scheduled tasks
 * </dl>
 *
 * <p>Note:  System services obtained via this API may be closely associated with
 * the Context in which they are obtained from.  In general, do not share the
 * service objects between various different contexts (Activities, Applications,
 * Services, Providers, etc.)
 *
 * @param name The name of the desired service.
 *
 * @return The service or null if the name does not exist.
 *
 * @see #WINDOW_SERVICE
 * @see android.view.WindowManager
 * @see #LAYOUT_INFLATER_SERVICE
 * @see android.view.LayoutInflater
 * @see #ACTIVITY_SERVICE
 * @see android.app.ActivityManager
 * @see #POWER_SERVICE
 * @see android.os.PowerManager
 * @see #ALARM_SERVICE
 * @see android.app.AlarmManager
 * @see #NOTIFICATION_SERVICE
 * @see android.app.NotificationManager
 * @see #KEYGUARD_SERVICE
 * @see android.app.KeyguardManager
 * @see #LOCATION_SERVICE
 * @see android.location.LocationManager
 * @see #SEARCH_SERVICE
 * @see android.app.SearchManager
 * @see #SENSOR_SERVICE
 * @see android.hardware.SensorManager
 * @see #STORAGE_SERVICE
 * @see android.os.storage.StorageManager
 * @see #VIBRATOR_SERVICE
 * @see android.os.Vibrator
 * @see #CONNECTIVITY_SERVICE
 * @see android.net.ConnectivityManager
 * @see #WIFI_SERVICE
 * @see android.net.wifi.WifiManager
 * @see #AUDIO_SERVICE
 * @see android.media.AudioManager
 * @see #MEDIA_ROUTER_SERVICE
 * @see android.media.MediaRouter
 * @see #TELEPHONY_SERVICE
 * @see android.telephony.TelephonyManager
 * @see #INPUT_METHOD_SERVICE
 * @see android.view.inputmethod.InputMethodManager
 * @see #UI_MODE_SERVICE
 * @see android.app.UiModeManager
 * @see #DOWNLOAD_SERVICE
 * @see android.app.DownloadManager
 * @see #BATTERY_SERVICE
 * @see android.os.BatteryManager
 * @see #JOB_SCHEDULER_SERVICE
 * @see android.app.job.JobScheduler
 */
public abstract Object getSystemService(@ServiceName @NonNull String name);


/******************************以下是服务的名称***************************/


/**
 * Use with {@link #getSystemService} to retrieve a
 * {@link android.os.PowerManager} for controlling power management,
 * including "wake locks," which let you keep the device on while
 * you're running long tasks.
 */
public static final String POWER_SERVICE = "power";

/**
 * Use with {@link #getSystemService} to retrieve a
 * {@link android.view.WindowManager} for accessing the system's window
 * manager.
 *
 * @see #getSystemService
 * @see android.view.WindowManager
 */
public static final String WINDOW_SERVICE = "window";

/**
 * Use with {@link #getSystemService} to retrieve a
 * {@link android.view.LayoutInflater} for inflating layout resources in this
 * context.
 *
 * @see #getSystemService
 * @see android.view.LayoutInflater
 */
public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater";

/**
 * Use with {@link #getSystemService} to retrieve a
 * {@link android.accounts.AccountManager} for receiving intents at a
 * time of your choosing.
 *
 * @see #getSystemService
 * @see android.accounts.AccountManager
 */


 /*******************************下面还有很多很多*************************/

6.以上可以看出,如果在Activity和ContextThemeWrapper不能帮你取到服务的话,最终会回到Context来一个”大搜查”。

ServiceManager 管理的服务

ServiceManager是一个独立的进程!这里特别强调,它是一个进程!作用就跟它的名称一样,管理各种系统服务,如下图所示:

其实ServiceManager本身也是一个Service,Framework提供了一个系统函数,可以获取ServiceManager
对应的Binder引用,那就是BinderInternal.getContextObject()。该静态函数返回ServiceManager后,就
可以通过ServiceManger提供的方法获取其他服务Service的Binder引用。这种设计模式就好比:ServiceManager
是一个公司的总机,这个总计的号码是公开的,系统中任何进程都可以使用BinderInternal.getContextObject()
获取该总机的Binder对象,而当前用户想联系公司的其他人(服务)的时候,则要经过总机再获取到分机的号码。
这种设计模式的优点就是:系统中仅仅只暴漏一个全局Binder引用,那就是ServiceManager,而其他服务则可以
隐藏起来,从而有助于系统服务的扩展,以及调用系统服务的安全检查。其他系统服务在启动的时候,首先把自己
的Binder对象传递给ServiceManager,就是所谓的注册(addService)。

BinderInternal.getContextObject() ->ServiceManager ->其它Service的Binder引用

那么我们来看一看ServiceManager.getService()的源码:

public static IBinder getService(String name){
    try{
        IBinder service = sCache.get(name);
        if(servie != null){
            return service
        }else{
            return getIServiceManager().getService(name);
        }
    }catch (RemoteException e) {
        Log.e(TAG, "error in getService",e);
    }
    return null;
}

以上片段源码,sCache.get(name) 缓存中查看是否有对应的 Binder 对象,有则返回,没有则调用
return getIServiceManager.getService(name);第一个getIServiceManager()即用于返回系统中
唯一的ServiceManager对应的Binder。

接着看看getIServiceManager():

private static IServiceManager getIServiceManager() {
    if (sServiceManager != null) {
        return sServiceManager;
    }

    // Find the service manager
    sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
    return sServiceManager;
}

以上源码中,BinderInternal.getContextObject()静态函数用于返回ServiceManager对应的全局Binder
对象,该函数不需要任何参数,因为它的作用所致是固定的。

其他所有通过ServiceManager获取的系统服务的过程与以上基本相似,所不同的就是传递给ServiceManager
的服务名称不同,因为ServiceManager正是按照服务的名称(String)来保存不同的Binder。

Android 中的 Manager

在Android中,Manager的含义应该翻译为“经纪人”,Manager所管理的对象时服务本身,因为每一
个具体的服务一般都会提供多个API接口,而Manager所管理的就是这些API。客户端一般不能直接通过
Binder访问的服务,而是要经过一个Manager,对应的Manager类对客户端是可见的,而远程的服务类
对客户端是隐藏的。

而这些Manager的类内部都会存在一个远程服务Binder的变量,而且在一般情况下,这些Manager的构造
函数中都会包含这个Binder对象。即先通过ServiceManager获取远程服务的Binder引用,然后使用这个Binder
引用构造一个客户端本地可以访问的经纪人,然后客户端就可以通过经纪人间接访问远程的服务了。

这种设计的作用是为了屏蔽客户端直接访问远程服务,从而可以给应用程序提供灵活的、可控的API接口,比
如Ams。系统不希望用户直接去访问Ams,而是经过ActivityManager类去访问,而ActivityManager内部则
提供一些更具可操作性的数据结构,比如RecentTaskInfo数据结构封装了最近访问过的Task列表;MemoryInfo
数据类封装了和内存相关的信息。如下(RecentTaskInfo和MemoryInfo的源代码):

ActivityManager 中的 RecentTaskInfo 类 源码:

/**
 * Information you can retrieve about tasks that the user has most recently
 * started or visited.
 */
public static class RecentTaskInfo implements Parcelable {
    /**
     * If this task is currently running, this is the identifier for it.
     * If it is not running, this will be -1.
     */
    public int id;

    /**
     * The true identifier of this task, valid even if it is not running.
     */
    public int persistentId;

    /**
     * The original Intent used to launch the task.  You can use this
     * Intent to re-launch the task (if it is no longer running) or bring
     * the current task to the front.
     */
    public Intent baseIntent;

    /**
     * If this task was started from an alias, this is the actual
     * activity component that was initially started; the component of
     * the baseIntent in this case is the name of the actual activity
     * implementation that the alias referred to.  Otherwise, this is null.
     */
    public ComponentName origActivity;

    /**
     * Description of the task's last state.
     */
    public CharSequence description;

    /**
     * The id of the ActivityStack this Task was on most recently.
     * @hide
     */
    public int stackId;

    /**
     * The id of the user the task was running as.
     * @hide
     */
    public int userId;

    /**
     * The first time this task was active.
     * @hide
     */
    public long firstActiveTime;

    /**
     * The last time this task was active.
     * @hide
     */
    public long lastActiveTime;

    /**
     * The recent activity values for the highest activity in the stack to have set the values.
     * {@link Activity#setTaskDescription(android.app.ActivityManager.TaskDescription)}.
     */
    public TaskDescription taskDescription;

    /**
     * Task affiliation for grouping with other tasks.
     */
    public int affiliatedTaskId;

    /**
     * Task affiliation color of the source task with the affiliated task id.
     *
     * @hide
     */
    public int affiliatedTaskColor;

    public RecentTaskInfo() {
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(id);
        dest.writeInt(persistentId);
        if (baseIntent != null) {
            dest.writeInt(1);
            baseIntent.writeToParcel(dest, 0);
        } else {
            dest.writeInt(0);
        }
        ComponentName.writeToParcel(origActivity, dest);
        TextUtils.writeToParcel(description, dest,
                Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
        if (taskDescription != null) {
            dest.writeInt(1);
            taskDescription.writeToParcel(dest, 0);
        } else {
            dest.writeInt(0);
        }
        dest.writeInt(stackId);
        dest.writeInt(userId);
        dest.writeLong(firstActiveTime);
        dest.writeLong(lastActiveTime);
        dest.writeInt(affiliatedTaskId);
        dest.writeInt(affiliatedTaskColor);
    }

    public void readFromParcel(Parcel source) {
        id = source.readInt();
        persistentId = source.readInt();
        baseIntent = source.readInt() > 0 ? Intent.CREATOR.createFromParcel(source) : null;
        origActivity = ComponentName.readFromParcel(source);
        description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
        taskDescription = source.readInt() > 0 ?
                TaskDescription.CREATOR.createFromParcel(source) : null;
        stackId = source.readInt();
        userId = source.readInt();
        firstActiveTime = source.readLong();
        lastActiveTime = source.readLong();
        affiliatedTaskId = source.readInt();
        affiliatedTaskColor = source.readInt();
    }

    public static final Creator<RecentTaskInfo> CREATOR
            = new Creator<RecentTaskInfo>() {
        public RecentTaskInfo createFromParcel(Parcel source) {
            return new RecentTaskInfo(source);
        }
        public RecentTaskInfo[] newArray(int size) {
            return new RecentTaskInfo[size];
        }
    };

    private RecentTaskInfo(Parcel source) {
        readFromParcel(source);
    }
}

ActivityManager 的 MemoryInfo类 源代码 :

/**
 * Information you can retrieve about the available memory through
 * {@link ActivityManager#getMemoryInfo}.
 */
public static class MemoryInfo implements Parcelable {
    /**
     * The available memory on the system.  This number should not
     * be considered absolute: due to the nature of the kernel, a significant
     * portion of this memory is actually in use and needed for the overall
     * system to run well.
     */
    public long availMem;

    /**
     * The total memory accessible by the kernel.  This is basically the
     * RAM size of the device, not including below-kernel fixed allocations
     * like DMA buffers, RAM for the baseband CPU, etc.
     */
    public long totalMem;

    /**
     * The threshold of {@link #availMem} at which we consider memory to be
     * low and start killing background services and other non-extraneous
     * processes.
     */
    public long threshold;

    /**
     * Set to true if the system considers itself to currently be in a low
     * memory situation.
     */
    public boolean lowMemory;

    /** @hide */
    public long hiddenAppThreshold;
    /** @hide */
    public long secondaryServerThreshold;
    /** @hide */
    public long visibleAppThreshold;
    /** @hide */
    public long foregroundAppThreshold;

    public MemoryInfo() {
    }

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel dest, int flags) {
        dest.writeLong(availMem);
        dest.writeLong(totalMem);
        dest.writeLong(threshold);
        dest.writeInt(lowMemory ? 1 : 0);
        dest.writeLong(hiddenAppThreshold);
        dest.writeLong(secondaryServerThreshold);
        dest.writeLong(visibleAppThreshold);
        dest.writeLong(foregroundAppThreshold);
    }

    public void readFromParcel(Parcel source) {
        availMem = source.readLong();
        totalMem = source.readLong();
        threshold = source.readLong();
        lowMemory = source.readInt() != 0;
        hiddenAppThreshold = source.readLong();
        secondaryServerThreshold = source.readLong();
        visibleAppThreshold = source.readLong();
        foregroundAppThreshold = source.readLong();
    }

    public static final Creator<MemoryInfo> CREATOR
            = new Creator<MemoryInfo>() {
        public MemoryInfo createFromParcel(Parcel source) {
            return new MemoryInfo(source);
        }
        public MemoryInfo[] newArray(int size) {
            return new MemoryInfo[size];
        }
    };

    private MemoryInfo(Parcel source) {
        readFromParcel(source);
    }
}

这种通过Manager 访问远程服务的模型如下图: