19 Power Consumption Optimization Part2 Methods and Online Monitoring for Power Optimization

19 Power Consumption Optimization Part2 Methods and Online Monitoring for Power Optimization #

Compared to optimization of startup time, lag, memory, and network, many applications may not pay as much attention to power consumption optimization. Of course, it’s not that we don’t want to optimize power consumption, but more often than not, we just don’t know where to start.

Unlike startup time and lag rate, there has always been a lack of a quantifiable metric for power consumption in online environments. The power consumption data obtained by the Android system is only an estimation, and starting from Android 4.4, even this estimation cannot be obtained anymore. When users complain about the power consumption of our application, we usually feel at a loss and don’t know how to locate or analyze the issue.

So, what work is required for power consumption optimization? How can we quickly identify unreasonable code calls and continuously monitor the power consumption of the application? Today, let’s learn about methods for optimizing power consumption and online monitoring.

Power Consumption Optimization #

Before discussing how to optimize power consumption, you need to understand what power consumption optimization is and what its purpose is.

1. What is power consumption optimization

Some students may wonder if power consumption optimization is simply about reducing the power consumption of applications and increasing user battery life. However, in practice, if our application needs to play videos, retrieve GPS information, or take photos, these power consumption elements seem unavoidable.

How can we determine which power consumption can be avoided or needs to be optimized? You can take a look at this graph. When users check the power consumption ranking, they find that “King of Glory” has been used for over 7 hours. At this point, users will have certain expectations for power consumption while using “King of Glory”.

Suppose at this time, it is discovered that a certain application has not been used much (low foreground time), but its power consumption is very high. This situation greatly deviates from the user’s expectation, and they may consider lodging a complaint.

Therefore, the first aspect of power consumption optimization is to optimize the background power consumption of applications. By understanding how the system calculates power consumption, we can determine what actions an application should not perform in the background, such as prolonged acquisition of WakeLock, scanning for Wi-Fi and Bluetooth, and so on. The reason why the first aspect of power consumption optimization is to optimize background power consumption is because most pre-installed apps have the most stringent requirements for background power consumption.

Of course, we will not completely disregard foreground power consumption, but the standards for foreground power consumption are more relaxed. Consider the following graph. If the system displays this dialog for your application, users might tolerate it for WeChat. However, for most other applications, many users may simply add you to the list of applications with restricted background activity.

The second aspect of power consumption optimization is to comply with the rules of the system, making the system regard your power consumption as normal. In Android P, background power consumption is monitored through Android Vitals. Therefore, we need to comply with the rules of Android Vitals. Currently, its specific rules are as follows:

Although the above standards are subject to change at any time, we can see that the Android system currently pays attention to background alarm wake-ups, background network usage, background Wi-Fi scanning, and extended WakeLock that prevents the system from entering background sleep.

2. Challenges in power consumption optimization

Now that we have clarified the purpose and direction of power consumption optimization, let’s get started. But I want to emphasize that you will only realize how deep the rabbit hole of power consumption optimization is once you dive into it. It mainly involves the following issues:

  • Lack of context, inability to reproduce. For example, a user uploads a screenshot showing that your application accounts for 30% of power consumption. Based on detailed battery usage information, we may have some guesses. However, users cannot provide more detailed information, such as the specific context in which the power consumption occurred, leaving us clueless.

  • Incomplete information, difficult to locate. If it were developers or manufacturers, they could provide a bug report. By utilizing Battery Historian, we can obtain comprehensive power consumption statistics. However, Battery Historian lacks the most crucial stack information. With complex code calls and potentially many third-party SDKs, we have no idea which line of code is responsible for requesting WakeLock, using the sensors, or making network calls.

  • Unable to evaluate the results. Through guesswork, we may try some solutions. However, starting from Android 4.4, we are unable to obtain the power consumption information of the application. Even if we solve a power consumption issue, it is difficult to evaluate whether it has taken effect and how much value it brings to users.

3. Methods for Power Consumption Optimization

It is not easy to optimize power consumption when it is difficult to reproduce, locate, and evaluate the results. Before actually optimizing, let’s see why our application needs to consume power in the background.

