private static <Result> CompletionStage<Result> shuttle(final Context context, final ShuttleMethod lambda) {
		final Class<?> clazz = lambda.getClass();
		final Constructor<?>[] constructors = clazz.getDeclaredConstructors();
		if (constructors.length < 1) throw new IllegalArgumentException("The method must have at least one constructor");
		final Constructor<?> constructor = constructors[0];		// Extra constructor may be generated by "Instant Run" of Android Studio.
		final Class<?>[] constructor_params = constructor.getParameterTypes();

		final Field[] fields = clazz.getDeclaredFields();
		final Object[] args;
		if (constructor_params.length > 0) {
			if (fields.length < constructor_params.length)		// Extra fields may be added by dev tools (e.g. instant-run).
				throw new IllegalArgumentException("Parameter types mismatch: " + constructor + " / " + Arrays.deepToString(fields));

			args = new Object[constructor_params.length];
			for (int i = 0; i < constructor_params.length; i++) try {
				final Field field = fields[i];
				if (field.getType() != constructor_params[i])
					throw new IllegalArgumentException("Parameter types mismatch: " + constructor + " / " + Arrays.deepToString(fields));
				field.setAccessible(true);
				final Object arg = field.get(lambda);
				if (field.getType() != Context.class) args[i] = arg;		// Context argument is intentionally left blank.
			} catch (final Exception e) {
				throw new IllegalArgumentException("Error enumerating lambda parameters.", e);
			}
		} else args = new Object[0];

		final MethodInvocation<Result> invocation = new MethodInvocation<>();
		invocation.clazz = clazz.getName();
		invocation.args = args;
		final CompletableFuture<Result> future = new CompletableFuture<>();
		final Services.ServiceReadyThrows<IMethodShuttle, DeadObjectException> procedure = shuttle -> {
			sCachedShuttle = shuttle;
			try {
				shuttle.invoke(invocation);
			} catch (final DeadObjectException e) {
				throw e;		// Required by sCachedShuttle to identify dead binder (isBinderAlive() is not reliable)
			} catch (final Exception e) {
				Log.w(TAG, "Error executing " + invocation.clazz, e);
				future.completeExceptionally(e);
				return;
			}
			if (invocation.throwable != null) future.completeExceptionally(invocation.throwable);
			else future.complete(invocation.result);
		};

		if (sCachedShuttle != null && sCachedShuttle.asBinder().isBinderAlive()) try {
			procedure.onServiceReady(sCachedShuttle);
			return future;
		} catch (final DeadObjectException ignored) {}    // Fall-through to reconnect

		if (Services.use(new ServiceShuttleContext(context), IMethodShuttle.class, IMethodShuttle.Stub::asInterface, procedure)) return future;
		final CompletableFuture<Result> failure = new CompletableFuture<>();
		failure.completeExceptionally(new IllegalStateException("Error connecting " + MethodShuttleService.class.getCanonicalName()));
		return failure;
	}
@param lambda should be a lambda function with return value of type <code>R</code>.
               Context (but not its derivation) and types acceptable by {@link Parcel#writeValue(Object)} can be carried.
shared/src/main/java/com/oasisfeng/island/shuttle/MethodShuttle.java