深入理解Android 5 源代码
上QQ阅读APP看书,第一时间看更新

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类中的隐藏接口。首先调用隐藏接口来获取模块使用时间,然后再得到平均用电时间,经过一定的算法即可得出该模块的耗电情况。是如果没有这样的隐藏接口,计算耗电时间将是很麻烦的一件事,而且可能会用到源代码中更多我们没有权限去调用的代码,开发难度将会增加。