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小节中详细介绍。
2.3.2 调用隐藏接口
在前面2.3.1的内容中,以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 + 0.5f) / 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"); }
从上述部分代码可以看出,在一些函数中广泛用到了BatteryStats类中的隐藏接口。首先调用隐藏接口来获取模块使用时间,然后再得到平均用电时间,经过一定的算法即可得出该模块的耗电情况。是如果没有这样的隐藏接口,计算耗电时间将是很麻烦的一件事,而且可能会用到源代码中更多我们没有权限去调用的代码,开发难度将会增加。