Intern strings used in Sensor information.
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
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user