Most developers are not intentionally wasting users’ battery power for malicious purposes. There are mainly the following reasons:

  • A specific use case. The most common scenario is push notifications, in which we have to keep the app alive in various ways. In the face of requirements, the value to users may be ranked second.

  • Bugs in the code. Due to insufficient consideration of certain logic, it may cause GPS to remain active or fail to release the WakeLock.

Therefore, the approach to power consumption optimization is also very simple.

  • Find alternative solutions for use cases. Taking push notifications as an example, can we utilize vendor channels more or adopt a timed pull mode for fetching the latest messages? If there is no other choice, can we use a foreground service or guide users to add the app to a whitelist? The overarching principle for background tasks is to reduce, delay, and consolidate tasks. You can refer to an article on background task scheduling and power optimization written by a developer at WeChat: “Android Background Task Scheduling and Battery Optimization”. Before running a task in the background, we need to think about the following:

  • Compliance with Android rules. First, most of the power consumption monitoring by the system is done when the phone is not charging. We can choose to perform power-consuming tasks only when the user is charging. For specific methods, refer to the official documentation: “Monitoring the Battery Level and Charging State”. Secondly, adapt to the latest Target API as early as possible, as higher version system’s background restrictions are already very strict, making it more difficult for the app to consume power in the background.
IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = context.registerReceiver(null, ifilter);

// Get the whether the user is charging or the battery is full
int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL;
  • Monitoring exceptional situations. Even in the most strict Android P, the system still allows the partial use of background network, Alarm, and JobScheduler events (different usage limits for different groups). Therefore, there is still a possibility of exceptional situations, not to mention lower version systems. For exceptional situations, we need to abstract the rules, similar to Android Vitals battery monitoring, and add more information to assist in problem diagnosis.

Power Consumption Monitoring #

In I/O monitoring, I have specified four rules: Duplicate I/O, Main Thread I/O, Buffer size, and I/O leakage. The same applies to power consumption monitoring. First, we need to abstract specific rules and gather as much auxiliary information as possible to help troubleshoot problems.

1. Android Vitals

I have already mentioned several monitoring solutions and rules related to power consumption in Android Vitals. Let’s review them.

After using it for a while, I found that it is not as useful as it seems. Taking Alarm wakeup as an example, Vitals takes more than 10 wakes per hour as a rule. Since this rule cannot be modified, we often want to make finer distinctions for different system versions.

Furthermore, similar to Battery Historian, we can only get the components marked as wakeups and cannot obtain the stack trace for the requests, as well as information on whether the phone was charging or the remaining battery level.

The same applies to network usage, WiFi scans, and wakelocks. Although Vitals helps narrow down the troubleshooting scope, we still need to search for suspicious code in the vast amount of code.

2. What does power consumption monitoring involve?

Android Vitals is not as useful and cannot be used for domestic applications. Nevertheless, we still need to build our own power consumption monitoring system.

What should our power consumption monitoring system monitor, and how can it be better than Android Vitals?

  • Monitoring information. In simple terms, we should monitor what the system cares about, and focus on background power consumption monitoring. Alarm wakeups, wakelocks, WiFi scans, and network usage are all necessary, while others can be determined based on the actual application. For example, background GPS access is allowed for a map application, and background sensor access is not a major issue for a pedometer application.

  • On-site information. The monitoring system should be able to obtain complete stack trace information, such as which line of code initiated WiFi scans or which line of code requested a wakelock. Additionally, information such as whether the phone was charging, the phone’s battery level, the foreground and background time of the application, and the CPU state can also help us troubleshoot certain problems.

  • Abstracting rules. Finally, we need to abstract the monitored content into rules. Of course, different applications have different monitoring items or parameters.

Since each application has different circumstances, here are some simple rules that can be used as a reference.

At the Android Green Alliance conference, Huawei publicized the “red line” for their background resource usage. You can also refer to some of the rules mentioned inside:

2. How to monitor power consumption

After clarifying what needs to be monitored and the specific rules, we can finally move on to implementing this aspect. Just like I/O monitoring and network monitoring, my first thought is to use a hooking solution.

Java Hook

