HardwarePropertiesManager: Add API for hardware properties retrieval

Add serive "hardwareproperties" and methods getDeviceTemperatures,
getCpuUsages and getFanSpeeds to retrieve hardware properties:
device temperatures (CPU, GPU and battery), CPU usages and fan speeds.
This is a public API.

Bug: 22407109
Change-Id: If7efcbba7b160256d41704b60d93a7218dcc79d7
diff --git a/api/current.txt b/api/current.txt
index 629d832..6b20e09 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7972,6 +7972,7 @@
     field public static final java.lang.String DOWNLOAD_SERVICE = "download";
     field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
     field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
+    field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardwareproperties";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
     field public static final java.lang.String INPUT_SERVICE = "input";
     field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
@@ -27646,6 +27647,14 @@
     method public final synchronized android.os.CountDownTimer start();
   }
 
+  public final class CpuUsageInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getActive();
+    method public long getTotal();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.os.CpuUsageInfo> CREATOR;
+  }
+
   public class DeadObjectException extends android.os.RemoteException {
     ctor public DeadObjectException();
     ctor public DeadObjectException(java.lang.String);
@@ -27898,6 +27907,18 @@
     method public boolean quitSafely();
   }
 
+  public class HardwarePropertiesManager {
+    method public android.os.CpuUsageInfo[] getCpuUsages();
+    method public float[] getDeviceTemperatures(int);
+    method public float[] getFanSpeeds();
+    field public static final int DEVICE_TEMPERATURE_BATTERY = 2; // 0x2
+    field public static final int DEVICE_TEMPERATURE_CPU = 0; // 0x0
+    field public static final int DEVICE_TEMPERATURE_GPU = 1; // 0x1
+  }
+
+  public static abstract class HardwarePropertiesManager.DeviceTemperatureType implements java.lang.annotation.Annotation {
+  }
+
   public abstract interface IBinder {
     method public abstract void dump(java.io.FileDescriptor, java.lang.String[]) throws android.os.RemoteException;
     method public abstract void dumpAsync(java.io.FileDescriptor, java.lang.String[]) throws android.os.RemoteException;
diff --git a/api/system-current.txt b/api/system-current.txt
index 6a36ce0..ab7b19b 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -8222,6 +8222,7 @@
     field public static final java.lang.String DOWNLOAD_SERVICE = "download";
     field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
     field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
+    field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardwareproperties";
     field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
     field public static final java.lang.String INPUT_SERVICE = "input";
@@ -29638,6 +29639,14 @@
     method public final synchronized android.os.CountDownTimer start();
   }
 
+  public final class CpuUsageInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getActive();
+    method public long getTotal();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.os.CpuUsageInfo> CREATOR;
+  }
+
   public class DeadObjectException extends android.os.RemoteException {
     ctor public DeadObjectException();
     ctor public DeadObjectException(java.lang.String);
@@ -29890,6 +29899,18 @@
     method public boolean quitSafely();
   }
 
+  public class HardwarePropertiesManager {
+    method public android.os.CpuUsageInfo[] getCpuUsages();
+    method public float[] getDeviceTemperatures(int);
+    method public float[] getFanSpeeds();
+    field public static final int DEVICE_TEMPERATURE_BATTERY = 2; // 0x2
+    field public static final int DEVICE_TEMPERATURE_CPU = 0; // 0x0
+    field public static final int DEVICE_TEMPERATURE_GPU = 1; // 0x1
+  }
+
+  public static abstract class HardwarePropertiesManager.DeviceTemperatureType implements java.lang.annotation.Annotation {
+  }
+
   public abstract interface IBinder {
     method public abstract void dump(java.io.FileDescriptor, java.lang.String[]) throws android.os.RemoteException;
     method public abstract void dumpAsync(java.io.FileDescriptor, java.lang.String[]) throws android.os.RemoteException;
diff --git a/api/test-current.txt b/api/test-current.txt
index 21b101f..daab1b3 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -7976,6 +7976,7 @@
     field public static final java.lang.String DOWNLOAD_SERVICE = "download";
     field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
     field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
+    field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardwareproperties";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
     field public static final java.lang.String INPUT_SERVICE = "input";
     field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
@@ -27654,6 +27655,14 @@
     method public final synchronized android.os.CountDownTimer start();
   }
 
