#ifndef ANDROID_WEBVIEW_JS_SANDBOX_SERVICE_JS_SANDBOX_ISOLATE_H_
#define ANDROID_WEBVIEW_JS_SANDBOX_SERVICE_JS_SANDBOX_ISOLATE_H_
#include <memory>
#include <set>
#include <string>
#include <unordered_map>
#include "android_webview/js_sandbox/service/js_sandbox_message_port.h"
#include "base/android/scoped_java_ref.h"
#include "base/compiler_specific.h"
#include "base/containers/flat_map.h"
#include "base/files/scoped_file.h"
#include "base/functional/callback_forward.h"
#include "base/memory/scoped_refptr.h"
#include "base/synchronization/lock.h"
#include "base/thread_annotations.h"
#include "v8/include/cppgc/persistent.h"
#include "v8/include/v8-array-buffer.h"
#include "v8/include/v8-inspector.h"
#include "v8/include/v8-promise.h"
namespace base {
class CancelableTaskTracker;
class SequencedTaskRunner;
class SingleThreadTaskRunner;
}
namespace gin {
class Arguments;
class IsolateHolder;
class ContextHolder;
}
namespace v8 {
class ObjectTemplate;
}
namespace android_webview {
class FdWithLength;
class JsSandboxArrayBufferAllocator;
class JsSandboxIsolateCallback;
class JsSandboxMessagePort;
class JsSandboxIsolate {
public:
explicit JsSandboxIsolate(
const base::android::JavaParamRef<jobject>& j_isolate_,
size_t max_heap_size_bytes);
~JsSandboxIsolate();
jboolean EvaluateJavascript(
JNIEnv* env,
const base::android::JavaParamRef<jstring>& jcode,
const base::android::JavaParamRef<jobject>& j_callback);
jboolean EvaluateJavascriptWithFd(
JNIEnv* env,
const jint fd,
const jlong length,
const jlong offset,
const base::android::JavaParamRef<jobject>& j_callback,
const base::android::JavaParamRef<jobject>& pfd);
void DestroyNative(JNIEnv* env);
jboolean ProvideNamedData(JNIEnv* env,
const base::android::JavaParamRef<jstring>& jname,
const jint fd,
const jint length);
void SetConsoleEnabled(JNIEnv* env,
jboolean enable);
void ProvideMessagePort(
JNIEnv* env,
std::string name,
const base::android::JavaParamRef<jobject>& j_message_port);
gin::ContextHolder* GetContextHolder();
v8::Isolate* GetIsolate();
scoped_refptr<base::SingleThreadTaskRunner> GetIsolateTaskRunner();
private:
class InspectorClient;
void DeleteSelf();
void InitializeIsolateOnThread();
void EvaluateJavascriptOnThread(
std::string code,
scoped_refptr<JsSandboxIsolateCallback> callback);
void PromiseFulfillCallback(scoped_refptr<JsSandboxIsolateCallback> callback,
gin::Arguments* args);
void PromiseRejectCallback(scoped_refptr<JsSandboxIsolateCallback> callback,
gin::Arguments* args);
void TerminateAndDestroy();
void DestroyWhenPossible();
void NotifyInitComplete();
void CreateCancelableTaskTracker();
void PostEvaluationToIsolateThread(
std::string code,
scoped_refptr<JsSandboxIsolateCallback> callback);
void PostFileDescriptorReadToIsolateThread(
int fd,
int64_t length,
int64_t offset,
base::android::ScopedJavaGlobalRef<jobject> pfd,
scoped_refptr<JsSandboxIsolateCallback> callback);
void ReadFileDescriptorOnThread(
int fd,
int64_t length,
int64_t offset,
base::android::ScopedJavaGlobalRef<jobject> pfd,
scoped_refptr<JsSandboxIsolateCallback> callback);
void ReportFileDescriptorIOError(
base::android::ScopedJavaGlobalRef<jobject> pfd,
scoped_refptr<JsSandboxIsolateCallback> callback,
std::string errorMessage);
void ConvertPromiseToArrayBufferInThreadPool(
base::ScopedFD fd,
ssize_t length,
std::string name,
std::unique_ptr<v8::Global<v8::ArrayBuffer>> array_buffer,
std::unique_ptr<v8::Global<v8::Promise::Resolver>> resolver,
void* inner_buffer);
void ConvertPromiseToArrayBufferInControlSequence(
std::string name,
std::unique_ptr<v8::Global<v8::ArrayBuffer>> array_buffer,
std::unique_ptr<v8::Global<v8::Promise::Resolver>> resolver);
void ConvertPromiseToFailureInControlSequence(
std::string name,
std::unique_ptr<v8::Global<v8::ArrayBuffer>> array_buffer,
std::unique_ptr<v8::Global<v8::Promise::Resolver>> resolver,
std::string reason);
void ConvertPromiseToFailureInIsolateSequence(
std::string name,
std::unique_ptr<v8::Global<v8::ArrayBuffer>> array_buffer,
std::unique_ptr<v8::Global<v8::Promise::Resolver>> resolver,
std::string reason);
void ConvertPromiseToArrayBufferInIsolateSequence(
std::string name,
std::unique_ptr<v8::Global<v8::ArrayBuffer>> array_buffer,
std::unique_ptr<v8::Global<v8::Promise::Resolver>> resolver);
void ConsumeNamedDataAsArrayBuffer(gin::Arguments* args);
void GetNamedPort(gin::Arguments* args);
v8::Local<v8::ObjectTemplate> CreateAndroidNamespaceTemplate(
v8::Isolate* isolate);
[[noreturn]] static void OOMErrorCallback(const char* location,
const v8::OOMDetails& details,
void* data);
v8::MaybeLocal<v8::ArrayBuffer> tryAllocateArrayBuffer(size_t length);
[[noreturn]] void MemoryLimitExceeded();
void ReportOutOfMemory();
[[noreturn]] void FreezeThread();
void EnableOrDisableInspectorAsNeeded();
void SetConsoleEnabledOnControlThread(bool enable);
void SetConsoleEnabledOnIsolateThread(bool enable);
void ProvideMessagePortOnIsolateThread(
std::string name,
const base::android::ScopedJavaGlobalRef<jobject> j_message_port);
const scoped_refptr<JsSandboxIsolateCallback>& UseCallback(
const scoped_refptr<JsSandboxIsolateCallback>& callback);
const base::android::ScopedJavaGlobalRef<jobject> j_isolate_;
const size_t isolate_max_heap_size_bytes_;
std::unique_ptr<JsSandboxArrayBufferAllocator> array_buffer_allocator_;
scoped_refptr<base::SequencedTaskRunner> control_task_runner_;
bool isolate_init_complete = false;
bool destroy_called_before_init = false;
std::unique_ptr<base::CancelableTaskTracker> cancelable_task_tracker_;
scoped_refptr<base::SingleThreadTaskRunner> isolate_task_runner_;
std::unique_ptr<gin::IsolateHolder> isolate_holder_;
std::unique_ptr<v8::Isolate::Scope> isolate_scope_;
std::unique_ptr<gin::ContextHolder> context_holder_;
base::Lock named_fd_lock_;
std::unordered_map<std::string, FdWithLength> named_fd_
GUARDED_BY(named_fd_lock_);
std::set<scoped_refptr<JsSandboxIsolateCallback>>
ongoing_evaluation_callbacks_;
bool console_enabled_;
base::flat_map<std::string, cppgc::Persistent<JsSandboxMessagePort>>
message_ports_;
base::flat_map<
std::string,
std::vector<std::unique_ptr<v8::Global<v8::Promise::Resolver>>>>
pending_port_requests_;
std::unique_ptr<v8_inspector::V8InspectorClient> inspector_client_;
std::unique_ptr<v8_inspector::V8Inspector> inspector_;
std::unique_ptr<v8_inspector::V8Inspector::Channel> inspector_channel_;
std::unique_ptr<v8_inspector::V8InspectorSession> inspector_session_;
};
}
#endif