关闭

在组件中获取服务对象的大致步骤

1159人阅读 评论(0) 收藏 举报
分类:

我们可以在Activity、Service中获取到服务的管理对象,从而可以让服务工作,完成客户端的请求。

在aidl文件编译生成的java文件中,有关服务管理对象(XXManager)、服务接口(IXXManager)、根(IXXManager.Stub)、服务(XXManagerService)、服务代理(IXXManager.Stub.Proxy)之间的大致类关系如图:

具体可以看下aidl文件编译后生成的Java文件。

现在,在Activity中通过获取PowerManager服务为例:

1、在Activity中通过:PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);获取电源服务管理对象。

对于PowerManager类中的构造:

    public PowerManager(Context context, IPowerManager service, Handler handler) {
        mContext = context;
        mService = service;
        mHandler = handler;
    }

其上的IPowerManager service参数给了 PowerManager中的成员变量mService,进而可以调用代理类中相应的方法,比如:

PowerManager中的方法,

    public boolean isScreenOn() {
        try {
            return mService.isScreenOn();
        } catch (RemoteException e) {
            return false;
        }
    }

2、进入Context类中,查看方法getSystemService的工作机制,此类中方法为:

public abstract Object getSystemService(String name);

3、上面方法是抽象的,看其实现类ContextImpl:

@Override
public Object getSystemService(String name) {
ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);

return fetcher == null ? null : fetcher.getService(this);
}

说明:

//以String为key,ServiceFetcher为value

private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP = new HashMap<String, ServiceFetcher>();

添加元素到的操作在方法:

private static void registerService(String serviceName,
ServiceFetcher fetcher) {
if (!(fetcher instanceof StaticServiceFetcher)) {
fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
}
SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
}

而实际上,调用这个发给方法的实在ContextImpl中的一个静态代码块中:

static {

................

registerService(POWER_SERVICE, new ServiceFetcher() {

public Object createService(ContextImpl ctx) {

IBinder b = ServiceManager.getService(POWER_SERVICE);
IPowerManager service = IPowerManager.Stub.asInterface(b);
return new PowerManager(ctx.getOuterContext(), service,
ctx.mMainThread.getHandler());
}
});

................

}

通过静态代码块调用的方法,将相应的服务管理对象添加到了SYSTEM_SERVICE_MAP中。

4、对于静态代码块中的一个内部方法等下再看,回到getSystemService方法中的return fetcher == null ? null : fetcher.getService(this);

看下ServiceFetcher,源码如下:

/**
* Override this class when the system service constructor needs a
* ContextImpl. Else, use StaticServiceFetcher below.
*/
/* package */static class ServiceFetcher {
int mContextCacheIndex = -1;


/**
* Main entrypoint; only override if you don't need caching.
*/
public Object getService(ContextImpl ctx) {
ArrayList<Object> cache = ctx.mServiceCache;
Object service;
synchronized (cache) {
if (cache.size() == 0) {
// Initialize the cache vector on first access.
// At this point sNextPerContextServiceCacheIndex
// is the number of potential services that are
// cached per-Context.
for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) {
cache.add(null);
}
} else {
service = cache.get(mContextCacheIndex);
if (service != null) {
return service;
}
}
service = createService(ctx);
cache.set(mContextCacheIndex, service);
return service;
}
}


/**
* Override this to create a new per-Context instance of the service.
* getService() will handle locking and caching.
*/
public Object createService(ContextImpl ctx) {
throw new RuntimeException("Not implemented");
}
}


/**
* Override this class for services to be cached process-wide.
*/
abstract static class StaticServiceFetcher extends ServiceFetcher {
private Object mCachedInstance;


@Override
public final Object getService(ContextImpl unused) {
synchronized (StaticServiceFetcher.this) {
Object service = mCachedInstance;
if (service != null) {
return service;
}
return mCachedInstance = createStaticService();
}
}


public abstract Object createStaticService();
}

上面的代码中可以通过getService调用createService方法,分别从集合HashMap中取得的ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);会调用静态代码中相应的方法,虽然在return fetcher == null ? null : fetcher.getService(this);只是调用了getService方法,但是前面代码也可一知道。

5、回到静态代码中的内部方法:

// Note: this was previously cached in a static variable, but
// constructed using mMainThread.getHandler(), so converting
// it to be a regular Context-cached service...
//##########################
registerService(POWER_SERVICE, new ServiceFetcher() {

public Object createService(ContextImpl ctx) {

IBinder b = ServiceManager.getService(POWER_SERVICE);
IPowerManager service = IPowerManager.Stub.asInterface(b);
return new PowerManager(ctx.getOuterContext(), service,
ctx.mMainThread.getHandler());
}
});

获取一个电源管理,并且最终返回给我们初始调用的方法getSystemService。

6、内部方法方法体:

IBinder b = ServiceManager.getService(POWER_SERVICE);
IPowerManager service = IPowerManager.Stub.asInterface(b);
return new PowerManager(ctx.getOuterContext(), service,
ctx.mMainThread.getHandler());

第一行:IBinder b = ServiceManager.getService(POWER_SERVICE);从ServiceManager服务注册管理类中取出PowerManagerService对象,可以看下是怎么添加上去的,见下面代码。

其实在SystemServer中:

power = new PowerManagerService();
ServiceManager.addService(Context.POWER_SERVICE, power);

第二行:IPowerManager service = IPowerManager.Stub.asInterface(b);获取代理对象。

调用的是IPowerManager.Stub.asInterface(b)方法,看下AIDL文件编译生成的java文件,就会知道。

这是个例子代码:

public static com.example.testactivitystart.HH asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.testactivitystart.HH))) {
return ((com.example.testactivitystart.HH)iin);
}
return new com.example.testactivitystart.HH.Stub.Proxy(obj);
}

最终通过return new com.example.testactivitystart.HH.Stub.Proxy(obj);获取该服务相对应的服务代理对象。

第三行:return new PowerManager(ctx.getOuterContext(), service,ctx.mMainThread.getHandler());

回到PowerManager类中的构造方法,

    /**
     * {@hide}
     */
    public PowerManager(Context context, IPowerManager service, Handler handler) {
        mContext = context;
        mService = service;
        mHandler = handler;
    }

 mService = service;电源服务代理对象给了电源管理中的成员变量mService。

=============================================================================================

Activity:

PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);

pm.isScreenOn();

===================================================================================================

客户段通过电源管理pm.isScreenOn()方法,

    public boolean isScreenOn() {
        try {
            return mService.isScreenOn();
        } catch (RemoteException e) {
            return false;
        }
    }

继而,调用电源服务代理中的isScreenOn()方法。

最后,调用电源服务中的方法isScreenOn()。他们之间的联系通过Binder机制实现。







0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:183656次
    • 积分:2630
    • 等级:
    • 排名:第13944名
    • 原创:94篇
    • 转载:60篇
    • 译文:3篇
    • 评论:18条
    最新评论