+  public final class CpuUsageInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getActive();
+    method public long getTotal();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.os.CpuUsageInfo> CREATOR;
+  }
+
   public class DeadObjectException extends android.os.RemoteException {
     ctor public DeadObjectException();
     ctor public DeadObjectException(java.lang.String);
@@ -27906,6 +27915,18 @@
     method public boolean quitSafely();
   }
 
+  public class HardwarePropertiesManager {
+    method public android.os.CpuUsageInfo[] getCpuUsages();
+    method public float[] getDeviceTemperatures(int);
+    method public float[] getFanSpeeds();
+    field public static final int DEVICE_TEMPERATURE_BATTERY = 2; // 0x2
+    field public static final int DEVICE_TEMPERATURE_CPU = 0; // 0x0
+    field public static final int DEVICE_TEMPERATURE_GPU = 1; // 0x1
+  }
+
+  public static abstract class HardwarePropertiesManager.DeviceTemperatureType implements java.lang.annotation.Annotation {
+  }
+
   public abstract interface IBinder {
     method public abstract void dump(java.io.FileDescriptor, java.lang.String[]) throws android.os.RemoteException;
     method public abstract void dumpAsync(java.io.FileDescriptor, java.lang.String[]) throws android.os.RemoteException;
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 89d52f2..ea8d6bd 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -85,6 +85,7 @@
 import android.nfc.NfcManager;
 import android.os.BatteryManager;
 import android.os.DropBoxManager;
+import android.os.HardwarePropertiesManager;
 import android.os.IBinder;
 import android.os.IPowerManager;
 import android.os.IUserManager;
@@ -704,6 +705,12 @@
             public RadioManager createService(ContextImpl ctx) {
                 return new RadioManager(ctx);
             }});
+        registerService(Context.HARDWARE_PROPERTIES_SERVICE, HardwarePropertiesManager.class,
+                new CachedServiceFetcher<HardwarePropertiesManager>() {
+            @Override
+            public HardwarePropertiesManager createService(ContextImpl ctx) {
+                return new HardwarePropertiesManager();
+            }});
     }
 
     /**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 84f6f3d..a245706 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -48,6 +48,7 @@
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
+import android.os.HardwarePropertiesManager;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.StatFs;
@@ -2601,6 +2602,7 @@
             MEDIA_PROJECTION_SERVICE,
             MIDI_SERVICE,
             RADIO_SERVICE,
+            HARDWARE_PROPERTIES_SERVICE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ServiceName {}
@@ -2662,6 +2664,8 @@
      * <dt> {@link #NETWORK_STATS_SERVICE} ("netstats")
      * <dd> A {@link android.app.usage.NetworkStatsManager NetworkStatsManager} for querying network
      * usage statistics.
+     * <dt> {@link #HARDWARE_PROPERTIES_SERVICE} ("hardwareproperties")
+     * <dd> A {@link android.os.HardwarePropertiesManager} for accessing hardware properties.
      * </dl>
      *
      * <p>Note:  System services obtained via this API may be closely associated with
@@ -2723,6 +2727,8 @@
      * @see android.app.job.JobScheduler
      * @see #NETWORK_STATS_SERVICE
      * @see android.app.usage.NetworkStatsManager
+     * @see android.os.HardwarePropertiesManager
+     * @see #HARDWARE_PROPERTIES_SERVICE
      */
     public abstract Object getSystemService(@ServiceName @NonNull String name);
 
