3.Android内核 ServiceManager




getSystemService很尽职,你知道吗?



   那个...嗯...曾记否上篇的2.Android Binder 中留下的疑问?就是在Context的实现类中使用

getSystemService(String serviceName)方法获取一个系统服务,那么这些系统服务的Binder

引用时如何传递给客户端的呢?其实这里有个关键点,就是系统服务并不是通过startService()启

动的。


   getSystemService函数的实现是在Context的实现类中,该函数返回的Service比较多。那

么就让我们看一下ActivityContextThemeWrapper的部分源代码吧:


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这个名字呢?让

我们再看一段关于ContextWrapperActivity的父类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 访问远程服务的模型如下图:





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值