Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9ba7c1c1 authored by destradaa's avatar destradaa
Browse files

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
parent 4a39e1bb
Loading
Loading
Loading
Loading
+92 −0
Original line number Diff line number Diff line
@@ -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;
        }
    }
}
+53 −9
Original line number Diff line number Diff line
@@ -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;
}