Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2014 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_TAG "BitmapSerializeUtils"
     18 
     19 #include <jni.h>
     20 #include <JNIHelp.h>
     21 
     22 #include <android/bitmap.h>
     23 #include <android/log.h>
     24 
     25 namespace android {
     26 
     27 #define RGBA_8888_COLOR_DEPTH 4
     28 
     29 static bool writeAllBytes(const int fd, void* buffer, const size_t byteCount) {
     30     char* writeBuffer = static_cast<char*>(buffer);
     31     size_t remainingBytes = byteCount;
     32     while (remainingBytes > 0) {
     33         ssize_t writtenByteCount = write(fd, writeBuffer, remainingBytes);
     34         if (writtenByteCount == -1) {
     35             if (errno == EINTR) {
     36                 continue;
     37             }
     38             __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
     39                     "Error writing to buffer: %d", errno);
     40             return false;
     41         }
     42         remainingBytes -= writtenByteCount;
     43         writeBuffer += writtenByteCount;
     44     }
     45     return true;
     46 }
     47 
     48 static bool readAllBytes(const int fd, void* buffer, const size_t byteCount) {
     49     char* readBuffer = static_cast<char*>(buffer);
     50     size_t remainingBytes = byteCount;
     51     while (remainingBytes > 0) {
     52         ssize_t readByteCount = read(fd, readBuffer, remainingBytes);
     53 
     54         remainingBytes -= readByteCount;
     55         readBuffer += readByteCount;
     56 
     57         if (readByteCount == -1) {
     58             if (errno == EINTR) {
     59                 continue;
     60             }
     61             __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
     62                     "Error reading from buffer: %d", errno);
     63             return false;
     64         } else if (readByteCount == 0 && remainingBytes > 0) {
     65             __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
     66                     "File closed before all bytes were read. %zu/%zu remaining", remainingBytes,
     67                     byteCount);
     68             return false;
     69         }
     70     }
     71     return true;
     72 }
     73 
     74 static void throwException(JNIEnv* env, const char* className, const char* message) {
     75     jclass exceptionClass = env->FindClass(className);
     76     env->ThrowNew(exceptionClass, message);
     77 }
     78 
     79 static void throwIllegalStateException(JNIEnv* env, char *message) {
     80     const char* className = "java/lang/IllegalStateException";
     81     throwException(env, className, message);
     82 }
     83 
     84 static void throwIllegalArgumentException(JNIEnv* env, char* message) {
     85     const char* className = "java/lang/IllegalArgumentException";
     86     throwException(env, className, message);
     87 }
     88 
     89 static void readBitmapPixels(JNIEnv* env, jclass /* clazz */, jobject jbitmap, jint fd) {
     90     // Read the info.
     91     AndroidBitmapInfo readInfo;
     92     bool read = readAllBytes(fd, (void*) &readInfo, sizeof(AndroidBitmapInfo));
     93     if (!read) {
     94         throwIllegalStateException(env, (char*) "Cannot read bitmap info");
     95         return;
     96     }
     97 
     98     // Get the info of the target bitmap.
     99     AndroidBitmapInfo targetInfo;
    100     int result = AndroidBitmap_getInfo(env, jbitmap, &targetInfo);
    101     if (result < 0) {
    102         throwIllegalStateException(env, (char*) "Cannot get bitmap info");
    103         return;
    104     }
    105 
    106     // Enforce we can reuse the bitmap.
    107     if (readInfo.width != targetInfo.width || readInfo.height != targetInfo.height
    108             || readInfo.stride != targetInfo.stride || readInfo.format != targetInfo.format
    109             || readInfo.flags != targetInfo.flags) {
    110         throwIllegalArgumentException(env, (char*) "Cannot reuse bitmap");
    111         return;
    112     }
    113 
    114     // Lock the pixels.
    115     void* pixels;
    116     result = AndroidBitmap_lockPixels(env, jbitmap, &pixels);
    117     if (result < 0) {
    118         throwIllegalStateException(env, (char*) "Cannot lock bitmap pixels");
    119         return;
    120     }
    121 
    122     // Read the pixels.
    123     size_t byteCount = readInfo.stride * readInfo.height;
    124     read = readAllBytes(fd, (void*) pixels, byteCount);
    125     if (!read) {
    126         throwIllegalStateException(env, (char*) "Cannot read bitmap pixels");
    127         return;
    128     }
    129 
    130     // Unlock the pixels.
    131     result = AndroidBitmap_unlockPixels(env, jbitmap);
    132     if (result < 0) {
    133         throwIllegalStateException(env, (char*) "Cannot unlock bitmap pixels");
    134     }
    135 }
    136 
    137 static void writeBitmapPixels(JNIEnv* env, jclass /* clazz */, jobject jbitmap, jint fd) {
    138     // Get the info.
    139     AndroidBitmapInfo info;
    140     int result = AndroidBitmap_getInfo(env, jbitmap, &info);
    141     if (result < 0) {
    142         throwIllegalStateException(env, (char*) "Cannot get bitmap info");
    143         return;
    144     }
    145 
    146     // Write the info.
    147     bool written = writeAllBytes(fd, (void*) &info, sizeof(AndroidBitmapInfo));
    148     if (!written) {
    149         throwIllegalStateException(env, (char*) "Cannot write bitmap info");
    150         return;
    151     }
    152 
    153     // Lock the pixels.
    154     void* pixels;
    155     result = AndroidBitmap_lockPixels(env, jbitmap, &pixels);
    156     if (result < 0) {
    157         throwIllegalStateException(env, (char*) "Cannot lock bitmap pixels");
    158         return;
    159     }
    160 
    161     // Write the pixels.
    162     size_t byteCount = info.stride * info.height;
    163     written = writeAllBytes(fd, (void*) pixels, byteCount);
    164     if (!written) {
    165         throwIllegalStateException(env, (char*) "Cannot write bitmap pixels");
    166         return;
    167     }
    168 
    169     // Unlock the pixels.
    170     result = AndroidBitmap_unlockPixels(env, jbitmap);
    171     if (result < 0) {
    172         throwIllegalStateException(env, (char*) "Cannot unlock bitmap pixels");
    173     }
    174 }
    175 
    176 static const JNINativeMethod sMethods[] = {
    177     {"nativeReadBitmapPixels", "(Landroid/graphics/Bitmap;I)V", (void *) readBitmapPixels},
    178     {"nativeWriteBitmapPixels", "(Landroid/graphics/Bitmap;I)V", (void *) writeBitmapPixels},
    179 };
    180 
    181 int register_com_android_printspooler_util_BitmapSerializeUtils(JNIEnv* env) {
    182     return jniRegisterNativeMethods(env, "com/android/printspooler/util/BitmapSerializeUtils",
    183         sMethods, NELEM(sMethods));
    184 }
    185 
    186 }
    187 
    188 jint JNI_OnLoad(JavaVM* jvm, void*) {
    189     JNIEnv *env = NULL;
    190     if (jvm->GetEnv((void**) &env, JNI_VERSION_1_6)) {
    191         return JNI_ERR;
    192     }
    193 
    194     if (android::register_com_android_printspooler_util_BitmapSerializeUtils(env) == -1) {
    195         return JNI_ERR;
    196     }
    197 
    198     return JNI_VERSION_1_6;
    199 }
    200