OSDN Git Service

Intern strings used in Sensor information.
authordestradaa <destradaa@google.com>
Tue, 10 Feb 2015 23:04:43 +0000 (15:04 -0800)
committerdestradaa <destradaa@google.com>
Tue, 10 Feb 2015 23:07:50 +0000 (15:07 -0800)
By creating a local 'interning map', Sensor information, such as: name, vendor,
stringType, and requirePermissions; 92 string objects are not needed anymore.
This frees ~6KB of memory in all processes accessing SensorManager.

Change-Id: Idfdc98160363bec844c34fc3b71f5e8d7843a7be

core/java/android/hardware/Sensor.java
core/jni/android_hardware_SensorManager.cpp

index cf6a779..43f44d2 100644 (file)
@@ -810,4 +810,96 @@ public final class Sensor {
                 + ", type=" + mType + ", maxRange=" + mMaxRange + ", resolution=" + mResolution
                 + ", power=" + mPower + ", minDelay=" + mMinDelay + "}";
     }
+
+    /**
+     * Sets the Type associated with the sensor.
+     * NOTE: to be used only by native bindings in SensorManager.
+     *
+     * This allows interned static strings to be used across all representations of the Sensor. If
+     * a sensor type is not referenced here, it will still be interned by the native SensorManager.
+     *
+     * @return {@code true} if the StringType was successfully set, {@code false} otherwise.
+     */
+    private boolean setType(int value) {
+        mType = value;
+        switch (mType) {
+            case TYPE_ACCELEROMETER:
+                mStringType = STRING_TYPE_ACCELEROMETER;
+                return true;
+            case TYPE_AMBIENT_TEMPERATURE:
+                mStringType = STRING_TYPE_AMBIENT_TEMPERATURE;
+                return true;
+            case TYPE_GAME_ROTATION_VECTOR:
+                mStringType = STRING_TYPE_GAME_ROTATION_VECTOR;
+                return true;
+            case TYPE_GEOMAGNETIC_ROTATION_VECTOR:
+                mStringType = STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR;
+                return true;
+            case TYPE_GLANCE_GESTURE:
+                mStringType = STRING_TYPE_GLANCE_GESTURE;
+                return true;
+            case TYPE_GRAVITY:
+                mStringType = STRING_TYPE_GRAVITY;
+                return true;
+            case TYPE_GYROSCOPE:
+                mStringType = STRING_TYPE_GYROSCOPE;
+                return true;
+            case TYPE_GYROSCOPE_UNCALIBRATED:
+                mStringType = STRING_TYPE_GYROSCOPE_UNCALIBRATED;
+                return true;
+            case TYPE_HEART_RATE:
+                mStringType = STRING_TYPE_HEART_RATE;
+                return true;
+            case TYPE_LIGHT:
+                mStringType = STRING_TYPE_LIGHT;
+                return true;
+            case TYPE_LINEAR_ACCELERATION:
+                mStringType = STRING_TYPE_LINEAR_ACCELERATION;
+                return true;
+            case TYPE_MAGNETIC_FIELD:
+                mStringType = STRING_TYPE_MAGNETIC_FIELD;
+                return true;
+            case TYPE_MAGNETIC_FIELD_UNCALIBRATED:
+                mStringType = STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED;
+                return true;
+            case TYPE_PICK_UP_GESTURE:
+                mStringType = STRING_TYPE_PICK_UP_GESTURE;
+                return true;
+            case TYPE_PRESSURE:
+                mStringType = STRING_TYPE_PRESSURE;
+                return true;
+            case TYPE_PROXIMITY:
+                mStringType = STRING_TYPE_PROXIMITY;
+                return true;
+            case TYPE_RELATIVE_HUMIDITY:
+                mStringType = STRING_TYPE_RELATIVE_HUMIDITY;
+                return true;
+            case TYPE_ROTATION_VECTOR:
+                mStringType = STRING_TYPE_ROTATION_VECTOR;
+                return true;
+            case TYPE_SIGNIFICANT_MOTION:
+                mStringType = STRING_TYPE_SIGNIFICANT_MOTION;
+                return true;
+            case TYPE_STEP_COUNTER:
+                mStringType = STRING_TYPE_STEP_COUNTER;
+                return true;
+            case TYPE_STEP_DETECTOR:
+                mStringType = STRING_TYPE_STEP_DETECTOR;
+                return true;
+            case TYPE_TILT_DETECTOR:
+                mStringType = SENSOR_STRING_TYPE_TILT_DETECTOR;
+                return true;
+            case TYPE_WAKE_GESTURE:
+                mStringType = STRING_TYPE_WAKE_GESTURE;
+                return true;
+            case TYPE_ORIENTATION:
+                mStringType = STRING_TYPE_ORIENTATION;
+                return true;
+            case TYPE_TEMPERATURE:
+                mStringType = STRING_TYPE_TEMPERATURE;
+                return true;
+            default:
+                return false;
+        }
+    }
 }
index d1b1a1a..0b737a7 100644 (file)
@@ -16,6 +16,8 @@
 
 #define LOG_TAG "SensorManager"
 
+#include <map>
+
 #include <utils/Log.h>
 #include <utils/Looper.h>
 
@@ -44,7 +46,6 @@ struct SensorOffsets
     jfieldID    vendor;
     jfieldID    version;
     jfieldID    handle;
-    jfieldID    type;
     jfieldID    range;
     jfieldID    resolution;
     jfieldID    power;
