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流程图如下

相关推荐
Devil枫25 分钟前
Kotlin高级特性深度解析
android·开发语言·kotlin
ChinaDragonDreamer27 分钟前
Kotlin:2.1.20 的新特性
android·开发语言·kotlin
雨白11 小时前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
kk爱闹13 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python
每次的天空14 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭15 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日16 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安16 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑16 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
还鮟20 小时前
CTF Web的数组巧用
android