1 /*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "ImageHashManager"
19
20 #include <android/hardware_buffer_jni.h>
21 #include <log/log_main.h>
22 #include <nativehelper/JNIHelp.h>
23 #include <nativehelper/scoped_utf_chars.h>
24 #include <array>
25 #include <string>
26
27 #include <ImageHashManager.h>
28
29 namespace android {
30
31 class BufferWrapper {
32 public:
BufferWrapper(AHardwareBuffer * buffer)33 BufferWrapper(AHardwareBuffer* buffer) : mBuffer(buffer) {}
34
lock(uint8_t ** buf)35 int lock(uint8_t** buf) {
36 if (mIsLocked) {
37 return -1;
38 }
39
40 int status = AHardwareBuffer_lock(mBuffer,
41 AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
42 AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER,
43 -1 /* fence */, nullptr /* rect */,
44 reinterpret_cast<void**>(buf));
45 if (!status) {
46 mIsLocked = true;
47 }
48 return status;
49 }
50
unlock()51 void unlock() {
52 if (!mIsLocked) {
53 return;
54 }
55 mIsLocked = false;
56 AHardwareBuffer_unlock(mBuffer, nullptr);
57 }
58
~BufferWrapper()59 ~BufferWrapper() { unlock(); }
60
61 private:
62 AHardwareBuffer* mBuffer = nullptr;
63 bool mIsLocked = false;
64 };
65
nativeGenerateHash(JNIEnv * env,jobject clazz,jobject hardwareBufferObj,jstring hashAlgorithmString)66 static jbyteArray nativeGenerateHash(JNIEnv* env, jobject clazz, jobject hardwareBufferObj,
67 jstring hashAlgorithmString) {
68 ScopedUtfChars hashAlgorithmChars(env, hashAlgorithmString);
69 std::string hashAlgorithm(hashAlgorithmChars.c_str());
70
71 transform(hashAlgorithm.begin(), hashAlgorithm.end(), hashAlgorithm.begin(), ::tolower);
72
73 AHardwareBuffer* hardwareBuffer = AHardwareBuffer_fromHardwareBuffer(env, hardwareBufferObj);
74
75 AHardwareBuffer_Desc bufferDesc;
76 AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
77
78 BufferWrapper bufferWrapper(hardwareBuffer);
79 uint8_t* buf = nullptr;
80 int32_t status = bufferWrapper.lock(&buf);
81
82 if (status) {
83 ALOGE("Failed to lock buffer status=%d", status);
84 return nullptr;
85 }
86
87 std::array<uint8_t, 8> imageHash;
88 status = ImageHashManager::generateHash(hashAlgorithm, buf, bufferDesc, &imageHash);
89
90 if (status) {
91 ALOGE("Failed to generate hash status=%d", status);
92 return nullptr;
93 }
94
95 jbyteArray ret = env->NewByteArray(8);
96 if (ret) {
97 jbyte* bytes = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
98 if (bytes) {
99 memcpy(bytes, imageHash.data(), 8);
100 env->ReleasePrimitiveArrayCritical(ret, bytes, 0);
101 }
102 }
103 return ret;
104 }
105
106 // clang-format off
107 static const JNINativeMethod gMethods[] = {
108 {"nativeGenerateHash", "(Landroid/hardware/HardwareBuffer;Ljava/lang/String;)[B",
109 (void *)nativeGenerateHash},
110 };
111 // clang-format on
112
register_android_ext_services_displayhash_DisplayHashAlgorithm(JNIEnv * env)113 int register_android_ext_services_displayhash_DisplayHashAlgorithm(JNIEnv* env) {
114 int res = jniRegisterNativeMethods(env, "android/ext/services/displayhash/ImageHashManager",
115 gMethods, NELEM(gMethods));
116 LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
117
118 return res;
119 }
120
121 } /* namespace android */
122