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