Bug 1566583 - Bridge GeckoResult to MozPromise and return a GeckoResult from GeckoProcessManager::start. r=snorp

Differential Revision: https://phabricator.services.mozilla.com/D38436

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Bobby Holley 2019-07-24 19:19:40 +00:00
Родитель c92332afaf
Коммит 53719788a1
7 изменённых файлов: 131 добавлений и 19 удалений

Просмотреть файл

@ -265,10 +265,9 @@ class AndroidProcessLauncher : public PosixProcessLauncher {
protected:
virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
void LaunchAndroidService(
RefPtr<ProcessHandlePromise> LaunchAndroidService(
const char* type, const std::vector<std::string>& argv,
const base::file_handle_mapping_vector& fds_to_remap,
base::ProcessHandle* process_handle);
const base::file_handle_mapping_vector& fds_to_remap);
};
typedef AndroidProcessLauncher ProcessLauncher;
// NB: Technically Android is linux (i.e. XP_LINUX is defined), but we want
@ -1136,12 +1135,8 @@ bool PosixProcessLauncher::DoSetup() {
#if defined(MOZ_WIDGET_ANDROID)
RefPtr<ProcessHandlePromise> AndroidProcessLauncher::DoLaunch() {
ProcessHandle handle = 0;
LaunchAndroidService(ChildProcessType(), mChildArgv,
mLaunchOptions->fds_to_remap, &handle);
return handle != 0
? ProcessHandlePromise::CreateAndResolve(handle, __func__)
: ProcessHandlePromise::CreateAndReject(LaunchError{}, __func__);
return LaunchAndroidService(ChildProcessType(), mChildArgv,
mLaunchOptions->fds_to_remap);
}
#endif // MOZ_WIDGET_ANDROID
@ -1553,10 +1548,9 @@ void GeckoChildProcessHost::GetQueuedMessages(std::queue<IPC::Message>& queue) {
}
#ifdef MOZ_WIDGET_ANDROID
void AndroidProcessLauncher::LaunchAndroidService(
RefPtr<ProcessHandlePromise> AndroidProcessLauncher::LaunchAndroidService(
const char* type, const std::vector<std::string>& argv,
const base::file_handle_mapping_vector& fds_to_remap,
base::ProcessHandle* process_handle) {
const base::file_handle_mapping_vector& fds_to_remap) {
MOZ_RELEASE_ASSERT((2 <= fds_to_remap.size()) && (fds_to_remap.size() <= 5));
JNIEnv* const env = mozilla::jni::GetEnvForThread();
MOZ_ASSERT(env);
@ -1586,12 +1580,10 @@ void AndroidProcessLauncher::LaunchAndroidService(
crashAnnotationFd = fds_to_remap[4].first;
}
int32_t handle = java::GeckoProcessManager::Start(
auto genericResult = java::GeckoProcessManager::Start(
type, jargs, prefsFd, prefMapFd, ipcFd, crashFd, crashAnnotationFd);
if (process_handle) {
*process_handle = handle;
}
auto typedResult = java::GeckoResult::LocalRef(std::move(genericResult));
return ProcessHandlePromise::FromGeckoResult(typedResult);
}
#endif

Просмотреть файл

@ -11,6 +11,8 @@ import org.mozilla.gecko.IGeckoEditableParent;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.geckoview.GeckoResult;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@ -207,11 +209,18 @@ public final class GeckoProcessManager extends IProcessManager.Stub {
}
@WrapForJNI
private static int start(final String type, final String[] args,
private static GeckoResult<Integer> start(final String type, final String[] args,
final int prefsFd, final int prefMapFd,
final int ipcFd,
final int crashFd, final int crashAnnotationFd) {
return INSTANCE.start(type, args, prefsFd, prefMapFd, ipcFd, crashFd, crashAnnotationFd, /* retry */ false);
int pid = INSTANCE.start(type, args, prefsFd, prefMapFd, ipcFd, crashFd, crashAnnotationFd, /* retry */ false);
GeckoResult<Integer> result = new GeckoResult<>();
if (pid == 0) {
result.completeExceptionally(new RuntimeException("Failed to start process"));
} else {
result.complete(pid);
}
return result;
}
private int filterFlagsForChild(final int flags) {

Просмотреть файл

@ -1,6 +1,7 @@
package org.mozilla.geckoview;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.mozglue.JNIObject;
import org.mozilla.gecko.util.ThreadUtils;
import android.os.Handler;
@ -463,6 +464,25 @@ public class GeckoResult<T> {
}
}
@WrapForJNI
public void nativeThen(final GeckoCallback accept, final GeckoCallback reject) {
// NB: We could use the lambda syntax here, but given all the layers
// of abstraction it's helpful to see the types written explicitly.
thenInternal(DirectDispatcher.sInstance, new OnValueListener<T, Void>() {
@Override
public GeckoResult<Void> onValue(final T value) {
accept.call(value);
return null;
}
}, new OnExceptionListener<Void>() {
@Override
public GeckoResult<Void> onException(final Throwable exception) {
reject.call(exception);
return null;
}
});
}
/**
* @return Get the {@link Looper} that will be used to schedule listeners registered via
* {@link #then(OnValueListener, OnExceptionListener)}.
@ -683,6 +703,15 @@ public class GeckoResult<T> {
@Nullable GeckoResult<V> onException(@NonNull Throwable exception) throws Throwable;
}
@WrapForJNI
private static class GeckoCallback extends JNIObject {
private native void call(Object arg);
@Override
protected native void disposeNative();
}
private boolean haveValue() {
return mComplete && mError == null;
}

Просмотреть файл

@ -7,6 +7,8 @@
#include "Conversions.h"
#include "JavaBuiltins.h"
#include "mozilla/ipc/GeckoChildProcessHost.h"
namespace mozilla {
namespace jni {
@ -87,5 +89,10 @@ double Java2Native(mozilla::jni::Object::Param aData, JNIEnv* aEnv) {
return result;
}
template <>
ipc::LaunchError Java2Native(mozilla::jni::Object::Param aData, JNIEnv* aEnv) {
return ipc::LaunchError{};
}
} // namespace jni
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,55 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_jni_GeckoResultUtils_h
#define mozilla_jni_GeckoResultUtils_h
#include "mozilla/jni/Conversions.h"
#include "GeneratedJNIWrappers.h"
#include "GeneratedJNINatives.h"
namespace mozilla {
namespace jni {
// C++-side object bound to Java's GeckoResult.GeckoCallback.
//
// Note that we can't template this class because that breaks JNI dispatch
// (surprisingly: it compiles, but selects the wrong method specialization
// during dispatch). So instead we use a templated factory function, which
// bundles the per-ArgType conversion logic into the callback.
class GeckoResultCallback final
: public java::GeckoResult::GeckoCallback::Natives<GeckoResultCallback> {
public:
typedef java::GeckoResult::GeckoCallback::Natives<GeckoResultCallback> Base;
typedef std::function<void(mozilla::jni::Object::Param)> OuterCallback;
void Call(mozilla::jni::Object::Param aArg) { mCallback(aArg); }
template <typename ArgType>
static java::GeckoResult::GeckoCallback::LocalRef CreateAndAttach(
std::function<void(ArgType)>&& aInnerCallback) {
auto java = java::GeckoResult::GeckoCallback::New();
OuterCallback outerCallback =
[inner{std::move(aInnerCallback)}](mozilla::jni::Object::Param aParam) {
ArgType converted = Java2Native<ArgType>(aParam);
inner(converted);
};
auto native = MakeUnique<GeckoResultCallback>(std::move(outerCallback));
Base::AttachNative(java, std::move(native));
return java;
}
explicit GeckoResultCallback(OuterCallback&& aCallback)
: mCallback(std::move(aCallback)) {}
private:
OuterCallback mCallback;
};
} // namespace jni
} // namespace mozilla
#endif // mozilla_jni_GeckoResultUtils_h

Просмотреть файл

@ -11,6 +11,7 @@ EXPORTS.mozilla.jni += [
'Accessors.h',
'Conversions.h',
'GeckoBundleUtils.h',
'GeckoResultUtils.h',
'Natives.h',
'Refs.h',
'Types.h',

Просмотреть файл

@ -20,6 +20,10 @@
# include "nsTArray.h"
# include "nsThreadUtils.h"
# ifdef MOZ_WIDGET_ANDROID
# include "mozilla/jni/GeckoResultUtils.h"
# endif
# if MOZ_DIAGNOSTIC_ASSERT_ENABLED
# define PROMISE_DEBUG
# endif
@ -934,6 +938,21 @@ class MozPromise : public MozPromiseBase {
}
}
# ifdef MOZ_WIDGET_ANDROID
// Creates a C++ MozPromise from its Java counterpart, GeckoResult.
static RefPtr<MozPromise> FromGeckoResult(
java::GeckoResult::Param aGeckoResult) {
using jni::GeckoResultCallback;
RefPtr<Private> p = new Private("GeckoResult Glue", false);
auto resolve = GeckoResultCallback::CreateAndAttach<ResolveValueType>(
[p](ResolveValueType aArg) { p->Resolve(aArg, __func__); });
auto reject = GeckoResultCallback::CreateAndAttach<RejectValueType>(
[p](RejectValueType aArg) { p->Reject(aArg, __func__); });
aGeckoResult->NativeThen(resolve, reject);
return p;
}
# endif
// Note we expose the function AssertIsDead() instead of IsDead() since
// checking IsDead() is a data race in the situation where the request is not
// dead. Therefore we enforce the form |Assert(IsDead())| by exposing