Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2017 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 TAG "NativeCursorWindow"
     18 
     19 #include <jni.h>
     20 #include <fcntl.h>
     21 #include <unistd.h>
     22 #include <sys/types.h>
     23 #include <sys/mman.h>
     24 #include <errno.h>
     25 
     26 #include <android/log.h>
     27 #define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
     28 #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
     29 
     30 struct Header {
     31     // Offset of the lowest unused byte in the window.
     32     uint32_t freeOffset;
     33 
     34     // Offset of the first row slot chunk.
     35     uint32_t firstChunkOffset;
     36 
     37     uint32_t numRows;
     38     uint32_t numColumns;
     39 };
     40 
     41 struct RowSlot {
     42     uint32_t offset;
     43 };
     44 
     45 #define ROW_SLOT_CHUNK_NUM_ROWS 100
     46 
     47 struct RowSlotChunk {
     48     struct RowSlot slots[ROW_SLOT_CHUNK_NUM_ROWS];
     49     uint32_t nextChunkOffset;
     50 };
     51 
     52 /* Field types. */
     53 enum {
     54     FIELD_TYPE_NULL = 0,
     55     FIELD_TYPE_INTEGER = 1,
     56     FIELD_TYPE_FLOAT = 2,
     57     FIELD_TYPE_STRING = 3,
     58     FIELD_TYPE_BLOB = 4,
     59 };
     60 
     61 /* Opaque type that describes a field slot. */
     62 struct FieldSlot {
     63     int32_t type;
     64     union {
     65         double d;
     66         int64_t l;
     67         struct {
     68             uint32_t offset;
     69             uint32_t size;
     70         } buffer;
     71     } data;
     72 } __attribute((packed));
     73 
     74 extern "C" JNIEXPORT jint JNICALL
     75 Java_android_content_cts_CursorWindowContentProvider_makeNativeCursorWindowFd(
     76         JNIEnv *env, jclass clazz,
     77         jstring filename, jint offset, jint size, jboolean isBlob) {
     78 
     79     const char* chars = env->GetStringUTFChars(filename, NULL);
     80 
     81     ALOGI("opening %s", chars);
     82 
     83     const int FILE_SIZE = 1024;
     84 
     85     int fd = open(chars, O_CREAT | O_RDWR | O_CLOEXEC, 0700);
     86     // env->ReleaseStringUTFChars(filename, chars); // too lazy; skip.
     87 
     88     if (fd == -1) {
     89         ALOGE("open(%s) failed: %d", chars, errno);
     90         return -1;
     91     }
     92 
     93     ftruncate(fd, FILE_SIZE);
     94 
     95     char* data = (char*) mmap(NULL, FILE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
     96     if (data == (char*) -1) {
     97         ALOGE("mmap(%s) failed: %d", chars, errno);
     98         return -1;
     99     }
    100 
    101     struct Header *header = (struct Header *) data;
    102     unsigned rowSlotChunkOffset = sizeof(struct Header);
    103     struct RowSlotChunk *rowSlotChunk = (struct RowSlotChunk *)(data + rowSlotChunkOffset);
    104     unsigned fieldSlotOffset = rowSlotChunkOffset + sizeof(struct RowSlotChunk);
    105     struct FieldSlot *fieldSlot = (struct FieldSlot *) (data + fieldSlotOffset);
    106 
    107     header->numRows = 1;
    108     header->numColumns = 1;
    109     header->firstChunkOffset = rowSlotChunkOffset;
    110 
    111     rowSlotChunk->slots[0].offset = fieldSlotOffset;
    112 
    113     fieldSlot->type = isBlob ? FIELD_TYPE_BLOB : FIELD_TYPE_STRING;
    114     fieldSlot->data.buffer.offset = offset;
    115     fieldSlot->data.buffer.size = size;
    116 
    117     munmap(data, FILE_SIZE);
    118 
    119     return fd;
    120 
    121 }
    122