ActivityManager与Proxy模式的运用

为了研究安卓横竖屏切换原理,深入学习了一下ActivityManager的设计模式。

一 Proxy模式

意图:

       为其他对象提供一种代理以控制这个对象的访问。

适用性:

  l  远程代理( Remote Proxy ): 为一个对象在不同的地址空间提供局部代表。

  l  虚代理(Virtual Proxy)根据需要创建开销很大的对象。使用一个代理对象作为代表,在真正的需要时进行创建。

  l  保护代理(Protection Proxy):控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。

  l  智能指引(Smart Reference): 取代了简单的指针,它在访问对象时执行一些附加操作。对指向实际对象的引用计数,

    这样当该对象没有引用时,可以自动释放它,智能指针当第一次引用一个持久对象时,将它装入内存。

    在访问一个实际对象前,检查是否已经锁定了它,以确保其他对象不能改变它

结构:

    

  

运行时刻一种可能的代理结构的对象图:

        

    

理解:

  1 ) Remote Proxy可以隐藏一个对象存在于不同地址空间的事实。但是提供一

    个代理对象,使用起来就像在使用真正的对象一样。

  2) Virtual Proxy 可以进行最优化,例如根据要求创建对象。copy - on – write。

    根据实际的需求对所代理的对象进行合理管理(创建加载销毁)

  3) Protection Proxies和Smart Reference都允许在访问一个对象时有一些附加

    的内务处理;对不同的访问设置权限,对对象进行保护。

二 Android中ActivityManager

从官方文档的介绍可以看到ActivityManager的作用:

  是与系统所有正在运行着的Acitivity进行交互,对系统所有运行中的Activity相关信息(Task,Memory,Service,App)

  进行管理和维护;提供了相应的接口用于获取这些信息。

 

但是这些信息真正维护并不是ActivityManager来负责的,从其中的众多接口getXXX()可以看到其中都是使用:

public List<RunningAppProcessInfo> getRunningAppProcesses() {
    return ActivityManagerNative.getDefault().getRunningAppProcesses();
} 

  都是通过这个ActivityManagerNative.getDefault()的操作来实现这些信息的获取。

虽然再继续进入函数查找,仍然不能知道到底是哪一个类的对象在实施具体的操作。

 

  所以要看清楚ActivityManager真正是和谁交互,

就需要去探究实施Activity Manager框架相关类作、继承关系和层次结构以及控制关系。

 

三 Android中Activity Manager相关类继承层次关系

       看一下类结构图如下:

      

    

  IActivityManager作为ActivityManagerProxy和ActivityManagerNative的公共接口

所以两个类具有部分相同的接口,可以实现合理的代理模式

  ActivityManagerProxy代理类是ActivityManagerNative的内部类;

ActivityManagerNative是个抽象类,真正发挥作用的是它的子类ActivityManagerService(系统Service组件)

 ActivityManagerNative源码:

public abstract class ActivityManagerNative extends Binder implements IActivityManager
{
	/**
	 * Cast a Binder object into an activity manager interface, generating
	 * a proxy if needed.
	 */
	static public IActivityManager asInterface(IBinder obj) {
		if (obj == null) {
			return null;
		}
		IActivityManager in =
			(IActivityManager)obj.queryLocalInterface(descriptor);
		if (in != null) {
			return in;
		}

		return new ActivityManagerProxy(obj);
	}

	/**
	 * Retrieve the system's default/global activity manager.
	 */
	static public IActivityManager getDefault() {
		return gDefault.get();
	}
	class ActivityManagerProxy implements IActivityManager{
		…  //内部类
	}
}

ActivityManagerService中设置横竖屏相关源码:
public final class ActivityManagerService extends ActivityManagerNative
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
	//...
	@Override
    public void setRequestedOrientation(IBinder token, int requestedOrientation) {
        synchronized (this) {
            ActivityRecord r = ActivityRecord.isInStackLocked(token);
            if (r == null) {
                return;
            }
            final long origId = Binder.clearCallingIdentity();
            mWindowManager.setAppOrientation(r.appToken, requestedOrientation);
            Configuration config = mWindowManager.updateOrientationFromAppTokens(
                    mConfiguration, r.mayFreezeScreenLocked(r.app) ? r.appToken : null);
            if (config != null) {
                r.frozenBeforeDestroy = true;
                if (!updateConfigurationLocked(config, r, false, false)) {//当返回false,就是现在的状态要改变(比如重启Activity)
                    mStackSupervisor.resumeTopActivitiesLocked();//调用ActivityStackSupervisor的resumeTopActivitiesLocked启动最上面的Activity
                }
            }
            Binder.restoreCallingIdentity(origId);
        }
    }
	//...
}

涉及到WindowManagerService的代码:

public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
	//...
	@Override
    public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                "setAppOrientation()")) {
            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
        }

        synchronized(mWindowMap) {
            AppWindowToken atoken = findAppWindowToken(token.asBinder());
            if (atoken == null) {
                Slog.w(TAG, "Attempted to set orientation of non-existing app token: " + token);
                return;
            }

            atoken.requestedOrientation = requestedOrientation;//找到这个apptoken的APPWindowToken,然后将其requestedOrientation值赋值
        }
    }
	@Override
    public Configuration updateOrientationFromAppTokens(
            Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                "updateOrientationFromAppTokens()")) {
            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
        }

        Configuration config = null;
        long ident = Binder.clearCallingIdentity();

        synchronized(mWindowMap) {
            config = updateOrientationFromAppTokensLocked(currentConfig,
                    freezeThisOneIfNeeded);
        }

        Binder.restoreCallingIdentity(ident);
        return config;
    }
	private Configuration updateOrientationFromAppTokensLocked(
            Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
        Configuration config = null;

        if (updateOrientationFromAppTokensLocked(false)) {//返回true,需要旋转
            if (freezeThisOneIfNeeded != null) {
                AppWindowToken atoken = findAppWindowToken(freezeThisOneIfNeeded);
                if (atoken != null) {
                    startAppFreezingScreenLocked(atoken);
                }
            }
            config = computeNewConfigurationLocked();//计算Configuration返回

        } else if (currentConfig != null) {
            // No obvious action we need to take, but if our current
            // state mismatches the activity manager's, update it,
            // disregarding font scale, which should remain set to
            // the value of the previous configuration.
            mTempConfiguration.setToDefaults();
            mTempConfiguration.fontScale = currentConfig.fontScale;
            if (computeScreenConfigurationLocked(mTempConfiguration)) {
                if (currentConfig.diff(mTempConfiguration) != 0) {
                    mWaitingForConfig = true;
                    final DisplayContent displayContent = getDefaultDisplayContentLocked();
                    displayContent.layoutNeeded = true;
                    int anim[] = new int[2];
                    if (displayContent.isDimming()) {
                        anim[0] = anim[1] = 0;
                    } else {
                        mPolicy.selectRotationAnimationLw(anim);
                    }
                    startFreezingDisplayLocked(false, anim[0], anim[1]);
                    config = new Configuration(mTempConfiguration);
                }
            }
        }
        return config;
    }
	/*
	 * * Determine the new desired orientation of the display, returning * a
	 * non-null new Configuration if it has changed from the current * orientation.
	 * IF TRUE IS RETURNED SOMEONE MUST CALL * setNewConfiguration() TO TELL THE
	 * WINDOW MANAGER IT CAN UNFREEZE THE * SCREEN. This will typically be done for
	 * you if you call * sendNewConfiguration(). * * The orientation is computed
	 * from non-application windows first. If none of * the non-application windows
	 * specify orientation, the orientation is computed from * application tokens.
	 * * @see android.view.IWindowManager#updateOrientationFromAppTokens( *
	 * android.os.IBinder)
	 */
	 boolean updateOrientationFromAppTokensLocked(boolean inTransaction) {
        long ident = Binder.clearCallingIdentity();
        try {
            int req = getOrientationFromWindowsLocked();//获取上次强制设置的方向,如果不同就调用updateRotationUncheckedLocked函数
            if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
                req = getOrientationFromAppTokensLocked();
            }

            if (req != mForcedAppOrientation) {
                mForcedAppOrientation = req;
                //send a message to Policy indicating orientation change to take
                //action like disabling/enabling sensors etc.,
                mPolicy.setCurrentOrientationLw(req);
                if (updateRotationUncheckedLocked(inTransaction)) {//核心函数!!!!!!最终会到DisplayManagerService中设置设备的方向
                    // changed
                    return true;
                }
            }

            return false;
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }

这里涉及到两个过程:

  代理对象建立:ActivityManagerProxy代理对象的创建;

  程序执行过程:如何通过代理对象来执行真正对象请求;

 

  从图中可以看出代理类:使用ActivityManagerProxy代理类,来代理ActivityManagerNative类的子类ActivityManagerService;

ActivityManagerService是系统统一的Service,运行在独立的进程中;通过系统ServiceManger获取;

  ActivityManager运行在一个进程里面,ActivityManagerService运行在另一个进程内,

对象在不同的进程里面,其地址是相互独立的;实现跨进程的对象访问,需要对应进程间通信的规则,

此处是采用Binder机制实现跨进程通信;所以此处的Proxy模式的运用属于:远程代理(RemoteProxy)

  下面看看这两个过程。

 

四 代理实现过程

1 代理对象建立

       是在ActivityManager的getRunningServices执行时就需要代理类来执行;

  public List<RunningServiceInfo> getRunningServices(int maxNum)

    returnActivityManagerNative.getDefault()

      getServices(maxNum, 0);

  }

  继续看看ActivityManagerNative.getDefault()到底干了什么事:

  实际上是关乎到Singleton<IActivityManager>类型的gDefault对象创建;

复制代码
private static final Singleton<IActivityManager> gDefault = new
       Singleton<IActivityManager>() {
      protected IActivityManager create() {
      IBinder b = ServiceManager.getService("activity");
      IActivityManager am = asInterface(b);
      return am;
  }
};
复制代码

  ServiceManager.getService("activity");获取系统的“activity”的Service, 

所有的Service都是注册到ServiceManager进行统一管理。

  这样就创建了一个对ActivityManagerService实例的本地代理对象ActivityManagerProxy实例。Singleton是通用的单例模板类。

      ActivityManagerNative.getDefault就返回一个此代理对象的公共接口IActivityManager类型,就可以在本地调用远程对象的操作方法。

      

2 执行过程

       这个执行过程就设计到ActivityManager框架的执行流程;简单看一下这个getServices的执行过程。

      

    

  此图表明整个Client对Service的访问是通过Service的代理对象Proxy进行访问的。

Android中对Service访问的模式都是以Client/Server模式进行;

Client实际上访问Service是通过对Service的建立代理的Proxy对象进行访问的——代理模式。

  此处也可以看到如果ActivityManager相关的Remote端的Service组件可以任意进行改变替换,依然不会影响到Local端的使用。

 

AcitivityManager的框架十分复杂,此处主要是为了学习Proxy模式的应用。

猜你喜欢

转载自blog.csdn.net/u010144805/article/details/79927461
今日推荐