Skip to content

Commit fbac1ca

Browse files
LofoWalkerExalTom
andauthored
ESOB016: Detects explicit or implicit use of hardware acceleration in Android components. (#103)
Co-authored-by: Tom WALKER <tom.walker@exalt-it.com>
1 parent 2026325 commit fbac1ca

File tree

8 files changed

+195
-2
lines changed

8 files changed

+195
-2
lines changed

android-plugin/src/main/java/io/ecocode/xml/XmlCheckList.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import io.ecocode.xml.checks.sobriety.DarkUIThemeXmlRule;
2727
import io.ecocode.xml.checks.power.CompagnionInBackgroundXmlRule;
2828
import io.ecocode.xml.checks.power.IgnoreBatteryOptimizationsXmlRule;
29+
import io.ecocode.xml.checks.sobriety.HardwareAccelerationXmlRule;
2930

3031
import java.util.Arrays;
3132
import java.util.List;
@@ -45,7 +46,8 @@ public static List<Class<?>> getXmlChecks() {
4546
CompagnionInBackgroundXmlRule.class,
4647
ChargeAwarenessXmlRule.class,
4748
ServiceBootTimeXmlRule.class,
48-
SaveModeAwarenessXmlRule.class
49+
SaveModeAwarenessXmlRule.class,
50+
HardwareAccelerationXmlRule.class
4951
);
5052
}
5153

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* ecoCode Android plugin - Provides rules to reduce the environmental footprint of your Android applications
3+
* Copyright © 2020 Green Code Initiative (contact@ecocode.io)
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
package io.ecocode.xml.checks.sobriety;
19+
20+
import io.ecocode.xml.checks.XPathSimpleCheck;
21+
import org.sonar.check.Priority;
22+
import org.sonar.check.Rule;
23+
import org.sonarsource.analyzer.commons.annotations.DeprecatedRuleKey;
24+
import org.w3c.dom.Node;
25+
26+
@Rule(key = "EC549", name = "Hardware acceleration", priority = Priority.MAJOR)
27+
@DeprecatedRuleKey(repositoryKey = "ecoCode-java", ruleKey = "ESOB016")
28+
public class HardwareAccelerationXmlRule extends XPathSimpleCheck {
29+
30+
private static final String ERROR_MESSAGE_ENABLED =
31+
"Hardware acceleration is enabled. Consider disabling it to reduce RAM usage.";
32+
33+
private static final String ERROR_MESSAGE_IMPLICIT =
34+
"Hardware acceleration is implicitly enabled. Consider disabling it explicitly with android:hardwareAccelerated=\"false\".";
35+
36+
private static final String ANDROID_HARDWARE_ACCELERATED = "android:hardwareAccelerated";
37+
private static final String XPATH_TARGET_COMPONENTS = "//application | //activity | //window | //view";
38+
39+
@Override
40+
protected String getMessage() {
41+
return ERROR_MESSAGE_IMPLICIT;
42+
}
43+
44+
@Override
45+
protected String getXPathExpressionString() {
46+
return XPATH_TARGET_COMPONENTS;
47+
}
48+
49+
@Override
50+
protected void visitNode(Node node, String message) {
51+
Node hardwareAttributeNode = getHardwareAccelerationAttribute(node);
52+
53+
if ("true".equals(getNodeValue(hardwareAttributeNode))) {
54+
reportIssue(hardwareAttributeNode, ERROR_MESSAGE_ENABLED);
55+
}
56+
else if (!isHardwareAccelerationDisabledInParent(node)) {
57+
reportIssue(node, ERROR_MESSAGE_IMPLICIT);
58+
}
59+
}
60+
61+
private boolean isHardwareAccelerationDisabledInParent(Node node) {
62+
Node parent = node;
63+
64+
while (parent != null && !"application".equals(parent.getNodeName())) {
65+
parent = parent.getParentNode();
66+
}
67+
68+
if (parent == null) {
69+
return false;
70+
}
71+
72+
Node parentHardwareAttr = getHardwareAccelerationAttribute(parent);
73+
return "false".equals(getNodeValue(parentHardwareAttr));
74+
}
75+
76+
private static Node getHardwareAccelerationAttribute(Node node) {
77+
if (node == null || node.getAttributes() == null) {
78+
return null;
79+
}
80+
81+
return node.getAttributes().getNamedItem(ANDROID_HARDWARE_ACCELERATED);
82+
}
83+
84+
private String getNodeValue(Node node) {
85+
return (node != null) ? node.getNodeValue() : null;
86+
}
87+
88+
}