The advantage of the hooking solution is that it is very simple for the user to implement and does not require modifying their own code. Let’s take a look at how to achieve monitoring using Java Hook with a few commonly used rules as examples.

  • Wakelocks. Wakelocks are used to prevent the CPU, screen, and even the keyboard from going to sleep. Similar to Alarm and JobService, wakelocks are also used to perform background CPU operations. The core control code for wakelocks is in PowerManagerService, and the implementation is very simple.

    // Proxy PowerManagerService ProxyHook().proxyHook(context.getSystemService(Context.POWER_SERVICE), “mService”, this);

    @Override public void beforeInvoke(Method method, Object[] args) {

// Acquire Wakelock
if (method.getName().equals("acquireWakeLock")) {
    if (isAppBackground()) {
        // Background logic, get application stack, etc.
    } else {
        // Foreground logic, get application stack, etc.
    }
}
// Release Wakelock
else if (method.getName().equals("releaseWakeLock")) {
    // Release logic
}
// Proxy AlarmManagerService
new ProxyHook().proxyHook(context.getSystemService
(Context.ALARM_SERVICE), "mService", this);

public void beforeInvoke(Method method, Object[] args) {
    // Set Alarm
    if (method.getName().equals("set")) {
        // Adaptation of parameter types for different versions, get application stack, etc.
    }
    // Clear Alarm
    else if (method.getName().equals("remove")) {
        // Clear logic
    }
}
  • Others. For background CPU monitoring, we can use the methods learned from lag monitoring. For background network monitoring, we can also use the methods learned from network monitoring. For GPS monitoring, we can Hook the LOCATION_SERVICE. For Sensor, we can get partial information by Hooking the “mSensorListeners” in SENSOR_SERVICE.

Using Hook, we can save stack information when acquiring resources. When we trigger a certain rule to report a problem, we can also include the collected stack information, whether the battery is charging, CPU information, and application foreground and background time as auxiliary information.

Instrumentation

Although using Hook is very simple, finding suitable Hook points for certain rules may not be easy. And after Android P, many Hook points are no longer supported.

For compatibility considerations, my first thought is to write a base class and add monitoring logic in the unified call interface. Taking WakeLock as an example:

public class WakelockMetrics {
    // Acquire Wakelock
    public void acquire(PowerManager.WakeLock wakelock) {
        wakeLock.acquire();
        // Add monitoring logic for acquiring Wakelock here
    }
    // Release Wakelock
    public void release(PowerManager.WakeLock wakelock, int flags) {
        wakelock.release();
        // Add monitoring logic for releasing Wakelock here
    }
}

Facebook also has an open-source library called Battery-Metrics for monitoring power consumption. It covers a wide range of data, including Alarm, WakeLock, Camera, CPU, Network, etc., and collects information such as battery charging status and battery level.

Battery-Metrics provides a series of base classes, and in practical use, the implementer may need to modify a large amount of source code. However, for some third-party SDKs or later added code, we may not be able to guarantee that they can be monitored. In such cases, monitoring is not possible, so Facebook uses instrumentation to dynamically replace them.

Unfortunately, Facebook has not open-sourced the specific implementation of their internal instrumentation solution. However, the implementation is not actually difficult. In fact, in the previous samples, we have already used two instrumentation solutions, ASM and AspectJ. I will also arrange a separate topic to discuss the implementation of different instrumentation solutions.

Instrumentation solutions are very compatible and have low integration costs for users. However, they are not perfect. Instrumentation solutions cannot replace system code, for example, JobService requesting PARTIAL_WAKE_LOCK.

Summary #

From the methods of calculating power consumption in the Android system, we have learned which modules to pay attention to in terms of power consumption. From the evolution of power optimization in Android, we have learned about some directions and points of concern in Android’s power optimization. From the power consumption monitoring in Android Vitals, we have learned about the monitoring methods for power optimization.

However, the system’s methods may not be completely suitable for our application, so it is still necessary to further read the source code, think, and develop our own optimization practices. This is also my methodology for performance optimization, which applies to other fields as well.

Homework #

Have you done any power optimization and monitoring work in your project? What is your implementation plan? Please leave a message here to discuss with me and other students.

Today’s homework is to use Java Hook to implement power consumption monitoring for Alarm, WakeLock, and GPS according to the ideas in the article. The specific rules are consistent with the table in the article. Please submit the improved code through Pull requests to the Chapter19 repository.

Feel free to click “Share with friends” to share today’s content with your friends and invite them to study together. Don’t forget to submit your homework in the comments section. I have prepared a rewarding “Study Gift Pack” for students who complete the homework seriously. Looking forward to learning and progressing together with you.