diff --git a/api/current.txt b/api/current.txt index 629d832c0c3cd..6b20e091ecc29 100644 --- a/api/current.txt +++ b/api/current.txt @@ -7972,6 +7972,7 @@ package android.content { 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 @@ package android.os { 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 CREATOR; + } + public class DeadObjectException extends android.os.RemoteException { ctor public DeadObjectException(); ctor public DeadObjectException(java.lang.String); @@ -27898,6 +27907,18 @@ package android.os { 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 6a36ce05acca2..ab7b19bdca09f 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -8222,6 +8222,7 @@ package android.content { 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 @@ package android.os { 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 CREATOR; + } + public class DeadObjectException extends android.os.RemoteException { ctor public DeadObjectException(); ctor public DeadObjectException(java.lang.String); @@ -29890,6 +29899,18 @@ package android.os { 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 21b101fef4499..daab1b38094f0 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -7976,6 +7976,7 @@ package android.content { 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 @@ package android.os { 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 CREATOR; + } + public class DeadObjectException extends android.os.RemoteException { ctor public DeadObjectException(); ctor public DeadObjectException(java.lang.String); @@ -27906,6 +27915,18 @@ package android.os { 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 89d52f248bded..ea8d6bd9fab70 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -85,6 +85,7 @@ import android.net.wifi.passpoint.WifiPasspointManager; 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 @@ final class SystemServiceRegistry { public RadioManager createService(ContextImpl ctx) { return new RadioManager(ctx); }}); + registerService(Context.HARDWARE_PROPERTIES_SERVICE, HardwarePropertiesManager.class, + new CachedServiceFetcher() { + @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 84f6f3da3edb1..a2457064e5cce 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -48,6 +48,7 @@ import android.net.Uri; 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 @@ public abstract class Context { MEDIA_PROJECTION_SERVICE, MIDI_SERVICE, RADIO_SERVICE, + HARDWARE_PROPERTIES_SERVICE, }) @Retention(RetentionPolicy.SOURCE) public @interface ServiceName {} @@ -2662,6 +2664,8 @@ public abstract class Context { *
{@link #NETWORK_STATS_SERVICE} ("netstats") *
A {@link android.app.usage.NetworkStatsManager NetworkStatsManager} for querying network * usage statistics. + *
{@link #HARDWARE_PROPERTIES_SERVICE} ("hardwareproperties") + *
A {@link android.os.HardwarePropertiesManager} for accessing hardware properties. * * *

Note: System services obtained via this API may be closely associated with @@ -2723,6 +2727,8 @@ public abstract class Context { * @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); @@ -3464,6 +3470,14 @@ public abstract class Context { */ 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 0000000000000..54caa15343f14 --- /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 CREATOR = new + Parcelable.Creator() { + 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 0000000000000..bc317b672d9cf --- /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 fc1ba44394435..6e968ee6c9972 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -175,7 +175,8 @@ LOCAL_SRC_FILES:= \ 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 63f193d57419c..fa1ccdb127ba9 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -196,6 +196,7 @@ extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env 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 @@ static const RegJNIRec gRegJNI[] = { 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 0000000000000..dc1ba48097b8f --- /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 + +#include +#include +#include + +#include + +#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, + "", "(JJ)V"); + return res; +} + +} /* namespace android */