Android中App耗电量统计核心函数注解

android8.0中:Settings->Battery一直显示Battery usage data isn’t availa(不显示apk耗电百分比) 代码路径在包/应用/设置/ SRC / COM /机器人/设置/ fuelgauge / PowerUsageSummary.java  每次进这个界面都会走refreshUi(),看里面的实现发现averagePower一直返回0.1,不管你电池用了多久。所以下面的代码都不会走,就不会显示应用程序用电量。 protected void refreshUi() { final... 阅读详情

    本文针对Android 5.0 以及以版本,对APP耗电量统计的核心函数,processAppUsage 进行解读,代码中增加了大量注释以及笔者个人的理解。

    

private void processAppUsage(SparseArray<UserHandle> asUsers) {
        final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null);
        SensorManager sensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);

        final int which = mStatsType;
        final int speedSteps = mPowerProfile.getNumSpeedSteps();            //获取CPU可以运转到在几种频率之下
        final double[] powerCpuNormal = new double[speedSteps];
        final long[] cpuSpeedStepTimes = new long[speedSteps];

        /**
         * 根据几种不同的频率,获取每个频率的平均电流值
         */
        for (int p = 0; p < speedSteps; p++) {
            powerCpuNormal[p] = mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_ACTIVE, p);
        }

        final double mobilePowerPerPacket = getMobilePowerPerPacket();        //移动数据流量功耗
        final double mobilePowerPerMs = getMobilePowerPerMs();                //数据连通网络时候的功耗
        final double wifiPowerPerPacket = getWifiPowerPerPacket();            //Wifi传输功耗

        long appWakelockTimeUs = 0;
        BatterySipper osApp = null;
        mStatsPeriod = mTypeBatteryRealtime;
        /**
         * SparseArray代替HashMap,效率更高,SpareArray用的是稀疏矩阵的方式
         */
        SparseArray<? extends Uid> uidStats = mStats.getUidStats();           //获取每一个uid的数据

        final int NU = uidStats.size();

        for (int iu = 0; iu < NU; iu++) {
            Uid u = uidStats.valueAt(iu);
            double p;                                                           // in mAs
            double power = 0;                                                   // in mAs
            double highestDrain = 0;
            String packageWithHighestDrain = null;

            Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();

            long cpuTime = 0;
            long cpuFgTime = 0;
            long wakelockTime = 0;
            long gpsTime = 0;

            if (processStats.size() > 0) {
                // Process CPU time
                for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
                        : processStats.entrySet()) {

                    Uid.Proc ps = ent.getValue();
                    /**
                     * 分别获取该进程,执行User的代码、执行系统级别的代码,以及在前段运行的时间
                     */
                    final long userTime = ps.getUserTime(which);
                    final long systemTime = ps.getSystemTime(which);
                    final long foregroundTime = ps.getForegroundTime(which);

                    cpuFgTime += foregroundTime * 10;                           // convert to millis,转化为毫秒

                    final long tmpCpuTime = (userTime + systemTime) * 10;       // convert to millis

                    int totalTimeAtSpeeds = 0;
                    /**
                     * 根据CPU所可以运行的几种频率,得到每种不同的频率下的改进程所消耗的时间
                     */
                    for (int step = 0; step < speedSteps; step++) {
                        cpuSpeedStepTimes[step] = ps.getTimeAtCpuSpeedStep(step, which);
                        totalTimeAtSpeeds += cpuSpeedStepTimes[step];
                    }
                    if (totalTimeAtSpeeds == 0) totalTimeAtSpeeds = 1;
                    /**
                     * 计算出每个CPU频率所消耗的时间,占总消耗时间的百分比,为什么要计算百分比?
                     */
                    double processPower = 0;
                    for (int step = 0; step < speedSteps; step++) {
                        double ratio = (double) cpuSpeedStepTimes[step] / totalTimeAtSpeeds;
                        if (DEBUG && ratio != 0) Log.d(TAG, "UID " + u.getUid() + ": CPU step #"
                                + step + " ratio=" + makemAh(ratio) + " power="
                                + makemAh(ratio*tmpCpuTime*powerCpuNormal[step] / (60*60*1000)));

                        processPower += ratio * tmpCpuTime * powerCpuNormal[step];
                    }

                    cpuTime += tmpCpuTime;                                                  //CPU时间

                    if (DEBUG && processPower != 0) {
                        Log.d(TAG, String.format("process %s, cpu power=%s",
                                ent.getKey(), makemAh(processPower / (60*60*1000))));
                    }
                    power += processPower;                                                  //总电量消耗加上该uid进程的消耗

                    if (packageWithHighestDrain == null
                            || packageWithHighestDrain.startsWith("*")) {
                        highestDrain = processPower;
                        packageWithHighestDrain = ent.getKey();
                    } else if (highestDrain < processPower
                            && !ent.getKey().startsWith("*")) {
                        highestDrain = processPower;
                        packageWithHighestDrain = ent.getKey();
                    }
                }
            }
            if (cpuFgTime > cpuTime) {
                if (DEBUG && cpuFgTime > cpuTime + 10000) {
                    Log.d(TAG, "WARNING! Cputime is more than 10 seconds behind Foreground time");
                }
                cpuTime = cpuFgTime;                            // Statistics may not have been gathered yet.数据还没有聚合??
            }
            /**
             * //该进程CPU所消耗的时间统计结束
             * 这里 60*60*1000 是将能量转化为 毫安时,得到的结果是 毫秒*毫安
             */
            power /= (60*60*1000);

            /**
             * // Process wake lock usage
             * 该进程所持有的Wakelock而消耗的电量,一个进程可能持有多个Wakelock
             */
            Map<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats = u.getWakelockStats();
            for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> wakelockEntry
                    : wakelockStats.entrySet()) {
                Uid.Wakelock wakelock = wakelockEntry.getValue();
                // Only care about partial wake locks since full wake locks
                // are canceled when the user turns the screen off.
                /**
                 * 这里只关心Patrial的Wakelock,因为 fullwakelock 在屏幕灭的时候 已经被取消
                 * 通过该循环,可以得到该进程所持有的所有Wakelock的时间
                 */
                BatteryStats.Timer timer = wakelock.getWakeTime(BatteryStats.WAKE_TYPE_PARTIAL);
                if (timer != null) {
                    wakelockTime += timer.getTotalTimeLocked(mRawRealtime, which);
                }
            }
            appWakelockTimeUs += wakelockTime;                      //得到的结果是微秒的形式
            wakelockTime /= 1000;                                   // convert to millis,转化为毫秒

            // Add cost of holding a wake lock
            /**
             * 计算得到持有Wakelock所消耗的电量,电流值为CPU醒着时候的电流值
             */
            p = (wakelockTime
                    * mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_AWAKE)) / (60*60*1000);
            if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": wake "
                    + wakelockTime + " power=" + makemAh(p));

            power += p;

            // Add cost of mobile traffic
            /**
             * 计算手机的数据流量,即使用 3G/4G 网络的流量数量
             */
            final long mobileRx = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, mStatsType);
            final long mobileTx = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, mStatsType);
            final long mobileRxB = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, mStatsType);
            final long mobileTxB = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, mStatsType);

            /**
             * 手机连通网络的时间
             */
            final long mobileActive = u.getMobileRadioActiveTime(mStatsType);

            if (mobileActive > 0) {
                // We are tracking when the radio is up, so can use the active time to
                // determine power use.
                /**
                 * 当监控的时候,网络已经连通,所以可以直接用网络连通的时间,来确定功耗值
                 */
                mAppMobileActive += mobileActive;
                p = (mobilePowerPerMs * mobileActive) / 1000;
            } else {
                // We are not tracking when the radio is up, so must approximate power use
                // based on the number of packets.
                /**
                 * 监控的时候,手机网络没有连通,那么就用流量值*流量电流 来估算出功耗
                 */
                p = (mobileRx + mobileTx) * mobilePowerPerPacket;
            }
            if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": mobile packets "
                    + (mobileRx+mobileTx) + " active time " + mobileActive
                    + " power=" + makemAh(p));

            power += p;

            // Add cost of wifi traffic
            /**
             * WIFI的数据流量功耗,与计算手机数据流量的方式类似
             */
            final long wifiRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, mStatsType);
            final long wifiTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, mStatsType);
            final long wifiRxB = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, mStatsType);
            final long wifiTxB = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, mStatsType);

            p = (wifiRx + wifiTx) * wifiPowerPerPacket;

            if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": wifi packets "
                    + (mobileRx+mobileTx) + " power=" + makemAh(p));

            power += p;

            // Add cost of keeping WIFI running.
            /**
             * WIFI打开时候的功耗,打开WIFI,WIFI并没有其他运作
             */
            long wifiRunningTimeMs = u.getWifiRunningTime(mRawRealtime, which) / 1000;
            mAppWifiRunning += wifiRunningTimeMs;
            p = (wifiRunningTimeMs
                    * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) / (60*60*1000);
            if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": wifi running "
                    + wifiRunningTimeMs + " power=" + makemAh(p));

            power += p;

            // Add cost of WIFI scans
            /**
             * WIFI扫描时候的功耗
             */
            long wifiScanTimeMs = u.getWifiScanTime(mRawRealtime, which) / 1000;
            p = (wifiScanTimeMs
                    * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_SCAN)) / (60*60*1000);
            if (DEBUG) Log.d(TAG, "UID " + u.getUid() + ": wifi scan " + wifiScanTimeMs
                    + " power=" + makemAh(p));
            power += p;

            /**
             * WIFI 批量扫描模式所造成的功耗
             */
            for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) {
                long batchScanTimeMs = u.getWifiBatchedScanTime(bin, mRawRealtime, which) / 1000;
                p = ((batchScanTimeMs
                        * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN, bin))
                    ) / (60*60*1000);
                if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": wifi batched scan # " + bin
                        + " time=" + batchScanTimeMs + " power=" + makemAh(p));
                power += p;
            }

            // Process Sensor usage
            /**
             * 进程使用传感器造成的功耗
             * 这里用SpareArray来存储
             */
            SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
            int NSE = sensorStats.size();

            for (int ise=0; ise<NSE; ise++) {
                Uid.Sensor sensor = sensorStats.valueAt(ise);                   //获取Sensor类型所对应的实体
                int sensorHandle = sensorStats.keyAt(ise);                      //获取Sensor的类型

                /**
                 * 该Sensor所消耗的时间
                 */
                BatteryStats.Timer timer = sensor.getSensorTime();
                long sensorTime = timer.getTotalTimeLocked(mRawRealtime, which) / 1000;

                /**
                 * 对GPS区别对待,貌似GPS的平均电流值,可以在PowerProfile中得到,而其他Sensor的平均
                 * 电流值,通过SensorManager获取,每个Sensor的型号功能不同,其电流值应该是做在驱动层
                 */
                double multiplier = 0;
                switch (sensorHandle) {
                    case Uid.Sensor.GPS:
                        multiplier = mPowerProfile.getAveragePower(PowerProfile.POWER_GPS_ON);
                        gpsTime = sensorTime;
                        break;
                    default:
                        List<Sensor> sensorList = sensorManager.getSensorList(
                                android.hardware.Sensor.TYPE_ALL);
                        for (android.hardware.Sensor s : sensorList) {
                            if (s.getHandle() == sensorHandle) {
                                multiplier = s.getPower();
                                break;
                            }
                        }
                }
                p = (multiplier * sensorTime) / (60*60*1000);
                if (DEBUG && p != 0) Log.d(TAG, "UID " + u.getUid() + ": sensor #" + sensorHandle
                        + " time=" + sensorTime + " power=" + makemAh(p));
                power += p;
            }

            if (DEBUG && power != 0) Log.d(TAG, String.format("UID %d: total power=%s",
                    u.getUid(), makemAh(power)));

            // Add the app to the list if it is consuming power
            /**
             * 如果该应用消耗的电量,就把它增加到列表中
             */
            final int userId = UserHandle.getUserId(u.getUid());

            if (power != 0 || u.getUid() == 0) {
                BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u,
                        new double[] {power});
                app.cpuTime = cpuTime;
                app.gpsTime = gpsTime;
                app.wifiRunningTime = wifiRunningTimeMs;
                app.cpuFgTime = cpuFgTime;
                app.wakeLockTime = wakelockTime;
                app.mobileRxPackets = mobileRx;
                app.mobileTxPackets = mobileTx;
                app.mobileActive = mobileActive / 1000;
                app.mobileActiveCount = u.getMobileRadioActiveCount(mStatsType);
                app.wifiRxPackets = wifiRx;
                app.wifiTxPackets = wifiTx;
                app.mobileRxBytes = mobileRxB;
                app.mobileTxBytes = mobileTxB;
                app.wifiRxBytes = wifiRxB;
                app.wifiTxBytes = wifiTxB;
                app.packageWithHighestDrain = packageWithHighestDrain;

                /**
                 * 对 WIFI 支持进程 和 蓝牙服务进程 区别对待,加入相应的列表中
                 */
                if (u.getUid() == Process.WIFI_UID) {                       //wifi 支持进程
                    mWifiSippers.add(app);
                    mWifiPower += power;
                } else if (u.getUid() == Process.BLUETOOTH_UID) {           //蓝牙服务进程
                    mBluetoothSippers.add(app);
                    mBluetoothPower += power;
                }
                /**
                 * Android 5.0 以后是多用户系统,这里要对用户做一些判别操作
                 */
                else if (!forAllUsers && asUsers.get(userId) == null
                        && UserHandle.getAppId(u.getUid()) >= Process.FIRST_APPLICATION_UID) {
                    List<BatterySipper> list = mUserSippers.get(userId);
                    /**
                     * 不同用户,拥有不同的app列表,要根据userId获取到应用列表,如果没有列表则新建,
                     * 然后在此用户下的应用列表中添加app
                     */
                    if (list == null) {
                        list = new ArrayList<BatterySipper>();
                        mUserSippers.put(userId, list);
                    }

                    list.add(app);

                    /**
                     *  在对不同用户的所在的app消耗的功耗进行统计
                     */
                    if (power != 0) {
                        Double userPower = mUserPower.get(userId);
                        if (userPower == null) {
                            userPower = power;
                        } else {
                            userPower += power;
                        }
                        mUserPower.put(userId, userPower);
                    }
                }
                /**
                 * 不区分用户的情况,则直接相加
                 */
                else {
                    mUsageList.add(app);
                    if (power > mMaxPower) mMaxPower = power;
                    if (power > mMaxRealPower) mMaxRealPower = power;
                    mComputedPower += power;
                }
                if (u.getUid() == 0) {
                    osApp = app;                        //Android 的系统 app
                }
            }
        }

        // The device has probably been awake for longer than the screen on
        // time and application wake lock time would account for.  Assign
        // this remainder to the OS, if possible.
        /**
         * 设备在灭屏之后,可能也依旧处于唤醒状态,所以设备的实际唤醒时间要比屏幕亮着的总体时间要长
         * 这个原因就是Wakelock引起的,笔者根据代码理解,应该是将释放Wakelock的时间归结为系统所消耗
         * 的时间,这部分时间算在系统头上
         *
         */
        if (osApp != null) {
            long wakeTimeMillis = mBatteryUptime / 1000;
            /**
             * wakeTimeMillis的值查阅源代码的 英文翻译过来是 当前电池正在运行的时间
             * 电池所运行的时间,减去应用占据Wakelock的时间 再减去屏幕亮起的时间
             * 剩下的时间,就是要额外计算的,就是不算app所持有的Wakelock时间,且发生在灭屏后的,那
             * 应该就是 释放Wakelock 所消耗的时间,这里是笔者的推测
             */
            wakeTimeMillis -= (appWakelockTimeUs / 1000)
                    + (mStats.getScreenOnTime(mRawRealtime, which) / 1000);

            //如果存在这样的时间
            if (wakeTimeMillis > 0) {
                double power = (wakeTimeMillis
                        * mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_AWAKE))
                        /  (60*60*1000);

                if (DEBUG) Log.d(TAG, "OS wakeLockTime " + wakeTimeMillis + " power "
                        + makemAh(power));

                /**
                 * 补偿进去每一项的值
                 */
                osApp.wakeLockTime += wakeTimeMillis;
                osApp.value += power;
                osApp.values[0] += power;

                /**
                 * 更新最大消耗电量的值
                 */
                if (osApp.value > mMaxPower) mMaxPower = osApp.value;
                if (osApp.value > mMaxRealPower) mMaxRealPower = osApp.value;

                mComputedPower += power;                                            //总消耗值
            }
        }
    }
    

    比Android4.4 相比起来,耗电统计精细了一点,两者的大致流程一样,主要是通过得到每个app占据CPU的时间(CPU分为不同的频率,不同频率的时间也要计算出来)、Wakelock的时间、数据流量的时间、WIFI的时间(包括WIFI的打开,工作,扫描,批量扫描几种不同的时间)以及各个传感器(GPS、光线,三轴加速,陀螺仪等)所消耗的时间,根据PowerProfile中已经存储的已知电流值,计算出其消耗的电量,并将单位转换为毫安时(mAh)

