blob: 23d2d32409dd8f71ad6dfa8bf761e33c90bb9d73 [file] [log] [blame]
/*
* Copyright 2020 The Android Open Source Project
*
* 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.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "ImageHashManager"
#include <android/hardware_buffer_jni.h>
#include <log/log_main.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/scoped_utf_chars.h>
#include <array>
#include <string>
#include <ImageHashManager.h>
namespace android {
class BufferWrapper {
public:
BufferWrapper(AHardwareBuffer* buffer) : mBuffer(buffer) {}
int lock(uint8_t** buf) {
if (mIsLocked) {
return -1;
}
int status = AHardwareBuffer_lock(mBuffer,
AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER,
-1 /* fence */, nullptr /* rect */,
reinterpret_cast<void**>(buf));
if (!status) {
mIsLocked = true;
}
return status;
}
void unlock() {
if (!mIsLocked) {
return;
}
mIsLocked = false;
AHardwareBuffer_unlock(mBuffer, nullptr);
}
~BufferWrapper() { unlock(); }
private:
AHardwareBuffer* mBuffer = nullptr;
bool mIsLocked = false;
};
static jbyteArray nativeGenerateHash(JNIEnv* env, jobject clazz, jobject hardwareBufferObj,
jstring hashAlgorithmString) {
ScopedUtfChars hashAlgorithmChars(env, hashAlgorithmString);
std::string hashAlgorithm(hashAlgorithmChars.c_str());
transform(hashAlgorithm.begin(), hashAlgorithm.end(), hashAlgorithm.begin(), ::tolower);
AHardwareBuffer* hardwareBuffer = AHardwareBuffer_fromHardwareBuffer(env, hardwareBufferObj);
AHardwareBuffer_Desc bufferDesc;
AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
BufferWrapper bufferWrapper(hardwareBuffer);
uint8_t* buf = nullptr;
int32_t status = bufferWrapper.lock(&buf);
if (status) {
ALOGE("Failed to lock buffer status=%d", status);
return nullptr;
}
std::array<uint8_t, 8> imageHash;
status = ImageHashManager::generateHash(hashAlgorithm, buf, bufferDesc, &imageHash);
if (status) {
ALOGE("Failed to generate hash status=%d", status);
return nullptr;
}
jbyteArray ret = env->NewByteArray(8);
if (ret) {
jbyte* bytes = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
if (bytes) {
memcpy(bytes, imageHash.data(), 8);
env->ReleasePrimitiveArrayCritical(ret, bytes, 0);
}
}
return ret;
}
// clang-format off
static const JNINativeMethod gMethods[] = {
{"nativeGenerateHash", "(Landroid/hardware/HardwareBuffer;Ljava/lang/String;)[B",
(void *)nativeGenerateHash},
};
// clang-format on
int register_android_ext_services_displayhash_DisplayHashAlgorithm(JNIEnv* env) {
int res = jniRegisterNativeMethods(env, "android/ext/services/displayhash/ImageHashManager",
gMethods, NELEM(gMethods));
LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
return res;
}
} /* namespace android */