Android 11 bindService 流程分析

我们可以使用bindService来跨进程通信,其使用方法如下

c 复制代码
Intent intent = new Intent("xxx");
intent.setPackage("xxx");
boolean result = bindService(intent,new ServiceConn(),BIND_AUTO_CREATE);

private class ServiceConn implements ServiceConnection{

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
           
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
}

服务绑定成功后,会回调onServiceConnected方法,然后我们就可以利用返回的IBinder 对象,和服务端通信了。本文来分析下bindService的内部实现。

c 复制代码
 @Override
public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
	return mBase.bindService(service, conn, flags);
}

这里的mBase是一个ContextImpl对象,接着来看ContextImpl的bindService方法

c 复制代码
@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
        warnIfCallingFromSystemProcess();
	return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,
                getUser());
}

继续调用ContextImpl的bindServiceCommon方法

c 复制代码
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
            String instanceName, Handler handler, Executor executor, UserHandle user) {
        // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
        IServiceConnection sd;
        //省略
        if (mPackageInfo != null) {
            if (executor != null) {
                sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
            } else {
                sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);//1
            }
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        validateServiceIntent(service);
        try {
            //省略
            int res = ActivityManager.getService().bindIsolatedService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, instanceName, getOpPackageName(), user.getIdentifier());//2
            //省略
            return res != 0;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

注释1处将我们传进来的ServiceConnection 对象封装成可以跨进程通信的IServiceConnection对象。注释2处是跨进程调用,调用到AMS的bindIsolatedService方法

先来看一下注释1处是如何将我们的ServiceConnection 对象封装成IServiceConnection对象的,mPackageInfo是一个LoadedApk对象getServiceDispatcher最后会调用其getServiceDispatcherCommon方法

c 复制代码
private IServiceConnection getServiceDispatcherCommon(ServiceConnection c,
            Context context, Handler handler, Executor executor, int flags) {
        synchronized (mServices) {
            LoadedApk.ServiceDispatcher sd = null;
            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
            if (map != null) {
                if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);
                sd = map.get(c);
            }
            if (sd == null) {
                if (executor != null) {
                    sd = new ServiceDispatcher(c, context, executor, flags);
                } else {
                    sd = new ServiceDispatcher(c, context, handler, flags);//1
                }
     
                if (map == null) {
                    map = new ArrayMap<>();
                    mServices.put(context, map);
                }
                map.put(c, sd);
            } else {
                sd.validate(context, handler, executor);
            }
            return sd.getIServiceConnection();//2
        }
    }

注释1处创建一个ServiceDispatcher对象,注意第一个参数为我们传入的ServiceConnection 对象。注释2处调用ServiceDispatcher的getIServiceConnection方法然后返回

c 复制代码
//getIServiceConnection
@UnsupportedAppUsage
IServiceConnection getIServiceConnection() {
     return mIServiceConnection;
}

ServiceDispatcher(ServiceConnection conn,Context context, Handler activityThread, int flags) {
            mIServiceConnection = new InnerConnection(this);
            mConnection = conn;
            mContext = context;
            mActivityThread = activityThread;
            mActivityExecutor = null;
            mLocation = new ServiceConnectionLeaked(null);
            mLocation.fillInStackTrace();
            mFlags = flags;
}

//
private static class InnerConnection extends IServiceConnection.Stub {
            @UnsupportedAppUsage
            final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;

            InnerConnection(LoadedApk.ServiceDispatcher sd) {
                mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}

可以看出getIServiceConnection返回的是一个 InnerConnection对象。InnerConnection继承自IServiceConnection.Stub类,是跨进程通信的Bn端。InnerConnection对象中的mDispatcher 指向的是 ServiceDispatcher对象,而ServiceDispatcher对象的mConnection 成员为我们传进来的IServiceConnection对象。

接着来看AMS的bindIsolatedService方法(实际上是通过跨进程调用,调用到AMS里面的,具体的跨进程调用过程本文不详细分析,直接看AMS里面对应的方法)

c 复制代码
public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, IServiceConnection connection, int flags, String instanceName,
            String callingPackage, int userId) throws TransactionTooLargeException {
        //省略

        synchronized(this) {
            return mServices.bindServiceLocked(caller, token, service,
                    resolvedType, connection, flags, instanceName, callingPackage, userId);
        }
    }