@@ -55,6 +56,7 @@ struct SensorOffsets
     jfieldID    requiredPermission;
     jfieldID    maxDelay;
     jfieldID    flags;
+    jmethodID   setType;
 } gSensorOffsets;
 
 
@@ -71,7 +73,6 @@ nativeClassInit (JNIEnv *_env, jclass _this)
     sensorOffsets.vendor      = _env->GetFieldID(sensorClass, "mVendor",    "Ljava/lang/String;");
     sensorOffsets.version     = _env->GetFieldID(sensorClass, "mVersion",   "I");
     sensorOffsets.handle      = _env->GetFieldID(sensorClass, "mHandle",    "I");
-    sensorOffsets.type        = _env->GetFieldID(sensorClass, "mType",      "I");
     sensorOffsets.range       = _env->GetFieldID(sensorClass, "mMaxRange",  "F");
     sensorOffsets.resolution  = _env->GetFieldID(sensorClass, "mResolution","F");
     sensorOffsets.power       = _env->GetFieldID(sensorClass, "mPower",     "F");
@@ -84,6 +85,47 @@ nativeClassInit (JNIEnv *_env, jclass _this)
                                                         "Ljava/lang/String;");
     sensorOffsets.maxDelay    = _env->GetFieldID(sensorClass, "mMaxDelay",  "I");
     sensorOffsets.flags = _env->GetFieldID(sensorClass, "mFlags",  "I");
+    sensorOffsets.setType = _env->GetMethodID(sensorClass, "setType", "(I)Z");
+}
+
+/**
+ * A key comparator predicate.
+ * It is used to intern strings associated with Sensor data.
+ * It defines a 'Strict weak ordering' for the interned strings.
+ */
+class InternedStringCompare {
+public:
+    bool operator()(const String8* string1, const String8* string2) const {
+        if (string1 == NULL) {
+            return string2 != NULL;
+        }
+        return string1->compare(*string2) < 0;
+    }
+};
+
+/**
+ * A localized interning mechanism for Sensor strings.
+ * We implement our own interning to avoid the overhead of using java.lang.String#intern().
+ * It is common that Vendor, StringType, and RequirePermission data is common between many of the
+ * Sensors, by interning the memory usage to represent Sensors is optimized.
+ */
+static jstring
+getInternedString(JNIEnv *env, const String8* string) {
+    static std::map<const String8*, jstring, InternedStringCompare> internedStrings;
+
+    jstring internedString;
+    std::map<const String8*, jstring>::iterator iterator = internedStrings.find(string);
+    if (iterator != internedStrings.end()) {
+        internedString = iterator->second;
+    } else {
+        jstring localString = env->NewStringUTF(string->string());
+        // we are implementing our own interning so expect these strings to be backed by global refs
+        internedString = (jstring) env->NewGlobalRef(localString);
+        internedStrings.insert(std::make_pair(string, internedString));
+        env->DeleteLocalRef(localString);
+    }
+
+    return internedString;
 }
 
 static jint
@@ -93,20 +135,19 @@ nativeGetNextSensor(JNIEnv *env, jclass clazz, jobject sensor, jint next)
 
     Sensor const* const* sensorList;
     size_t count = mgr.getSensorList(&sensorList);
-    if (size_t(next) >= count)
+    if (size_t(next) >= count) {
         return -1;
+    }
 
     Sensor const* const list = sensorList[next];
     const SensorOffsets& sensorOffsets(gSensorOffsets);
-    jstring name = env->NewStringUTF(list->getName().string());
-    jstring vendor = env->NewStringUTF(list->getVendor().string());
-    jstring stringType = env->NewStringUTF(list->getStringType().string());
-    jstring requiredPermission = env->NewStringUTF(list->getRequiredPermission().string());
+    jstring name = getInternedString(env, &list->getName());
+    jstring vendor = getInternedString(env, &list->getVendor());
+    jstring requiredPermission = getInternedString(env, &list->getRequiredPermission());
     env->SetObjectField(sensor, sensorOffsets.name,      name);
     env->SetObjectField(sensor, sensorOffsets.vendor,    vendor);
     env->SetIntField(sensor, sensorOffsets.version,      list->getVersion());
     env->SetIntField(sensor, sensorOffsets.handle,       list->getHandle());
-    env->SetIntField(sensor, sensorOffsets.type,         list->getType());
     env->SetFloatField(sensor, sensorOffsets.range,      list->getMaxValue());
     env->SetFloatField(sensor, sensorOffsets.resolution, list->getResolution());
     env->SetFloatField(sensor, sensorOffsets.power,      list->getPowerUsage());
@@ -115,11 +156,14 @@ nativeGetNextSensor(JNIEnv *env, jclass clazz, jobject sensor, jint next)
                      list->getFifoReservedEventCount());
     env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount,
                      list->getFifoMaxEventCount());
-    env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
     env->SetObjectField(sensor, sensorOffsets.requiredPermission,
                         requiredPermission);
     env->SetIntField(sensor, sensorOffsets.maxDelay, list->getMaxDelay());
     env->SetIntField(sensor, sensorOffsets.flags, list->getFlags());
+    if (env->CallBooleanMethod(sensor, sensorOffsets.setType, list->getType()) == JNI_FALSE) {
+        jstring stringType = getInternedString(env, &list->getStringType());
+        env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
+    }
     next++;
     return size_t(next) < count ? next : 0;
 }