拼多多Android面试题及参考答案 Android 系统采用分层架构设计,从底层到上层依次为Linux 内核层硬件抽象层(HAL)系统运行时库层应用框架层应用层,共五层。位置:Linux 内核层与系统运行时库层之间,是“硬件与系统的隔离层”。核心作用:屏蔽硬件差异,为上层提供统一的硬件访问接口,解决 Android 开源与硬件厂商闭源的矛盾,具体功能如下:硬件能力抽象:将硬件的具体实现(如不同厂商的摄像头芯片、音频芯片)封装为标准化接口(如Camera HALAudio HAL。 阅读详情

相关推荐

Nvidia Jetson AGX Orin 如何进入 Recovery Mode(刷机注意事项)

Jetson Orin 如何进入Recovery mode + 刷机注意事项

Pandako's Blog 1万+

【亲测免费】 BetterBatteryStats - 更全面的电池统计工具

BetterBatteryStats - 更全面的电池统计工具 是一个强大的 Android 应用程序,提供详细的电池使用情况、唤醒锁信息等,帮助您更好地了解设备电量消耗,并找到优化方案。 项目简介 BetterBatteryStats 是一个专业的电池统计工具,专注于为用户提供关于设备电池使用情况的详细报告。通过分析应用程序、服务、广播接收器和其他组件对电池的影响,该应用能够帮助用户找出导致...

gitblog_00031的博客 1247

【强化学习】常用算法之一 “A3C”

A3C(Asynchronous Advantage Actor-Critic)算法是一种在强化学习领域中应用广泛的算法,它结合了策略梯度方法和价值函数的学习,用于近似解决马尔可夫决策过程(Markov Decision Process)问题。A3C算法在近年来备受关注,因为它在处理大规模连续动作空间和高维状态空间方面具有出色的性能。A3C算法是一种基于策略梯度的强化学习算法,通过多个并行的智能体异步地与环境交互,并利用Actor和Critic网络实现策略和价值的近似,从而实现快速而稳定的强化学习训练。

Code_and516的博客 6758

Android BatteryStats服务功耗统计流程详解

BatteryStatsService和BatterStatsImpl是系统中用于估算电流消耗的关键对象,能够估算并存储软件功耗和硬件功耗。其中主要流程分为事件回调时记录耗电信息、触发读取时计算并统计耗电信息两大流程。本文介绍耗电信息的读取和统计过程。BatteryStatsService从系统各服务、驱动节点、Linux文件系统节点中取得的数据,在需要时,通过BatteryStatsImpl.refresh()取出、过滤、计算。其中,按照App电耗、硬件电耗两大部分来分别计算。

performance 3487

openssl+SM2开发实例一(含源码)

是中国国家密码管理局(CNCA)颁布的椭圆曲线密码算法标准,属于非对称加密算法。它基于椭圆曲线离散对数问题,提供了安全可靠的数字签名、密钥交换和公钥加密等功能。SM2被设计为适用于各种场景下的密码学应用,包括数字证书、数据加密、数字签名、身份认证等。SM2是一种非对称加密算法,意味着它使用两个密钥:公钥和私钥。公钥用于加密数据和验证签名,而私钥用于解密数据和生成签名。SM2基于椭圆曲线密码学(Elliptic Curve Cryptography,ECC),使用椭圆曲线上的点运算来实现加密和签名操作。

N阶二进制的博客 7989

《QGIS快速入门与应用基础》009:国内镜像源(清华大学/阿里云)下载技巧

针对国内用户下载QGIS速度慢、易中断的问题,推荐使用清华大学和阿里云两大国内镜像源,提供3-10MB/s的极速下载方案。详细解析镜像源核心优势、分步骤下载指南及校验方法,对比清华(同步快、北方优选)与阿里云(南方节点多)的特点。针对常见问题如版本延迟、404错误等提供解决方案,并介绍搭配IDM等工具实现多线程加速的进阶技巧。通过镜像源+下载工具组合,用户可高效获取QGIS安装包,为后续系统安装奠定基础。

LuckyHanMo的博客 1745

Android 系统电量统计

本文主要通过跟踪 Android 设置 APP 的源码分析如何统计手机各个软件的电量。 ·PowerProfile 简介 PowerProfile这个类对手机的各个子系统运行时的平均电流(mA)和基本状态做了初步统计,所有信息都存放在sPowerMap这个 Map 里,这个 Map 实际是从power_profile.xml文件中读取的,PowerProfile提供接口如getAveragePower(String type)之类,供我们去取该XML里的各项的value,是个很短的类,也...

weixin_40430041的博客 1661

BDD测试用例:Playwright的MCP Server实战

Playwright MCP Server建立了大模型和真实的浏览环境之间的桥梁,可以让大模型操作多款浏览器完成测试任务。

Criss@陈磊 455

电量统计(1)-原理

说明:本文的代码以android-5.1.1_r8为蓝本,代码的在线网址是https://android.googlesource.com/ 1. 概要 我们平常说的手机耗电量,一般涵盖两个方面:硬件层面的功耗和软件层面的电量。 本文介绍的电量统计的原理,并不涉及到硬件层面的功耗设计,仅从软件层面围绕以下几个问题进行分析: Android如何启动电量统计服务? 电量统计涉及到哪一些硬件模...

weixin_42164528的博客 2388

DNA图谱分析:自动分析DNA图谱中的变异YOLOv5、YOLOv8、YOLOv10

YOLO(You Only Look Once)是一种基于卷积神经网络(CNN)的目标检测模型,因其高效的检测速度和优异的精度而广泛应用于计算机视觉任务。一次性检测:与传统的目标检测方法不同,YOLO通过回归方法同时预测多个边界框和类别信息,从而实现高效的目标检测。高精度与高速度:YOLO在检测精度和速度之间找到了平衡,适用于实时目标检测任务。

YOLO 733

【实战教程】OpenClaw接入MySQL数据库实战指南

本文介绍了在虚拟机Ubuntu中访问宿主机Win11中MySQL数据库的配置方法,重点包括创建远程用户、权限配置和安全设置。首先在MySQL中创建具有只读权限的用户并刷新权限,然后调整服务器设置允许远程连接。文章还提供了某金融机构财富管理系统的数据库设计方案,包含理财产品表、客户表和份额表的核心结构,其中金额字段使用DECIMAL类型确保精度,并设置唯一键约束。文末强调测试环境配置完成后应恢复安全更新模式以保障生产环境安全。

海兰 8700

android开发获取应用本身耗电量_Android耗电量测试

背 / 景 / 介 / 绍目前对于移动设备而言,电量是很重要的一个方面。现在大家使用手机基本每天都需要充电,所以用户也非常关注耗电的问题,如果应用设计不合理导致电量大量消耗,那么对于关注耗电的用户而言,这款应用将会是首要卸载目标。因此,作为测试人员,我们也应该对应用的耗电做一些针对性测试。Android电量测试1使用硬件测试仪 如安捷伦N6705B,这种的硬件功耗测试仪可以比较精确的测试...

weixin_39591720的博客 708

【个人成长笔记】在Ubuntu中安装RTL8188GU USB无线网卡驱动(Driver for Linux RTL8188GU)

这篇笔记提供了在Ubuntu系统中安装RTL8188GU无线网卡驱动的完整指南。主要内容包括:驱动程序的官方来源(Github链接)、详细安装步骤(通过git下载、编译安装等命令),以及将设备转换为USB网卡模式的关键指令。特别提醒每次开机都需要执行模式转换命令,因为设备默认会以U盘模式启动。文章以简洁的技术文档形式呈现,适合Linux用户快速查阅和操作。

yuhuasheng1997的博客 1827

安卓App后台保活实战:四层防御体系与厂商适配指南

安卓后台保活本质是系统资源约束与业务连续性的平衡问题,涉及AMS进程管理、PowerManager息屏控制、BatteryManager耗电监管三大核心机制。理解Android 8.0+后台执行限制与Doze模式原理,是构建合规保活策略的基础;Foreground Service、WorkManager任务调度、AlarmManager精准唤醒及厂商白名单适配,共同构成可落地的技术价值链。典型应用场景包括运动健康类实时定位、即时通讯消息同步、车载导航语音播报等强后台需求,而真正有效的方案并非‘永驻内存’,而

weixin_34194359的博客 314

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Android高性能AI日志库StatLog:结构化日志与性能监控实践

在移动应用开发中,日志记录是调试与性能监控的基础技术,其核心原理是通过记录程序运行时的状态与事件,帮助开发者理解应用行为。传统日志工具在记录方式上多为非结构化文本,难以进行自动化分析,尤其在面对高性能要求和复杂AI场景时,其I/O开销和字符串处理往往成为性能瓶颈。为了解决这一问题,现代日志库转向了结构化、语义化的设计范式,通过内存缓冲、异步处理和批量化输出等技术,将日志记录的性能开销降至最低。这种技术革新为应用性能监控(APM)和AI模型推理的深度可观测性提供了可能,使得开发者能够在不影响应用流畅度的前提下

weixin_34161083的博客 378

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

BatteryStatsHelper.processAppUsage 流程图绘制

BatteryStatsHelper.processAppUsage 流程图绘制 主要是进程耗电的计算框架,其中核心是CPU的耗电计算

苏法迪的专栏 523

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Android App耗电量统计

还没有完成的,初稿App耗电量统计:源码 PowerUsageSummary.java 继承PowerUsageBase.java类 BatteryHistoryPreference类--sp 获取耗电量历史(读取sp文件)--sp文件数据来自xml文件(power_usage_summary.xml) PreferenceGroup类--统计所有App耗电量同historyrefreshSt

8887

Android下APP耗电量统计实现

设置中的电量统计即系统调用内部API的统计结果。 http://www.autooo.net/classid164-id138050.html:智能手机的耗电特征及APP耗电量测试的两种方法 这篇文章主要分析了耗电量的 手机发展趋势和耗电特性 智能手机越来越普及,硬件处理能力越来越强,支持的软件应用越来越多。 我们不免也有另一种担心,现在的智能手机的待机时间已经是一个短板,未来的

maochongsandai110的专栏 4715

Android BatteryStatsHelper深入理解(and5.1)

BatteryStatsHelper这个类主要是统计各个应用,多用户的每个用户,以及蓝牙,屏幕等耗电统计。 一般使用BatteryStatsHelper这个类,先要new一个实例,然后再调用create函数: 下面我们就先从create分析,两种create方法,其中sStatsXfer是静态的 public void create(BatteryStats stats) {

kc58236582的博客 9606

android开发获取应用本身耗电量_APP性能测试——Android

性能测试需要从以下几个维度来测试:cpu、内存、FPS、启动时间、流量和耗电量,分别详细介绍每种维度的测试方法和判断标准。1、CPU 加载插件或者sdk:返回到主页面,cpu值能回落 2、内存 带来内存升高平均不超过7MB、内存消耗曲线最终可以收敛、不存在内存泄漏 3、FPS 最低50fps4、启动时间 主端:和上个版本比较 插件或者sdk:第一次启动:不高于1秒,后续启动不超过20...

weixin_39834780的博客 818

android开发获取应用本身耗电量_Android性能测试④-流量、电量怎么测?

Android性能测试④-流量、电量怎么测?Android用户也许会经常碰到以下的问题:1)应用后台开着,手机很快没电了——应用耗电大;2)首次/非首次启动应用,进入应用特别慢——应用启动慢;3)应用使用过程中,越来越卡——CPU能力不足/内存泄露;4)应用页面卡顿——帧率较低、页面卡顿。因此,对开发的Android应用,必须对其进行性能测试,不然将会直接影响用户体验。Android应用性能测试通...