@@ -3465,6 +3471,14 @@
     public static final String RADIO_SERVICE = "radio";
 
     /**
+     * Use with {@link #getSystemService} to retrieve a
+     * {@link android.os.HardwarePropertiesManager} for accessing the hardware properties service.
+     *
+     * @see #getSystemService
+     */
+    public static final String HARDWARE_PROPERTIES_SERVICE = "hardwareproperties";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/os/CpuUsageInfo.java b/core/java/android/os/CpuUsageInfo.java
new file mode 100644
index 0000000..54caa15
--- /dev/null
+++ b/core/java/android/os/CpuUsageInfo.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package android.os;
+
+/**
+ * CPU usage information per core.
+ */
+public final class CpuUsageInfo implements Parcelable {
+    private long mActive;
+    private long mTotal;
+
+    public static final Parcelable.Creator<CpuUsageInfo> CREATOR = new
+            Parcelable.Creator<CpuUsageInfo>() {
+                    public CpuUsageInfo createFromParcel(Parcel in) {
+                        return new CpuUsageInfo(in);
+                    }
+
+                    public CpuUsageInfo[] newArray(int size) {
+                        return new CpuUsageInfo[size];
+                    }
+                };
+
+    /** @hide */
+    public CpuUsageInfo(long activeTime, long totalTime) {
+        mActive = activeTime;
+        mTotal = totalTime;
+    }
+
+    private CpuUsageInfo(Parcel in) {
+        readFromParcel(in);
+    }
+
+    /**
+     * Gets the active time in milliseconds since the system last booted.
+     *
+     * @return Active time in milliseconds.
+     */
+    public long getActive() {
+        return mActive;
+    }
+
+    /**
+     * Gets the total time in milliseconds that the CPU has been enabled since the system last
+     * booted. This includes time the CPU spent idle.
+     *
+     * @return Total time in milliseconds.
+     */
+    public long getTotal() {
+        return mTotal;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeLong(mActive);
+        out.writeLong(mTotal);
+    }
+
+    private void readFromParcel(Parcel in) {
+        mActive = in.readLong();
+        mTotal = in.readLong();
+    }
+}
diff --git a/core/java/android/os/HardwarePropertiesManager.java b/core/java/android/os/HardwarePropertiesManager.java
new file mode 100644
index 0000000..bc317b6
--- /dev/null
+++ b/core/java/android/os/HardwarePropertiesManager.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+package android.os;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+
+/**
+ * The HardwarePropertiesManager class provides a mechanism of accessing hardware state of a
+ * device: CPU, GPU and battery temperatures, CPU usage per core, fan speed, etc.
+ */
+public class HardwarePropertiesManager {
+
+    private static final String TAG = HardwarePropertiesManager.class.getSimpleName();
+
+    private static native void nativeInit();
+
+    private static native float[] nativeGetFanSpeeds();
+    private static native float[] nativeGetDeviceTemperatures(int type);
+    private static native CpuUsageInfo[] nativeGetCpuUsages();
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+        DEVICE_TEMPERATURE_CPU, DEVICE_TEMPERATURE_GPU, DEVICE_TEMPERATURE_BATTERY
+    })
+    public @interface DeviceTemperatureType {}
+
+    /**
+     * Device temperature types. These must match the values in
+     * frameworks/native/include/hardwareproperties/HardwarePropertiesManager.h
+     */
+    /** Temperature of CPUs in Celsius. */
+    public static final int DEVICE_TEMPERATURE_CPU = 0;
+
+    /** Temperature of GPUs in Celsius. */
+    public static final int DEVICE_TEMPERATURE_GPU = 1;
+
+    /** Temperature of battery in Celsius. */
+    public static final int DEVICE_TEMPERATURE_BATTERY = 2;
+
+    /** @hide */
+    public HardwarePropertiesManager() {
+        nativeInit();
+    }
+
+    /**
+     * Return an array of device temperatures in Celsius.
+     *
+     * @param type type of requested device temperature, one of {@link #DEVICE_TEMPERATURE_CPU},
+     * {@link #DEVICE_TEMPERATURE_GPU} or {@link #DEVICE_TEMPERATURE_BATTERY}.
+     * @return an array of requested float device temperatures.
+     *         Empty if platform doesn't provide the queried temperature.
+     *
+     * @throws IllegalArgumentException if an incorrect temperature type is queried.
+    */
+    public @NonNull float[] getDeviceTemperatures(@DeviceTemperatureType int type) {
+        switch (type) {
+        case DEVICE_TEMPERATURE_CPU:
+        case DEVICE_TEMPERATURE_GPU:
+        case DEVICE_TEMPERATURE_BATTERY:
+            return nativeGetDeviceTemperatures(type);
+        default:
+            throw new IllegalArgumentException();
+        }
+    }
+
+    /**
+     * Return an array of CPU usage info for each core.
+     *
+     * @return an array of {@link android.os.CpuUsageInfo} for each core.
+     *         Empty if CPU usage is not supported on this system.
+     */
+    public @NonNull CpuUsageInfo[] getCpuUsages() {
+        return nativeGetCpuUsages();
+    }
+
+    /**
+     * Return an array of fan speeds in RPM.
+     *
+     * @return an arrat of float fan speeds. Empty if there is no fans or fan speed
+     *         not supported on this system.
+     */
+    public @NonNull float[] getFanSpeeds() {
+        return nativeGetFanSpeeds();
+    }
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index fc1ba44..6e968ee 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -175,7 +175,8 @@
     com_android_internal_net_NetworkStatsFactory.cpp \
     com_android_internal_os_Zygote.cpp \
     com_android_internal_util_VirtualRefBasePtr.cpp \
