本节书摘来自异步社区《深入理解Android 5 源代码》一书中的第2章,第2.3节Android源代码提供的接口,作者 李骏,更多章节内容可以访问云栖社区“异步社区”公众号查看
2.3 Android源代码提供的接口
我们知道,Android源代码当中提供了很多资源、工具或者文档供开发者使用,当然,其中也包括应用程序开发接口的实现,也就是我们开发应用程序所使用的SDK的API。正是由于有了这些种类丰富、功能强大、抽象程度高的接口,才让我们开发应用程序变得简单方便。在本节的内容中,将详细讲解Android系统中这些接口的基本知识。
2.3.1 暴露接口和隐藏接口
我们可以将Android源代码编译生成一个SDK,这个SDK的功能等同于官方网站上单独下载的SDK开发包。这说明在Android源代码中存在SDK的实现代码,不仅可以提供与独立SDK相同的API接口,而且会有一些SDK开发包中不具备的API接口。当然,这部分隐藏的接口在基于SDK开发的时候是看不到的,只有在基于源代码开发或者往独立的SDK中“增加”隐藏接口的时候才能调用到。
究竟源代码中的哪些接口是暴露接口,哪些接口是隐藏接口呢?比如要做一个统计电量消耗信息的应用程序,以及WiFi或者蓝牙的打开时间,在SDK中是没有直接相关的接口来调用的。当然通过其他途径可以找到很多种方法来满足这个需求,这里我们讲解怎么用源代码中的隐藏接口来实现这些功能。
在源代码路径/frameworks/base/core/java/android/os目录下,存在两个电池相关的文件:BatteryStats.java和BatteryStatsImpl.java,其中前者声明了一个与电池相关的抽象类BatteryStats,后者继承了BatteryStats,并实现了里面的方法。下面来看文件BatteryStats.java中的抽象类,在这个类中定义了很多变量来记录系统功能的状态变化,例如:
WiFi开关;
蓝牙开关;
音频打开;
视频打开;
上次充电时刻。
上述信息用来计算各个模块的电量消耗情况,同时在里面也定义了其他的抽象类,里面的抽象接口都可以用来计算电量消耗,文件BatteryStats.java的代码如下所示:
public abstract class BatteryStats implements Parcelable {
/*省略部分代码*/
//WIFI开启时间
public static final int WIFI_RUNNING = 4;
//WIFI完全锁定时间
public static final int FULL_WIFI_LOCK = 5;
//WIFI扫描时间
public static final int WIFI_SCAN = 6;
//WIFI其他功能开启时间
public static final int WIFI_MULTICAST_ENABLED = 7;
//音频开启时间
public static final int AUDIO_TURNED_ON = 7;
//视频开启时间
public static final int VIDEO_TURNED_ON = 8;
//系统状态自从上次变化到现在
public static final int STATS_SINCE_CHARGED = 0;
//上一次的系统状态
public static final int STATS_LAST = 1;
//现在的系统状态
public static final int STATS_CURRENT = 2;
//从上次拔下设备到现在的状态
public static final int STATS_SINCE_UNPLUGGED = 3;
/*省略部分代码*/
public static abstract class Uid {
//得到相关联UID锁屏状态
public abstract Map<String, ? extends Wakelock> getWakelockStats();
public static abstract class Wakelock {
public abstract Timer getWakeTime(int type);
}
//得到相关联UID的传感器状态
public abstract Map<Integer, ? extends Sensor> getSensorStats();
//得到Pid状态
public abstract SparseArray<? extends Pid> getPidStats();
//得到进程状态
public abstract Map<String, ? extends Proc> getProcessStats();
//得到包状态
public abstract Map<String, ? extends Pkg> getPackageStats();
/**
* 得到Uid
* {@hide}
*/
public abstract int getUid();
/**
* 得到Tcp接收到的字节数
* {@hide}
*/
public abstract long getTcpBytesReceived(int which);
/**
* 得到Tcp发出的字节数
* {@hide}
*/
public abstract long getTcpBytesSent(int which);
//记录WiFi运行时刻
public abstract void noteWifiRunningLocked();
//记录WiFi停止时刻
public abstract void noteWifiStoppedLocked();
public abstract void noteFullWifiLockAcquiredLocked();
public abstract void noteFullWifiLockReleasedLocked();
public abstract void noteWifiScanStartedLocked();
public abstract void noteWifiScanStoppedLocked();
public abstract void noteWifiMulticastEnabledLocked();
public abstract void noteWifiMulticastDisabledLocked();
public abstract void noteAudioTurnedOnLocked();
public abstract void noteAudioTurnedOffLocked();
public abstract void noteVideoTurnedOnLocked();
public abstract void noteVideoTurnedOffLocked();
//得到WiFi运行时间
public abstract long getWifiRunningTime(long batteryRealtime, int which);
//得到WiFi锁定时间
public abstract long getFullWifiLockTime(long batteryRealtime, int which);
//得到WiFi扫描时间
public abstract long getWifiScanTime(long batteryRealtime, int which);
//得到WiFi其他功能开启时间
public abstract long getWifiMulticastTime(long batteryRealtime,
int which);
//得到音频开启时间
public abstract long getAudioTurnedOnTime(long batteryRealtime, int which);
//得到视频开启时间
public abstract long getVideoTurnedOnTime(long batteryRealtime, int which);
static final String[] USER_ACTIVITY_TYPES = {
"other", "button", "touch"
};
public static final int NUM_USER_ACTIVITY_TYPES = 3;
public abstract void noteUserActivityLocked(int type);
public abstract boolean hasUserActivity();
public abstract int getUserActivityCount(int type, int which);
//传感器抽象类
public static abstract class Sensor {
public static final int GPS = -10000;
public abstract int getHandle();
public abstract Timer getSensorTime();
}
//Pid类
public class Pid {
public long mWakeSum;
public long mWakeStart;
}
//进程相关类
public static abstract class Proc {
public static class ExcessivePower {
//唤醒方式
public static final int TYPE_WAKE = 1;
//CPU类型
public static final int TYPE_CPU = 2;
public int type;
public long overTime;
public long usedTime;
}
//得到用户时间
public abstract long getUserTime(int which);
//得到系统时间
public abstract long getSystemTime(int which);
//得到状态
public abstract int getStarts(int which);
//得到CPU在前台运行的时间
public abstract long getForegroundTime(int which);
//得到CPU的速度等级
public abstract long getTimeAtCpuSpeedStep(int speedStep, int which);
//得到剩余的电量
public abstract int countExcessivePowers();
public abstract ExcessivePower getExcessivePower(int i);
}
}
/*省略部分代码*/
/** 得到屏幕点亮的时间
* {@hide}
*/
public abstract long getScreenOnTime(long batteryRealtime, int which);
/** 根据屏幕点亮的等级,得到相应时间
* {@hide}
*/
public abstract long getScreenBrightnessTime(int brightnessBin,
long batteryRealtime, int which);
/**
* 得到用电池的时候电话运行时的时间
* {@hide}
*/
public abstract long getPhoneOnTime(long batteryRealtime, int which);
/**
* 得到手机处于不同信号强度的时间
* {@hide}
*/
public abstract long getPhoneSignalStrengthTime(int strengthBin,
long batteryRealtime, int which);
/**
* 得到手机扫描信号用掉的时间
* {@hide}
*/
public abstract long getPhoneSignalScanningTime(
long batteryRealtime, int which);
/**
* 得到手机扫描到不同信号强度用掉的时间
* {@hide}
*/
public abstract int getPhoneSignalStrengthCount(int strengthBin, int which);
/**
* 得到手机不同数据连接消耗的时间
* {@hide}
*/
public abstract long getPhoneDataConnectionTime(int dataType,
long batteryRealtime, int which);
/**
* 得到手机进入到不同数据连接所消耗的时间
* {@hide}
*/
public abstract int getPhoneDataConnectionCount(int dataType, int which);
/**
* 得到手机处于WiFi打开的状态的时间
* {@hide}
*/
public abstract long getWifiOnTime(long batteryRealtime, int which);
/**
* 得到手机处于WiFi打开的状态并且驱动层的WiFi也处于打开状态时的时间
* {@hide}
*/
public abstract long getGlobalWifiRunningTime(long batteryRealtime, int which);
/**
* 得到手机蓝牙处于打开状态时的时间
* {@hide}
*/
public abstract long getBluetoothOnTime(long batteryRealtime, int which);
}
``
从上面的源代码可以看出,在文件BatteryStats.java中定义了很多与电池电量和系统状态相关的函数和变量,有一些函数在声明时加上了@hide字样,说明这些接口因为不稳定或者其他方面的原因暂时被Google隐藏了,不能通过SDK进行访问,可能会在以后的版本中开放。
对于那些没有标记@hide接口的函数,则不属于Google官方声明的隐藏接口,但是同样可以将其看成是隐藏的,只不过Google短期内或者一直都不会将其开放,所以不会特别进行维护,其形式与有@hide的隐藏接口一致。
看完文件BatteryStats.java中定义的隐藏接口后,接下来看看文件BatteryStatsImpl.java,在此文件中继承了BatteryStats抽象类,对BatteryStats中的很多隐藏方法进行了实现,其具体代码如下所示:
public final class BatteryStatsImpl extends BatteryStats {
/省略了部分代码/
@Override
public int getUid() {
return mUid;
}
@Override
public long getTcpBytesReceived(int which) {
if (which == STATS_LAST) {
return mLoadedTcpBytesReceived;
} else {
long current = computeCurrentTcpBytesReceived();
if (which == STATS_SINCE_UNPLUGGED) {
current -= mTcpBytesReceivedAtLastUnplug;
} else if (which == STATS_SINCE_CHARGED) {
current += mLoadedTcpBytesReceived;
}
return current;
}
}
@Override
public long getTcpBytesSent(int which) {
if (which == STATS_LAST) {
return mLoadedTcpBytesSent;
} else {
long current = computeCurrentTcpBytesSent();
if (which == STATS_SINCE_UNPLUGGED) {
current -= mTcpBytesSentAtLastUnplug;
} else if (which == STATS_SINCE_CHARGED) {
current += mLoadedTcpBytesSent;
}
return current;
}
}
@Override public long getScreenOnTime(long batteryRealtime, int which) {
return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which);
}
@Override public long getScreenBrightnessTime(int brightnessBin,
long batteryRealtime, int which) {
return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked(
batteryRealtime, which);
}
@Override public long getPhoneOnTime(long batteryRealtime, int which) {
return mPhoneOnTimer.getTotalTimeLocked(batteryRealtime, which);
}
@Override public long getPhoneSignalStrengthTime(int strengthBin,
long batteryRealtime, int which) {
return mPhoneSignalStrengthsTimer[strengthBin].getTotalTimeLocked(
batteryRealtime, which);
}
@Override public long getPhoneSignalScanningTime(
long batteryRealtime, int which) {
return mPhoneSignalScanningTimer.getTotalTimeLocked(
batteryRealtime, which);
}
@Override public int getPhoneSignalStrengthCount(int strengthBin, int which){
return mPhoneSignalStrengthsTimer[strengthBin].getCountLocked(which);
}
@Override public long getPhoneDataConnectionTime(int dataType,
long batteryRealtime, int which) {
return mPhoneDataConnectionsTimer[dataType].getTotalTimeLocked(
batteryRealtime, which);
}
@Override public int getPhoneDataConnectionCount(int dataType, int which) {
return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
}
@Override public long getWifiOnTime(long batteryRealtime, int which) {
return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which);
}
@Override public long getGlobalWifiRunningTime(long batteryRealtime, int
which) {
return mGlobalWifiRunningTimer.getTotalTimeLocked(batteryRealtime,
which);
}
@Override public long getBluetoothOnTime(long batteryRealtime, int which) {
return mBluetoothOnTimer.getTotalTimeLocked(batteryRealtime, which);
}
}
在上述代码中,BatteryStatsImpl继承了类BatteryStats,然后实现了其中的隐藏接口,这样当进行应用程序开发时就可以使用这些还未开放的隐藏接口了,具体使用隐藏接口的方法将在小节中详细介绍。
**2.3.2 调用隐藏接口**
在前面的内容中,以BatteryStats这个类为例详细分析了Android中存在的隐藏接口。在接下来的内容中,将分析在源代码中使用这些隐藏接口的方法,然后分析在应用程序开发过程中调用隐藏接口的方法。
Android系统中在Settings程序中使用类BatteryStats,主要用来统计一些系统功能模块的工作时间和耗电情况。Settings中使用BatteryStats类的是文件PowerUsageSummary.java,其存放路径为:
/packages/apps/settings/src/com/android/settings/fuelgauge
文件PowerUsageSummary.java的主要功能是统计系统中的电量信息,在此用到了一些BatteryStats类中的隐藏接口,下面具体分析其实现代码,其中部分典型代码如下所示:
public class PowerUsageSummary extends PreferenceFragment implements Runnable {
/*省略部分代码*/
//定义了BatteryStats相关的3个对象,涉及到跨进程通信
private static BatteryStatsImpl sStatsXfer;
IBatteryStats mBatteryInfo;
BatteryStatsImpl mStats;
//在onCreate中初始化mBatteryInfo对象
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
if (icicle != null) {
//对mStats对象赋值
mStats = sStatsXfer;
}
addPreferencesFromResource(R.xml.power_usage_summary);
//初始化mBatteryInfo对象
mBatteryInfo = IBatteryStats.Stub.asInterface(
ServiceManager.getService("batteryinfo"));
mUm =(UserManager)getActivity().getSystemService(Context.USER_SERVICE);
mAppListGroup = (PreferenceGroup) findPreference(KEY_APP_LIST);
mBatteryStatusPref = mAppListGroup.findPreference(KEY_BATTERY_STATUS);
mPowerProfile = new PowerProfile(getActivity());
setHasOptionsMenu(true);
}
private void addPhoneUsage(long uSecNow) {
long phoneOnTimeMs = mStats.getPhoneOnTime(uSecNow, mStatsType) / 1000;
double phoneOnPower = mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ ACTIVE)
* phoneOnTimeMs / 1000;
addEntry(getActivity().getString(R.string.power_phone), DrainType.PHONE,
phoneOnTimeMs, R.drawable.ic_settings_voice_calls, phoneOnPower);
}
}
//当mStats没有初始化时则通过Parcel接口继续初始化
private void load() {
try {
byte[] data = mBatteryInfo.getStatistics();
Parcel parcel = Parcel.obtain();
parcel.unmarshall(data, 0, data.length);
parcel.setDataPosition(0);
mStats = com.android.internal.os.BatteryStatsImpl.CREATOR
.createFromParcel(parcel);
mStats.distributeWorkLocked(BatteryStats.STATS_SINCE_CHARGED);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException:", e);
}
}
//得到屏幕的使用时间和耗电情况
private void addScreenUsage(long uSecNow) {
double power = 0;
// getScreenOnTime()为BatteryStats中的隐藏接口
long screenOnTimeMs = mStats.getScreenOnTime(uSecNow, mStatsType) / 1000;
power += screenOnTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_ SCREEN_ON);
final double screenFullPower =
mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL);
for (int i = 0; i < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; i++) {
double screenBinPower = screenFullPower * (i + )
/ BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS;
// getScreenBrightnessTime为BatteryStats中的隐藏接口
long brightnessTime = mStats.getScreenBrightnessTime(i, uSecNow,
mStatsType) / 1000;
power += screenBinPower * brightnessTime;
if (DEBUG) {
Log.i(TAG, "Screen bin power = " + (int) screenBinPower +
", time = " + brightnessTime);
}
}
power /= 1000;
addEntry(getActivity().getString(R.string.power_screen),
DrainType.SCREEN, screenOnTimeMs, R.drawable.ic_settings_display, power);
}
//得到Wifi的使用时间和耗电情况
private void addWiFiUsage(long uSecNow) {
// getWifiOnTime为BatteryStats中的隐藏接口
long onTimeMs = mStats.getWifiOnTime(uSecNow, mStatsType) / 1000;
// getGlobalWifiRunningTime为BatteryStats中的隐藏接口
long runningTimeMs = mStats.getGlobalWifiRunningTime(uSecNow, mStatsType) / 1000;
if (DEBUG) Log.i(TAG, "WIFI runningTime=" + runningTimeMs
+ " app runningTime=" + mAppWifiRunning);
runningTimeMs -= mAppWifiRunning;
if (runningTimeMs < 0) runningTimeMs = 0;
double wifiPower = (onTimeMs * 0 /* TODO */
* mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)
+ runningTimeMs *
mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) / 1000;
if (DEBUG) Log.i(TAG, "WIFI power=" + wifiPower + " from procs=" +
mWifiPower);
BatterySipper bs=addEntry(getActivity().getString(R.string.power_wifi),
DrainType.WIFI,
runningTimeMs, R.drawable.ic_settings_wifi, wifiPower + mWifiPower);
aggregateSippers(bs, mWifiSippers, "WIFI");
}
//得到蓝牙的使用时间和耗电情况
private void addBluetoothUsage(long uSecNow) {
// getBluetoothOnTime为BatteryStats中的隐藏接口
long btOnTimeMs = mStats.getBluetoothOnTime(uSecNow, mStatsType) / 1000;
double btPower = btOnTimeMs *
mPowerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_ON)
/ 1000;
// getBluetoothPingCount为BatteryStats中的隐藏接口
int btPingCount = mStats.getBluetoothPingCount();
btPower += (btPingCount *
mPowerProfile.getAveragePower(PowerProfile.POWER_BLUETOOTH_AT_CMD)) / 1000;
BatterySipper bs = addEntry(getActivity().getString(R.string.power_bluetooth),
DrainType.BLUETOOTH, btOnTimeMs,
R.drawable.ic_settings_bluetooth, btPower + mBluetoothPower);
aggregateSippers(bs, mBluetoothSippers, "Bluetooth");
}