weixin_39770226的博客 513

android开发获取应用本身耗电量_小编妹子手把手带您开发第一个android应用

我认为现代世界里最重要的不是我们所处的位置,而是我们前进的方向。  (老奥利费·温德尔·霍姆斯​)大家好,我是今天的值班小编,业余android开发工程师,来这个平台凑个数。今天是鼠年的第四天了,不知道朋友们在家里宅的可开心。 其实不能出门也不算是坏事,网上不是流传一个关于牛顿大佬的说法么:1665 年,英国伦敦大瘟疫,当时牛顿被迫回家进行隔离,他亲戚不走,聚会也不参加,但就是通过这段时间的学习和...

weixin_39824191的博客 227

Android APP耗电量采集数据模板

测试结论:针对xxx功能测试什么内容,分为什么场景,统计耗电量时长数据等。此数据正常操作中,通过ADB指令查看当前电量的百分比。应用包名:com.android.XXX。测试版本:设备型号+测试版本。测试时长:30mins。

weixin_39166825的博客 1324

Android性能专项测试之耗电量统计API

参考文章:Android应用的耗电量统计 深入浅出Android App耗电量统计 耗电量APIAndroid系统中很早就有耗电量的API,只不过一直都是隐藏的,Android系统的设置-电池功能就是调用的这个API,该API的核心部分是调用了com.android.internal.os.BatteryStatsHelper类,利用到PowerProfile类,要读取power_profi

doctorq 1万+

深入浅出Android App耗电量统计

前言     在Android统计App耗电量比较麻烦,直至Android 4.4,它仍没公开“电量统计”API或文档……额,是的,仅没有公开,并不是没有。平时在手机“设置- 电量”看到的数据          就是系统调用内部API的统计结果。   基础概念     1. 手机由众多“部件”组成,所谓“部件”是指:CPU,WIFI,GPS....所以,Android App消耗总电量...

weixin_34399060的博客 805
上一篇: dumpsys alarm 格式解读
下一篇: Tensorflow入门教程【1】---Hello TensorFlow
memoryjs
博客等级 码龄18年 240粉丝 113原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值