-    com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
+    com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp \
+    android_os_HardwarePropertiesManager.cpp
 
 LOCAL_C_INCLUDES += \
     $(JNI_H_INCLUDE) \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 63f193d..fa1ccdb 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -196,6 +196,7 @@
 extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
 extern int register_com_android_internal_os_Zygote(JNIEnv *env);
 extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
+extern int register_android_os_HardwarePropertiesManager(JNIEnv *env);
 
 static AndroidRuntime* gCurRuntime = NULL;
 
@@ -1380,7 +1381,7 @@
     REG_JNI(register_android_animation_PropertyValuesHolder),
     REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
     REG_JNI(register_com_android_internal_net_NetworkStatsFactory),
-
+    REG_JNI(register_android_os_HardwarePropertiesManager),
 
 };
 
diff --git a/core/jni/android_os_HardwarePropertiesManager.cpp b/core/jni/android_os_HardwarePropertiesManager.cpp
new file mode 100644
index 0000000..dc1ba48
--- /dev/null
+++ b/core/jni/android_os_HardwarePropertiesManager.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2015 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 "HardwarePropertiesManager-JNI"
+
+#include "JNIHelp.h"
+#include "jni.h"
+
+#include <stdlib.h>
+
+#include <hardware/hardware_properties.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include <hardware_properties/HardwarePropertiesManager.h>
+
+#include "core_jni_helpers.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+static struct {
+    jclass clazz;
+    jmethodID initMethod;
+} gCpuUsageInfoClassInfo;
+
+static struct hardware_properties_module* gHardwarePropertiesModule;
+
+// ----------------------------------------------------------------------------
+
+static void nativeInit(JNIEnv* env, jobject obj) {
+    status_t err = hw_get_module(HARDWARE_PROPERTIES_HARDWARE_MODULE_ID,
+            (hw_module_t const**)&gHardwarePropertiesModule);
+    if (err) {
+        ALOGE("Couldn't load %s module (%s)", HARDWARE_PROPERTIES_HARDWARE_MODULE_ID,
+              strerror(-err));
+    }
+}
+
+static jfloatArray nativeGetFanSpeeds(JNIEnv *env, jclass /* clazz */) {
+    if (gHardwarePropertiesModule && gHardwarePropertiesModule->getFanSpeeds) {
+        float *speeds = nullptr;
+        ssize_t size = gHardwarePropertiesModule->getFanSpeeds(gHardwarePropertiesModule, &speeds);
+
+        if (speeds && size > 0) {
+            jfloatArray fanSpeeds = env->NewFloatArray(size);
+            env->SetFloatArrayRegion(fanSpeeds, 0, size, speeds);
+            free(speeds);
+            return fanSpeeds;
+        }
+
+        if (size < 0) {
+            ALOGE("Cloudn't get fan speeds because of HAL error");
+        }
+    }
+    return env->NewFloatArray(0);
+}
+
+static jfloatArray nativeGetDeviceTemperatures(JNIEnv *env, jclass /* clazz */, int type) {
+    if (gHardwarePropertiesModule) {
+        ssize_t size = 0;
+        float *temps = nullptr;
+        switch (type) {
+        case DEVICE_TEMPERATURE_CPU:
+            if (gHardwarePropertiesModule->getCpuTemperatures) {
+                size = gHardwarePropertiesModule->getCpuTemperatures(gHardwarePropertiesModule,
+                                                                     &temps);
+            }
+            break;
+        case DEVICE_TEMPERATURE_GPU:
+            if (gHardwarePropertiesModule->getGpuTemperatures) {
+                size = gHardwarePropertiesModule->getGpuTemperatures(gHardwarePropertiesModule,
+                                                                    &temps);
+            }
+            break;
+        case DEVICE_TEMPERATURE_BATTERY:
+            if (gHardwarePropertiesModule->getBatteryTemperatures) {
+                size = gHardwarePropertiesModule->getBatteryTemperatures(gHardwarePropertiesModule,
+                                                                        &temps);
+            }
+            break;
+        }
+        if (temps && size > 0) {
+            jfloatArray deviceTemps = env->NewFloatArray(size);
+            env->SetFloatArrayRegion(deviceTemps, 0, size, temps);
+            free(temps);
+            return deviceTemps;
+        }
+        if (size < 0) {
+            ALOGE("Couldn't get device temperatures type=%d because of HAL error", type);
+        }
+    }
+    return env->NewFloatArray(0);
+}
+
+static jobjectArray nativeGetCpuUsages(JNIEnv *env, jclass /* clazz */) {
+    if (gHardwarePropertiesModule && gHardwarePropertiesModule->getCpuUsages
+        && gCpuUsageInfoClassInfo.initMethod) {
+        int64_t *active_times = nullptr;
+        int64_t *total_times = nullptr;
+        ssize_t size = gHardwarePropertiesModule->getCpuUsages(gHardwarePropertiesModule,
+                                                               &active_times, &total_times);
+        if (active_times && total_times && size > 0) {
+            jobjectArray cpuUsages = env->NewObjectArray(size, gCpuUsageInfoClassInfo.clazz,
+                                                         nullptr);
+            for (ssize_t i = 0; i < size; ++i) {
+                jobject cpuUsage = env->NewObject(gCpuUsageInfoClassInfo.clazz,
+                                                  gCpuUsageInfoClassInfo.initMethod,
+                                                  active_times[i], total_times[i]);
+                env->SetObjectArrayElement(cpuUsages, i, cpuUsage);
+            }
+            free(active_times);
+            free(total_times);
+            return cpuUsages;
+        }
+
+        if (size < 0) {
+            ALOGE("Couldn't get CPU usages because of HAL error");
+        }
+    }
+    return env->NewObjectArray(0, gCpuUsageInfoClassInfo.clazz, nullptr);
+}
+
+// ----------------------------------------------------------------------------
+
+static const JNINativeMethod gHardwarePropertiesManagerMethods[] = {
+    /* name, signature, funcPtr */
+    { "nativeInit", "()V",
+            (void*) nativeInit },
+    { "nativeGetFanSpeeds", "()[F",
+            (void*) nativeGetFanSpeeds },
+    { "nativeGetDeviceTemperatures", "(I)[F",
+            (void*) nativeGetDeviceTemperatures },
+    { "nativeGetCpuUsages", "()[Landroid/os/CpuUsageInfo;",
+            (void*) nativeGetCpuUsages }
+};
+
+int register_android_os_HardwarePropertiesManager(JNIEnv* env) {
+    gHardwarePropertiesModule = nullptr;
+    int res = jniRegisterNativeMethods(env, "android/os/HardwarePropertiesManager",
+                                       gHardwarePropertiesManagerMethods,
+                                       NELEM(gHardwarePropertiesManagerMethods));
+    jclass clazz = env->FindClass("android/os/CpuUsageInfo");
+    gCpuUsageInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
+    gCpuUsageInfoClassInfo.initMethod = GetMethodIDOrDie(env, gCpuUsageInfoClassInfo.clazz,
+                                                         "<init>", "(JJ)V");
+    return res;
+}
+
+} /* namespace android */