mServices是ActiveServices对象,接着来看ActiveServices的bindServiceLocked方法

c 复制代码
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String instanceName, String callingPackage, final int userId)
            throws TransactionTooLargeException {
       //省略
       if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                s.lastActivity = SystemClock.uptimeMillis();
                if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                        permissionsReviewRequired) != null) {//1
                    return 0;
                }
       }
		
	//省略

	if (s.app != null && b.intent.received) {
		//省略
	}else if (!b.intent.requested) {
		requestServiceBindingLocked(s, b.intent, callerFg, false);//2
	}
		
	//省略

bindServiceLocked方法比较长,省略了大部分代码,主要是执行以下两个方法

  1. bringUpServiceLocked
  2. requestServiceBindingLocked

接下来分开来看一下这两个方法都干了什么事情

bringUpServiceLocked

c 复制代码
 private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
	//省略
	if (!isolated) {
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
                    realStartServiceLocked(r, app, execInFg);//1
                    return null;
                } catch (TransactionTooLargeException e) {
                    throw e;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting service " + r.shortInstanceName, e);
                }

                // If a dead object exception was thrown -- fall through to
                // restart the application.
            }
        } else {
			//省略
		}
	if (app == null && !permissionsReviewRequired) {
            // TODO (chriswailes): Change the Zygote policy flags based on if the launch-for-service
            //  was initiated from a notification tap or not.
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,//2
                    hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated, false)) == null) {
                bringDownServiceLocked(r);
                return msg;
            }
            if (isolated) {
                r.isolatedProc = app;
            }
    }
	//省略
}

注释1处调用realStartServiceLocked来启动服务。注释2处如果要启动的服务的进程不存在,则需要先创建进程。我们假设进程已经存在,重点来看realStartServiceLocked方法

c 复制代码
private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
	//省略
	app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                    app.getReportedProcState());
	//省略
}

这里又是一个跨进程通讯,调用服务端的scheduleCreateService方法

c 复制代码
public final void scheduleCreateService(IBinder token,
                ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
            updateProcessState(processState, false);
            CreateServiceData s = new CreateServiceData();
            s.token = token;
            s.info = info;
            s.compatInfo = compatInfo;

            sendMessage(H.CREATE_SERVICE, s);
 }

对于CREATE_SERVICE消息,最终调用到handleCreateService方法

c 复制代码
private void handleCreateService(CreateServiceData data) {
       //省略
        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);

            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);//创建context
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = packageInfo.getAppFactory()
                    .instantiateService(cl, data.info.name, data.intent);
            // Service resources must be initialized with the same loaders as the application
            // context.
            context.getResources().addLoaders(
                    app.getResources().getLoaders().toArray(new ResourcesLoader[0]));

            context.setOuterContext(service);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            service.onCreate();//1
            mServices.put(data.token, service);
           //省略
    }

注释1处Service的onCreate方法就会被执行。

requestServiceBindingLocked

c 复制代码
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {
       //省略
        if ((!i.requested || rebind) && i.apps.size() > 0) {
            try {
                bumpServiceExecutingLocked(r, execInFg, "bind");
                r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.getReportedProcState());//1
               
            } catch (TransactionTooLargeException e) {
                
            } catch (RemoteException e) {
               
            }
        }
        return true;
    }

注释1处又是一个跨进程调用,调用服务端的scheduleBindService方法

c 复制代码
public final void scheduleBindService(IBinder token, Intent intent,
                boolean rebind, int processState) {
           //省略
            sendMessage(H.BIND_SERVICE, s);
}

对于BIND_SERVICE消息,调用handleBindService方法

c 复制代码
private void handleBindService(BindServiceData data) {
        Service s = mServices.get(data.token);
        if (DEBUG_SERVICE)
            Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
        if (s != null) {
            try {
                data.intent.setExtrasClassLoader(s.getClassLoader());
                data.intent.prepareToEnterProcess();
                try {
                    if (!data.rebind) {
                        IBinder binder = s.onBind(data.intent);//1
                        ActivityManager.getService().publishService(
                                data.token, data.intent, binder);//2
                    } else {
                        s.onRebind(data.intent);
                        ActivityManager.getService().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(s, e)) {
                    throw new RuntimeException(
                            "Unable to bind to service " + s
                            + " with " + data.intent + ": " + e.toString(), e);
                }
            }
        }
    }

注释1处会导致Service的onBind方法被调用,onBind方法中返回一个IBinder 对象。重点来看注释2处的publishService的方法干了什么事情。publishService方法也是一个跨进程调用,又调用到AMS的publishService方法

c 复制代码
public void publishService(IBinder token, Intent intent, IBinder service) {
        // Refuse possible leaked file descriptors
        if (intent != null && intent.hasFileDescriptors() == true) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }

        synchronized(this) {
            if (!(token instanceof ServiceRecord)) {
                throw new IllegalArgumentException("Invalid service token");
            }
            mServices.publishServiceLocked((ServiceRecord)token, intent, service);//1
        }
    }

