| /* |
| * Copyright (C) 2007 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_TAG "OSMemory" |
| |
| #include "JNIHelp.h" |
| #include "utils/misc.h" |
| #include "utils/Log.h" |
| #include <sys/mman.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| |
| /* |
| * Cached dalvik.system.VMRuntime pieces. |
| */ |
| static struct { |
| jmethodID method_trackExternalAllocation; |
| jmethodID method_trackExternalFree; |
| |
| jobject runtimeInstance; |
| } gIDCache; |
| |
| static const int MMAP_READ_ONLY = 1; |
| static const int MMAP_READ_WRITE = 2; |
| static const int MMAP_WRITE_COPY = 4; |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: littleEndian |
| * Signature: ()Z |
| */ |
| static jboolean harmony_nio_littleEndian(JNIEnv*, jclass) { |
| long l = 0x01020304; |
| unsigned char* c = (unsigned char*)&l; |
| return (*c == 0x04) ? JNI_TRUE : JNI_FALSE; |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: getPointerSizeImpl |
| * Signature: ()I |
| */ |
| static jint harmony_nio_getPointerSizeImpl(JNIEnv*, jclass) { |
| return sizeof(void *); |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: mallocImpl |
| * Signature: (I)I |
| */ |
| static jint harmony_nio_mallocImpl(JNIEnv* _env, jobject, jint size) { |
| jboolean allowed = _env->CallBooleanMethod(gIDCache.runtimeInstance, |
| gIDCache.method_trackExternalAllocation, (jlong) size); |
| if (!allowed) { |
| LOGW("External allocation of %d bytes was rejected\n", size); |
| jniThrowException(_env, "java/lang/OutOfMemoryError", NULL); |
| return 0; |
| } |
| |
| LOGV("OSMemory alloc %d\n", size); |
| void *returnValue = malloc(size + sizeof(jlong)); |
| if (returnValue == NULL) { |
| jniThrowException(_env, "java/lang/OutOfMemoryError", NULL); |
| return 0; |
| } |
| |
| /* |
| * Tuck a copy of the size at the head of the buffer. We need this |
| * so harmony_nio_freeImpl() knows how much memory is being freed. |
| */ |
| jlong* adjptr = (jlong*) returnValue; |
| *adjptr++ = size; |
| return (jint)adjptr; |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: freeImpl |
| * Signature: (I)V |
| */ |
| static void harmony_nio_freeImpl(JNIEnv* _env, jobject, jint pointer) { |
| jlong* adjptr = (jlong*) pointer; |
| jint size = *--adjptr; |
| LOGV("OSMemory free %d\n", size); |
| _env->CallVoidMethod(gIDCache.runtimeInstance, |
| gIDCache.method_trackExternalFree, (jlong) size); |
| free((void *)adjptr); |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: memset |
| * Signature: (IBJ)V |
| */ |
| static void harmony_nio_memset(JNIEnv*, jobject, jint address, |
| jbyte value, jlong length) { |
| memset ((void *) ((jint) address), (jbyte) value, (jlong) length); |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: memmove |
| * Signature: (IIJ)V |
| */ |
| static void harmony_nio_memmove(JNIEnv*, jobject, jint destAddress, |
| jint srcAddress, jlong length) { |
| memmove ((void *) ((jint) destAddress), (const void *) ((jint) srcAddress), |
| (jlong) length); |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: getByteImpl |
| * Signature: (I)B |
| */ |
| static jbyte harmony_nio_getByteImpl(JNIEnv*, jobject, |
| jint pointer) { |
| jbyte returnValue = *((jbyte *)pointer); |
| return returnValue; |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: getBytesImpl |
| * Signature: (I[BII)V |
| */ |
| static void harmony_nio_getBytesImpl(JNIEnv* _env, jobject, jint pointer, |
| jbyteArray dst, jint offset, jint length) { |
| jbyte* src = reinterpret_cast<jbyte*>(static_cast<uintptr_t>(pointer)); |
| _env->SetByteArrayRegion(dst, offset, length, src); |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: putByteImpl |
| * Signature: (IB)V |
| */ |
| static void harmony_nio_putByteImpl(JNIEnv*, jobject, jint pointer, |
| jbyte val) { |
| *((jbyte *)pointer) = val; |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: putBytesImpl |
| * Signature: (I[BII)V |
| */ |
| static void harmony_nio_putBytesImpl(JNIEnv* _env, jobject, |
| jint pointer, jbyteArray src, jint offset, jint length) { |
| jbyte* dst = reinterpret_cast<jbyte*>(static_cast<uintptr_t>(pointer)); |
| _env->GetByteArrayRegion(src, offset, length, dst); |
| } |
| |
| static void |
| swapShorts(jshort *shorts, int count) { |
| jbyte *src = (jbyte *) shorts; |
| jbyte *dst = src; |
| for (int i = 0; i < count; ++i) { |
| jbyte b0 = *src++; |
| jbyte b1 = *src++; |
| *dst++ = b1; |
| *dst++ = b0; |
| } |
| } |
| |
| static void |
| swapInts(jint *ints, int count) { |
| jbyte *src = (jbyte *) ints; |
| jbyte *dst = src; |
| for (int i = 0; i < count; ++i) { |
| jbyte b0 = *src++; |
| jbyte b1 = *src++; |
| jbyte b2 = *src++; |
| jbyte b3 = *src++; |
| *dst++ = b3; |
| *dst++ = b2; |
| *dst++ = b1; |
| *dst++ = b0; |
| } |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: setShortArrayImpl |
| * Signature: (I[SIIZ)V |
| */ |
| static void harmony_nio_setShortArrayImpl(JNIEnv* _env, jobject, |
| jint pointer, jshortArray src, jint offset, jint length, jboolean swap) { |
| jshort* dst = reinterpret_cast<jshort*>(static_cast<uintptr_t>(pointer)); |
| _env->GetShortArrayRegion(src, offset, length, dst); |
| if (swap) { |
| swapShorts(dst, length); |
| } |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: setIntArrayImpl |
| * Signature: (I[IIIZ)V |
| */ |
| static void harmony_nio_setIntArrayImpl(JNIEnv* _env, jobject, |
| jint pointer, jintArray src, jint offset, jint length, jboolean swap) { |
| jint* dst = reinterpret_cast<jint*>(static_cast<uintptr_t>(pointer)); |
| _env->GetIntArrayRegion(src, offset, length, dst); |
| if (swap) { |
| swapInts(dst, length); |
| } |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: getShortImpl |
| * Signature: (I)S |
| */ |
| static jshort harmony_nio_getShortImpl(JNIEnv*, jobject, |
| jint pointer) { |
| if ((pointer & 0x1) == 0) { |
| jshort returnValue = *((jshort *)pointer); |
| return returnValue; |
| } else { |
| // Handle unaligned memory access one byte at a time |
| jshort s; |
| unsigned char *src = (unsigned char *) pointer; |
| unsigned char *dst = (unsigned char *) &s; |
| dst[0] = src[0]; |
| dst[1] = src[1]; |
| return s; |
| } |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: petShortImpl |
| * Signature: (IS)V |
| */ |
| static void harmony_nio_putShortImpl(JNIEnv*, jobject, jint pointer, |
| jshort value) { |
| if ((pointer & 0x1) == 0) { |
| *((jshort *)pointer) = value; |
| } else { |
| // Handle unaligned memory access one byte at a time |
| unsigned char *src = (unsigned char *) &value; |
| unsigned char *dst = (unsigned char *) pointer; |
| dst[0] = src[0]; |
| dst[1] = src[1]; |
| } |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: getIntImpl |
| * Signature: (I)I |
| */ |
| static jint harmony_nio_getIntImpl(JNIEnv*, jobject, jint pointer) { |
| if ((pointer & 0x3) == 0) { |
| jint returnValue = *((jint *)pointer); |
| return returnValue; |
| } else { |
| // Handle unaligned memory access one byte at a time |
| jint i; |
| unsigned char *src = (unsigned char *) pointer; |
| unsigned char *dst = (unsigned char *) &i; |
| dst[0] = src[0]; |
| dst[1] = src[1]; |
| dst[2] = src[2]; |
| dst[3] = src[3]; |
| return i; |
| } |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: putIntImpl |
| * Signature: (II)V |
| */ |
| static void harmony_nio_putIntImpl(JNIEnv*, jobject, jint pointer, |
| jint value) { |
| if ((pointer & 0x3) == 0) { |
| *((jint *)pointer) = value; |
| } else { |
| // Handle unaligned memory access one byte at a time |
| unsigned char *src = (unsigned char *) &value; |
| unsigned char *dst = (unsigned char *) pointer; |
| dst[0] = src[0]; |
| dst[1] = src[1]; |
| dst[2] = src[2]; |
| dst[3] = src[3]; |
| } |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: getLongImpl |
| * Signature: (I)Ljava/lang/Long; |
| */ |
| static jlong harmony_nio_getLongImpl(JNIEnv*, jobject, |
| jint pointer) { |
| if ((pointer & 0x7) == 0) { |
| jlong returnValue = *((jlong *)pointer); |
| return returnValue; |
| } else { |
| // Handle unaligned memory access one byte at a time |
| jlong l; |
| memcpy((void *) &l, (void *) pointer, sizeof(jlong)); |
| return l; |
| } |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: putLongImpl |
| * Signature: (IJ)V |
| */ |
| static void harmony_nio_putLongImpl(JNIEnv*, jobject, jint pointer, |
| jlong value) { |
| if ((pointer & 0x7) == 0) { |
| *((jlong *)pointer) = value; |
| } else { |
| // Handle unaligned memory access one byte at a time |
| memcpy((void *) pointer, (void *) &value, sizeof(jlong)); |
| } |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: getFloatImpl |
| * Signature: (I)F |
| */ |
| static jfloat harmony_nio_getFloatImpl(JNIEnv*, jobject, |
| jint pointer) { |
| if ((pointer & 0x3) == 0) { |
| jfloat returnValue = *((jfloat *)pointer); |
| return returnValue; |
| } else { |
| // Handle unaligned memory access one byte at a time |
| jfloat f; |
| memcpy((void *) &f, (void *) pointer, sizeof(jfloat)); |
| return f; |
| } |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: setFloatImpl |
| * Signature: (IF)V |
| */ |
| static void harmony_nio_putFloatImpl(JNIEnv*, jobject, jint pointer, |
| jfloat value) { |
| if ((pointer & 0x3) == 0) { |
| *((jfloat *)pointer) = value; |
| } else { |
| // Handle unaligned memory access one byte at a time |
| memcpy((void *) pointer, (void *) &value, sizeof(jfloat)); |
| } |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: getDoubleImpl |
| * Signature: (I)D |
| */ |
| static jdouble harmony_nio_getDoubleImpl(JNIEnv*, jobject, |
| jint pointer) { |
| if ((pointer & 0x7) == 0) { |
| jdouble returnValue = *((jdouble *)pointer); |
| return returnValue; |
| } else { |
| // Handle unaligned memory access one byte at a time |
| jdouble d; |
| memcpy((void *) &d, (void *) pointer, sizeof(jdouble)); |
| return d; |
| } |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: putDoubleImpl |
| * Signature: (ID)V |
| */ |
| static void harmony_nio_putDoubleImpl(JNIEnv*, jobject, jint pointer, |
| jdouble value) { |
| if ((pointer & 0x7) == 0) { |
| *((jdouble *)pointer) = value; |
| } else { |
| // Handle unaligned memory access one byte at a time |
| memcpy((void *) pointer, (void *) &value, sizeof(jdouble)); |
| } |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: getAddress |
| * Signature: (I)I |
| */ |
| static jint harmony_nio_getAddress(JNIEnv*, jobject, jint pointer) { |
| return (jint) * (int *) pointer; |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: setAddress |
| * Signature: (II)V |
| */ |
| static void harmony_nio_setAddress(JNIEnv*, jobject, jint pointer, |
| jint value) { |
| *(int *) pointer = (int) value; |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: mmapImpl |
| * Signature: (IJJI)I |
| */ |
| static jint harmony_nio_mmapImpl(JNIEnv* env, jobject, jint fd, |
| jlong offset, jlong size, jint mapMode) { |
| int prot, flags; |
| switch (mapMode) { |
| case MMAP_READ_ONLY: |
| prot = PROT_READ; |
| flags = MAP_SHARED; |
| break; |
| case MMAP_READ_WRITE: |
| prot = PROT_READ|PROT_WRITE; |
| flags = MAP_SHARED; |
| break; |
| case MMAP_WRITE_COPY: |
| prot = PROT_READ|PROT_WRITE; |
| flags = MAP_PRIVATE; |
| break; |
| default: |
| jniThrowIOException(env, EINVAL); |
| LOGE("bad mapMode %i", mapMode); |
| return -1; |
| } |
| |
| void* mapAddress = mmap(0, size, prot, flags, fd, offset); |
| if (mapAddress == MAP_FAILED) { |
| jniThrowIOException(env, errno); |
| } |
| return reinterpret_cast<uintptr_t>(mapAddress); |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: unmapImpl |
| * Signature: (IJ)V |
| */ |
| static void harmony_nio_unmapImpl(JNIEnv*, jobject, jint address, |
| jlong size) { |
| munmap((void *)address, (size_t)size); |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: loadImpl |
| * Signature: (IJ)I |
| */ |
| static jint harmony_nio_loadImpl(JNIEnv*, jobject, jint address, |
| jlong size) { |
| |
| if(mlock((void *)address, (size_t)size)!=-1) { |
| if(munlock((void *)address, (size_t)size)!=-1) { |
| return 0; /* normally */ |
| } |
| } |
| else { |
| /* according to linux sys call, only root can mlock memory. */ |
| if(errno == EPERM) { |
| return 0; |
| } |
| } |
| |
| return -1; |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: isLoadedImpl |
| * Signature: (IJ)Z |
| */ |
| static jboolean harmony_nio_isLoadedImpl(JNIEnv*, jobject, |
| jint address, jlong size) { |
| |
| static int page_size = getpagesize(); |
| jboolean result = 0; |
| jint m_addr = (jint)address; |
| |
| int align_offset = m_addr%page_size;// addr should align with the boundary of a page. |
| m_addr -= align_offset; |
| size += align_offset; |
| int page_count = (size+page_size-1)/page_size; |
| |
| unsigned char* vec = (unsigned char *) malloc(page_count*sizeof(char)); |
| |
| if (mincore((void *)m_addr, size, (MINCORE_POINTER_TYPE) vec)==0) { |
| // or else there is error about the mincore and return false; |
| int i; |
| for(i=0 ;i<page_count;i++) { |
| if(vec[i]!=1) { |
| break; |
| } |
| } |
| if(i==page_count) { |
| result = 1; |
| } |
| } |
| |
| free(vec); |
| |
| return result; |
| } |
| |
| /* |
| * Class: org_apache_harmony_luni_platform_OSMemory |
| * Method: flushImpl |
| * Signature: (IJ)I |
| */ |
| static jint harmony_nio_flushImpl(JNIEnv *, jobject, jint address, jlong size) { |
| return msync((void *)address, size, MS_SYNC); |
| } |
| |
| static JNINativeMethod gMethods[] = { |
| { "isLittleEndianImpl", "()Z", (void*) harmony_nio_littleEndian }, |
| { "getPointerSizeImpl", "()I", (void*) harmony_nio_getPointerSizeImpl }, |
| { "malloc", "(I)I", (void*) harmony_nio_mallocImpl }, |
| { "free", "(I)V", (void*) harmony_nio_freeImpl }, |
| { "memset", "(IBJ)V", (void*) harmony_nio_memset }, |
| { "memmove", "(IIJ)V", (void*) harmony_nio_memmove }, |
| { "getByteArray", "(I[BII)V",(void*) harmony_nio_getBytesImpl }, |
| { "setByteArray", "(I[BII)V",(void*) harmony_nio_putBytesImpl }, |
| { "setShortArray", "(I[SIIZ)V",(void*) harmony_nio_setShortArrayImpl }, |
| { "setIntArray", "(I[IIIZ)V",(void*) harmony_nio_setIntArrayImpl }, |
| { "getByte", "(I)B", (void*) harmony_nio_getByteImpl }, |
| { "setByte", "(IB)V", (void*) harmony_nio_putByteImpl }, |
| { "getShort", "(I)S", (void*) harmony_nio_getShortImpl }, |
| { "setShort", "(IS)V", (void*) harmony_nio_putShortImpl }, |
| { "getInt", "(I)I", (void*) harmony_nio_getIntImpl }, |
| { "setInt", "(II)V", (void*) harmony_nio_putIntImpl }, |
| { "getLong", "(I)J", (void*) harmony_nio_getLongImpl }, |
| { "setLong", "(IJ)V", (void*) harmony_nio_putLongImpl }, |
| { "getFloat", "(I)F", (void*) harmony_nio_getFloatImpl }, |
| { "setFloat", "(IF)V", (void*) harmony_nio_putFloatImpl }, |
| { "getDouble", "(I)D", (void*) harmony_nio_getDoubleImpl }, |
| { "setDouble", "(ID)V", (void*) harmony_nio_putDoubleImpl }, |
| { "getAddress", "(I)I", (void*) harmony_nio_getAddress }, |
| { "setAddress", "(II)V", (void*) harmony_nio_setAddress }, |
| { "mmapImpl", "(IJJI)I", (void*) harmony_nio_mmapImpl }, |
| { "unmapImpl", "(IJ)V", (void*) harmony_nio_unmapImpl }, |
| { "loadImpl", "(IJ)I", (void*) harmony_nio_loadImpl }, |
| { "isLoadedImpl", "(IJ)Z", (void*) harmony_nio_isLoadedImpl }, |
| { "flushImpl", "(IJ)I", (void*) harmony_nio_flushImpl } |
| }; |
| int register_org_apache_harmony_luni_platform_OSMemory(JNIEnv* env) { |
| /* |
| * We need to call VMRuntime.trackExternal{Allocation,Free}. Cache |
| * method IDs and a reference to the singleton. |
| */ |
| static const char* kVMRuntimeName = "dalvik/system/VMRuntime"; |
| jmethodID method_getRuntime; |
| jclass clazz; |
| |
| clazz = env->FindClass(kVMRuntimeName); |
| if (clazz == NULL) { |
| LOGE("Unable to find class %s\n", kVMRuntimeName); |
| return -1; |
| } |
| gIDCache.method_trackExternalAllocation = env->GetMethodID(clazz, |
| "trackExternalAllocation", "(J)Z"); |
| gIDCache.method_trackExternalFree = env->GetMethodID(clazz, |
| "trackExternalFree", "(J)V"); |
| method_getRuntime = env->GetStaticMethodID(clazz, |
| "getRuntime", "()Ldalvik/system/VMRuntime;"); |
| |
| if (gIDCache.method_trackExternalAllocation == NULL || |
| gIDCache.method_trackExternalFree == NULL || |
| method_getRuntime == NULL) |
| { |
| LOGE("Unable to find VMRuntime methods\n"); |
| return -1; |
| } |
| |
| jobject instance = env->CallStaticObjectMethod(clazz, method_getRuntime); |
| if (instance == NULL) { |
| LOGE("Unable to obtain VMRuntime instance\n"); |
| return -1; |
| } |
| gIDCache.runtimeInstance = env->NewGlobalRef(instance); |
| |
| return jniRegisterNativeMethods(env, "org/apache/harmony/luni/platform/OSMemory", |
| gMethods, NELEM(gMethods)); |
| } |