android-plugin/src/main/resources/io/ecocode/android/xml/ecocode_xml_profile.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"EC544",
99
"EC545",
1010
"EC546",
11-
"EC548"
11+
"EC548",
12+
"EC549"
1213
]
1314
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<img src="http://www.neomades.com/extern/partage/ecoCode/2sur5_1x.png">
2+
<p>
3+
Hardware acceleration is a feature that improves rendering performance by offloading certain 2D drawing operations to the GPU.
4+
While it can enhance UI responsiveness, it also increases memory and power consumption — especially on lower-end or older devices.
5+
<br>
6+
Since API level 14, hardware acceleration is enabled by default in Android applications. However, if not required,
7+
it is recommended to disable it explicitly in the manifest to reduce resource usage and promote energy-efficient design.
8+
<br>
9+
This rule detects components (activities, services, etc.) that either explicitly enable hardware acceleration or inherit it implicitly without being disabled at the application level.
10+
</p>
11+
12+
<h2>Noncompliant Code Example</h2>
13+
<pre>
14+
&lt;application
15+
android:label="@string/app_name"&gt;
16+
17+
&lt;activity
18+
android:name=".FastActivity"
19+
android:hardwareAccelerated="true" /&gt;
20+
21+
&lt;activity
22+
android:name=".AnotherFastActivity" /&gt;
23+
24+
&lt;/application&gt;
25+
</pre>
26+
27+
<h2>Compliant Solution</h2>
28+
<pre>
29+
&lt;application
30+
android:label="@string/app_name"
31+
android:hardwareAccelerated="false"&gt;
32+
33+
&lt;activity
34+
android:name=".FastActivity"
35+
android:hardwareAccelerated="true" /&gt; &lt;!-- Only if really needed --&gt;
36+
37+
&lt;activity
38+
android:name=".AnotherFastActivity" /&gt; &lt;!-- Inherits 'false' --&gt;
39+
40+
&lt;/application&gt;
41+
</pre>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"title": "Sobriety: Hardware acceleration",
3+
"type": "CODE_SMELL",
4+
"status": "ready",
5+
"remediation": {
6+
"func": "Constant\/Issue",
7+
"constantCost": "1min"
8+
},
9+
"tags": [
10+
"sobriety",
11+
"environment",
12+
"ecocode",
13+
"android",
14+
"eco-design"
15+
],
16+
"defaultSeverity": "Major"
17+
}

android-plugin/src/test/java/io/ecocode/xml/XmlRulesDefinitionTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ public void test() {
7171
assertThat(saveModeAwarenessXml).isNotNull();
7272
assertThat(saveModeAwarenessXml.name()).isEqualTo("Power: Save Mode Awareness");
7373

74+
RulesDefinition.Rule hardwareAccelerationXml = repository.rule("EC549");
75+
assertThat(hardwareAccelerationXml).isNotNull();
76+
assertThat(hardwareAccelerationXml.name()).isEqualTo("Sobriety: Hardware acceleration");
77+
78+
7479
for (RulesDefinition.Rule rule : repository.rules()) {
7580
for (RulesDefinition.Param param : rule.params()) {
7681
assertThat(param.description()).as("description for " + param.key()).isNotEmpty();
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package io.ecocode.xml.checks.sobriety;
2+
3+
import org.junit.Test;
4+
import org.sonarsource.analyzer.commons.xml.checks.SonarXmlCheckVerifier;
5+
6+
public class HardwareAccelerationXmlRuleTest {
7+
8+
@Test
9+
public void detectExplicitOrImplicitHardwareAcceleration() {
10+
SonarXmlCheckVerifier.verifyIssues("HardwareAccelerationCheck.xml", new HardwareAccelerationXmlRule());
11+
}
12+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2+
package="com.example.hardwaretest">
3+
4+
<application android:label="@string/app_name" android:hardwareAccelerated="false">
5+
6+
<activity android:name=".SafeActivity" android:hardwareAccelerated="false"/>
7+
<activity android:name=".FastActivity" android:hardwareAccelerated="true"/> <!-- Noncompliant {{Hardware acceleration is enabled. Consider disabling it to reduce RAM usage.}} -->
8+
<activity android:name=".MainActivity"/>
9+
<service android:name=".MyService"/>
10+
<activity android:name=".AnotherFastActivity" android:hardwareAccelerated="true"/> <!-- Noncompliant {{Hardware acceleration is enabled. Consider disabling it to reduce RAM usage.}} -->
11+
<receiver android:name=".MyReceiver"/>
12+
<window android:name=".FancyWindow" android:hardwareAccelerated="true"/> <!-- Noncompliant {{Hardware acceleration is enabled. Consider disabling it to reduce RAM usage.}} -->
13+
<view android:name=".DefaultNotAcceleratedView"/>
14+
15+
</application>
16+
17+
<activity android:name=".OutOfAppActivity"/> <!-- Noncompliant {{Hardware acceleration is implicitly enabled. Consider disabling it explicitly with android:hardwareAccelerated="false".}} -->
18+
<view android:name=".DefaultAcceleratedView"/> <!-- Noncompliant {{Hardware acceleration is implicitly enabled. Consider disabling it explicitly with android:hardwareAccelerated="false".}} -->
19+
20+
<activity android:name=".OutOfAppActivityExplicit" android:hardwareAccelerated="true"/><!-- Noncompliant {{Hardware acceleration is enabled. Consider disabling it to reduce RAM usage.}} -->
21+
<view android:name=".DefaultAcceleratedViewExplicit" android:hardwareAccelerated="true"/><!-- Noncompliant {{Hardware acceleration is enabled. Consider disabling it to reduce RAM usage.}} -->
22+
23+
<application android:label="@string/alt_app" android:hardwareAccelerated="false">
24+
<activity android:name=".AltActivity"/>
25+
</application>
26+
</manifest>
27+

0 commit comments

Comments
 (0)