注释1处继续调用ActiveServices的publishServiceLocked方法

c 复制代码
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {

	try {
     
            if (r != null) {
                Intent.FilterComparison filter
                        = new Intent.FilterComparison(intent);
                IntentBindRecord b = r.bindings.get(filter);
                if (b != null && !b.received) {
                    b.binder = service;
                    b.requested = true;
                    b.received = true;
                    ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
                    for (int conni = connections.size() - 1; conni >= 0; conni--) {
                        ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
                        for (int i=0; i<clist.size(); i++) {
                            ConnectionRecord c = clist.get(i);
                            if (!filter.equals(c.binding.intent.intent)) {
  
                                continue;
                            }
                            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
                            try {
                                c.conn.connected(r.name, service, false);//1
                            } catch (Exception e) {
                                Slog.w(TAG, "Failure sending service " + r.shortInstanceName
                         //省略

注释1处c.conn就是之前我们封装成的InnerConnection 对象,这里调用其connected方法,注意这里也是一个跨进程调用

c 复制代码
private static class InnerConnection extends IServiceConnection.Stub {
         
	final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
	
	public void connected(ComponentName name, IBinder service, boolean dead)
                    throws RemoteException {
		LoadedApk.ServiceDispatcher sd = mDispatcher.get();
		if (sd != null) {
			sd.connected(name, service, dead);
		}
	}
}

继续调用ServiceDispatcher 的connected方法

c 复制代码
public void connected(ComponentName name, IBinder service, boolean dead) {
	if (mActivityExecutor != null) {
		mActivityExecutor.execute(new RunConnection(name, service, 0, dead));
	} else if (mActivityThread != null) {
		mActivityThread.post(new RunConnection(name, service, 0, dead));
	} else {
		doConnected(name, service, dead);//1
	}
}

注释1处调用doConnected

c 复制代码
public void doConnected(ComponentName name, IBinder service, boolean dead) {
            ServiceDispatcher.ConnectionInfo old;
            ServiceDispatcher.ConnectionInfo info;

	//省略
	// If there is a new viable service, it is now connected.
	if (service != null) {
		mConnection.onServiceConnected(name, service);
	} else {
		// The binding machinery worked, but the remote returned null from onBind().
		mConnection.onNullBinding(name);
	}
		

可以看出,这里就调用了mConnection的onServiceConnected方法,而这个mConnection就是之前我们封装是传入的ServiceConnection对象。我们传入的ServiceConnection的onServiceConnected就被调用了。

总结

bindService流程图如下

相关推荐
Dnelic-2 小时前
【单元测试】【Android】JUnit 4 和 JUnit 5 的差异记录
android·junit·单元测试·android studio·自学笔记
Eastsea.Chen5 小时前
MTK Android12 user版本MtkLogger
android·framework
长亭外的少年12 小时前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin
建群新人小猿14 小时前
会员等级经验问题
android·开发语言·前端·javascript·php
1024小神15 小时前
tauri2.0版本开发苹果ios和安卓android应用,环境搭建和最后编译为apk
android·ios·tauri
兰琛16 小时前
20241121 android中树结构列表(使用recyclerView实现)
android·gitee
Y多了个想法16 小时前
RK3568 android11 适配敦泰触摸屏 FocalTech-ft5526
android·rk3568·触摸屏·tp·敦泰·focaltech·ft5526
NotesChapter17 小时前
Android吸顶效果,并有着ViewPager左右切换
android
_祝你今天愉快18 小时前
分析android :The binary version of its metadata is 1.8.0, expected version is 1.5.
android
暮志未晚Webgl19 小时前
109. UE5 GAS RPG 实现检查点的存档功能
android·java·ue5