blob: 56608c6d6a5ae351eca926f3e8ce08d3e65a14ce [file] [log] [blame]
// Copyright 2019 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "starboard/android/shared/platform_service.h"
#include <memory>
#include "starboard/android/shared/jni_env_ext.h"
#include "starboard/android/shared/jni_utils.h"
#include "starboard/common/log.h"
#include "starboard/common/string.h"
#include "starboard/extension/platform_service.h"
typedef struct CobaltExtensionPlatformServicePrivate {
void* context;
ReceiveMessageCallback receive_callback;
const char* name;
jobject cobalt_service;
~CobaltExtensionPlatformServicePrivate() {
if (name) {
delete name;
}
if (cobalt_service) {
starboard::android::shared::JniEnvExt::Get()->DeleteGlobalRef(
cobalt_service);
}
}
} CobaltExtensionPlatformServicePrivate;
namespace starboard {
namespace android {
namespace shared {
namespace {
using starboard::android::shared::JniEnvExt;
using starboard::android::shared::ScopedLocalJavaRef;
bool Has(const char* name) {
JniEnvExt* env = JniEnvExt::Get();
ScopedLocalJavaRef<jstring> j_name(env->NewStringStandardUTFOrAbort(name));
jboolean j_has = env->CallStarboardBooleanMethodOrAbort(
"hasCobaltService", "(Ljava/lang/String;)Z", j_name.Get());
return j_has;
}
CobaltExtensionPlatformService Open(void* context,
const char* name,
ReceiveMessageCallback receive_callback) {
SB_DCHECK(context);
JniEnvExt* env = JniEnvExt::Get();
if (!Has(name)) {
SB_LOG(ERROR) << "Can't open Service " << name;
return kCobaltExtensionPlatformServiceInvalid;
}
CobaltExtensionPlatformService service =
new CobaltExtensionPlatformServicePrivate(
{context, receive_callback, name});
ScopedLocalJavaRef<jstring> j_name(env->NewStringStandardUTFOrAbort(name));
jobject cobalt_service = env->CallStarboardObjectMethodOrAbort(
"openCobaltService",
"(JLjava/lang/String;)Ldev/cobalt/coat/CobaltService;",
reinterpret_cast<jlong>(service), j_name.Get());
if (!cobalt_service) {
delete static_cast<CobaltExtensionPlatformServicePrivate*>(service);
return kCobaltExtensionPlatformServiceInvalid;
}
service->cobalt_service = env->ConvertLocalRefToGlobalRef(cobalt_service);
return service;
}
void Close(CobaltExtensionPlatformService service) {
JniEnvExt* env = JniEnvExt::Get();
env->CallVoidMethodOrAbort(service->cobalt_service, "onClose", "()V");
ScopedLocalJavaRef<jstring> j_name(
env->NewStringStandardUTFOrAbort(service->name));
env->CallStarboardVoidMethodOrAbort("closeCobaltService",
"(Ljava/lang/String;)V", j_name.Get());
delete static_cast<CobaltExtensionPlatformServicePrivate*>(service);
}
void* Send(CobaltExtensionPlatformService service,
void* data,
uint64_t length,
uint64_t* output_length,
bool* invalid_state) {
SB_DCHECK(data);
SB_DCHECK(output_length);
SB_DCHECK(invalid_state);
JniEnvExt* env = JniEnvExt::Get();
ScopedLocalJavaRef<jbyteArray> data_byte_array;
data_byte_array.Reset(
env->NewByteArrayFromRaw(reinterpret_cast<const jbyte*>(data), length));
ScopedLocalJavaRef<jobject> j_response_from_client(
static_cast<jbyteArray>(env->CallObjectMethodOrAbort(
service->cobalt_service, "receiveFromClient",
"([B)Ldev/cobalt/coat/CobaltService$ResponseToClient;",
data_byte_array.Get())));
if (!j_response_from_client) {
*invalid_state = true;
*output_length = 0;
return 0;
}
*invalid_state = env->GetBooleanFieldOrAbort(j_response_from_client.Get(),
"invalidState", "Z");
ScopedLocalJavaRef<jbyteArray> j_out_data_array(static_cast<jbyteArray>(
env->GetObjectFieldOrAbort(j_response_from_client.Get(), "data", "[B")));
*output_length = env->GetArrayLength(j_out_data_array.Get());
char* output = new char[*output_length];
env->GetByteArrayRegion(j_out_data_array.Get(), 0, *output_length,
reinterpret_cast<jbyte*>(output));
return output;
}
const CobaltExtensionPlatformServiceApi kPlatformServiceApi = {
kCobaltExtensionPlatformServiceName,
1, // API version that's implemented.
&Has,
&Open,
&Close,
&Send};
} // namespace
extern "C" SB_EXPORT_PLATFORM void
Java_dev_cobalt_coat_CobaltService_nativeSendToClient(JniEnvExt* env,
jobject jcaller,
jlong nativeService,
jbyteArray j_data) {
CobaltExtensionPlatformService service =
reinterpret_cast<CobaltExtensionPlatformService>(nativeService);
if (!CobaltExtensionPlatformServiceIsValid(service)) {
SB_LOG(WARNING) << "Trying to send message through platform service when "
"the service is already closed";
return;
}
jsize length = env->GetArrayLength(j_data);
std::unique_ptr<char[]> data(new char[length]);
env->GetByteArrayRegion(j_data, 0, length,
reinterpret_cast<jbyte*>(data.get()));
service->receive_callback(service->context, data.get(), length);
}
const void* GetPlatformServiceApi() {
return &kPlatformServiceApi;
}
} // namespace shared
} // namespace android
} // namespace starboard