diff --git a/codeql-custom-queries-java/android/avoid-android-sdk-location.ql b/codeql-custom-queries-java/android/avoid-android-sdk-location.ql
index b9be9f6..b43b111 100644
--- a/codeql-custom-queries-java/android/avoid-android-sdk-location.ql
+++ b/codeql-custom-queries-java/android/avoid-android-sdk-location.ql
@@ -12,8 +12,6 @@
import java
-import java
-
from RefType t, Variable v
where
v.getType() = t and
diff --git a/codeql-custom-queries-java/android/avoid-brightness-override.expected b/codeql-custom-queries-java/android/avoid-brightness-override.expected
new file mode 100644
index 0000000..6829855
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-brightness-override.expected
@@ -0,0 +1,3 @@
+| avoid-brightness-override.java:17:9:17:31 | params.screenBrightness | Avoid setting screenBrightness to BRIGHTNESS_OVERRIDE_FULL. This disables Android's adaptive brightness feature which was introduced to improve battery life. |
+| avoid-brightness-override.java:23:9:23:31 | params.screenBrightness | Avoid setting screenBrightness to BRIGHTNESS_OVERRIDE_FULL. This disables Android's adaptive brightness feature which was introduced to improve battery life. |
+| avoid-brightness-override.java:29:13:29:35 | params.screenBrightness | Avoid setting screenBrightness to BRIGHTNESS_OVERRIDE_FULL. This disables Android's adaptive brightness feature which was introduced to improve battery life. |
diff --git a/codeql-custom-queries-java/android/avoid-brightness-override.java b/codeql-custom-queries-java/android/avoid-brightness-override.java
new file mode 100644
index 0000000..1420a06
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-brightness-override.java
@@ -0,0 +1,51 @@
+// WindowManager et WindowManager.LayoutParams sont déjà déclarés dans avoid-keep-screen-on.java
+// avec seulement FLAG_KEEP_SCREEN_ON — on ne peut pas les redéclarer ni les modifier.
+// On utilise une classe proxy BrightnessParams qui simule WindowManager.LayoutParams
+// pour les champs screenBrightness et BRIGHTNESS_OVERRIDE_FULL.
+
+class BrightnessParams {
+ float screenBrightness;
+ static final float BRIGHTNESS_OVERRIDE_FULL = 1.0f;
+ static final float BRIGHTNESS_OVERRIDE_NONE = -1.0f;
+}
+
+// 🚫 Noncompliant - screenBrightness set to BRIGHTNESS_OVERRIDE_FULL
+class NoncompliantBrightnessOverride {
+
+ void disableAdaptiveBrightness() {
+ BrightnessParams params = new BrightnessParams();
+ params.screenBrightness = BrightnessParams.BRIGHTNESS_OVERRIDE_FULL; // $ Alert
+ }
+
+ void disableAdaptiveBrightnessWithVar() {
+ float override = BrightnessParams.BRIGHTNESS_OVERRIDE_FULL;
+ BrightnessParams params = new BrightnessParams();
+ params.screenBrightness = override; // $ Alert
+ }
+
+ void disableInLoop() {
+ for (int i = 0; i < 3; i++) {
+ BrightnessParams params = new BrightnessParams();
+ params.screenBrightness = BrightnessParams.BRIGHTNESS_OVERRIDE_FULL; // $ Alert
+ }
+ }
+}
+
+// ✅ Compliant - screenBrightness not set to BRIGHTNESS_OVERRIDE_FULL
+class CompliantBrightnessUsage {
+
+ void useAdaptiveBrightness() {
+ BrightnessParams params = new BrightnessParams();
+ params.screenBrightness = BrightnessParams.BRIGHTNESS_OVERRIDE_NONE;
+ }
+
+ void useCustomBrightness() {
+ BrightnessParams params = new BrightnessParams();
+ params.screenBrightness = 0.5f;
+ }
+
+ void noScreenBrightnessSet() {
+ BrightnessParams params = new BrightnessParams();
+ int x = 42;
+ }
+}
\ No newline at end of file
diff --git a/codeql-custom-queries-java/android/avoid-brightness-override.ql b/codeql-custom-queries-java/android/avoid-brightness-override.ql
new file mode 100644
index 0000000..321a235
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-brightness-override.ql
@@ -0,0 +1,24 @@
+/**
+ * @name Brightness Override
+ * @description Setting WindowManager.LayoutParams#screenBrightness to BRIGHTNESS_OVERRIDE_FULL
+ * disables the adaptive brightness feature introduced in Android 9.
+ * Adaptive brightness adjusts screen brightness based on environment light
+ * to improve battery life. Overriding it is a very bad idea.
+ * @kind problem
+ * @problem.severity warning
+ * @id java/android/avoid-brightness-override
+ * @tags android
+ * @tags java
+ */
+
+import java
+
+from FieldWrite fw
+where
+ fw.getField().getName() = "screenBrightness" and
+ exists(FieldRead fr |
+ fr.getField().getName() = "BRIGHTNESS_OVERRIDE_FULL" and
+ fw.getEnclosingCallable() = fr.getEnclosingCallable()
+ )
+select fw,
+ "Avoid setting screenBrightness to BRIGHTNESS_OVERRIDE_FULL. This disables Android's adaptive brightness feature which was introduced to improve battery life."
\ No newline at end of file
diff --git a/codeql-custom-queries-java/android/avoid-day-night-mode.expected b/codeql-custom-queries-java/android/avoid-day-night-mode.expected
new file mode 100644
index 0000000..5ee9390
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-day-night-mode.expected
@@ -0,0 +1,10 @@
+| avoid-day-night-mode.xml:5:5:5:65 | parent=Theme.AppCompat.Light | The theme 'AppTheme.Light' does not inherit from a DayNight theme. Use 'Theme.*.DayNight' as parent to support Android dark mode and reduce energy consumption on (AM)OLED screens. |
+| avoid-day-night-mode.xml:9:5:9:58 | parent=Theme.AppCompat | The theme 'AppTheme.Dark' does not inherit from a DayNight theme. Use 'Theme.*.DayNight' as parent to support Android dark mode and reduce energy consumption on (AM)OLED screens. |
+| avoid-day-night-mode.xml:13:5:13:71 | parent=Theme.MaterialComponents | The theme 'AppTheme.Material' does not inherit from a DayNight theme. Use 'Theme.*.DayNight' as parent to support Android dark mode and reduce energy consumption on (AM)OLED screens. |
+| avoid-day-night-mode.xml:17:5:17:83 | parent=Theme.AppCompat.Light.DarkActionBar | The theme 'AppTheme.LightDark' does not inherit from a DayNight theme. Use 'Theme.*.DayNight' as parent to support Android dark mode and reduce energy consumption on (AM)OLED screens. |
+| avoid-ligth-ui.xml:5:5:5:65 | parent=Theme.AppCompat.Light | The theme 'AppTheme.Light' does not inherit from a DayNight theme. Use 'Theme.*.DayNight' as parent to support Android dark mode and reduce energy consumption on (AM)OLED screens. |
+| avoid-ligth-ui.xml:9:5:9:82 | parent=Theme.MaterialComponents.Light | The theme 'AppTheme.MaterialLight' does not inherit from a DayNight theme. Use 'Theme.*.DayNight' as parent to support Android dark mode and reduce energy consumption on (AM)OLED screens. |
+| avoid-ligth-ui.xml:13:5:13:83 | parent=Theme.AppCompat.Light.DarkActionBar | The theme 'AppTheme.LightDark' does not inherit from a DayNight theme. Use 'Theme.*.DayNight' as parent to support Android dark mode and reduce energy consumption on (AM)OLED screens. |
+| avoid-ligth-ui.xml:17:5:17:100 | parent=Theme.MaterialComponents.Light.DarkActionBar | The theme 'AppTheme.MaterialLightDark' does not inherit from a DayNight theme. Use 'Theme.*.DayNight' as parent to support Android dark mode and reduce energy consumption on (AM)OLED screens. |
+| avoid-ligth-ui.xml:21:5:21:58 | parent=Theme.AppCompat | The theme 'AppTheme.Dark' does not inherit from a DayNight theme. Use 'Theme.*.DayNight' as parent to support Android dark mode and reduce energy consumption on (AM)OLED screens. |
+| avoid-ligth-ui.xml:25:5:25:75 | parent=Theme.MaterialComponents | The theme 'AppTheme.MaterialDark' does not inherit from a DayNight theme. Use 'Theme.*.DayNight' as parent to support Android dark mode and reduce energy consumption on (AM)OLED screens. |
diff --git a/codeql-custom-queries-java/android/avoid-day-night-mode.ql b/codeql-custom-queries-java/android/avoid-day-night-mode.ql
new file mode 100644
index 0000000..7f1f2d9
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-day-night-mode.ql
@@ -0,0 +1,26 @@
+/**
+ * @name Day Night Mode
+ * @description Dark theme is available in Android 10 (API level 29) and higher.
+ * Apps should support Dark theme by inheriting from a DayNight theme
+ * (parent="Theme.*.DayNight"). Failing to do so prevents the app from
+ * adapting to the user's system dark mode preference, increasing energy
+ * consumption on (AM)OLED screens.
+ * @kind problem
+ * @problem.severity warning
+ * @id java/android/avoid-day-night-mode
+ * @tags android
+ * @tags java
+ *
+ * @note Test contains those for the darktheme detection too
+ */
+
+import semmle.code.xml.XML
+
+from XmlAttribute attr
+where
+ attr.getName() = "parent" and
+ not attr.getValue().matches("%DayNight%") and
+ attr.getElement().getName() = "style"
+select attr,
+ "The theme '" + attr.getElement().getAttribute("name").getValue() +
+ "' does not inherit from a DayNight theme. Use 'Theme.*.DayNight' as parent to support Android dark mode and reduce energy consumption on (AM)OLED screens."
\ No newline at end of file
diff --git a/codeql-custom-queries-java/android/avoid-day-night-mode.xml b/codeql-custom-queries-java/android/avoid-day-night-mode.xml
new file mode 100644
index 0000000..421c3c8
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-day-night-mode.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/codeql-custom-queries-java/android/avoid-everlasting-service.expected b/codeql-custom-queries-java/android/avoid-everlasting-service.expected
new file mode 100644
index 0000000..a0fee8f
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-everlasting-service.expected
@@ -0,0 +1,4 @@
+| avoid-everlasting-service.java:15:9:15:38 | startService(...) | startService() is called here without a corresponding stopService() or stopSelf() in the same method. This may keep the service alive indefinitely and cause uncontrolled energy leakage. |
+| avoid-everlasting-service.java:20:9:20:38 | startService(...) | startService() is called here without a corresponding stopService() or stopSelf() in the same method. This may keep the service alive indefinitely and cause uncontrolled energy leakage. |
+| avoid-everlasting-service.java:21:9:21:38 | startService(...) | startService() is called here without a corresponding stopService() or stopSelf() in the same method. This may keep the service alive indefinitely and cause uncontrolled energy leakage. |
+| avoid-everlasting-service.java:26:9:26:38 | startService(...) | startService() is called here without a corresponding stopService() or stopSelf() in the same method. This may keep the service alive indefinitely and cause uncontrolled energy leakage. |
diff --git a/codeql-custom-queries-java/android/avoid-everlasting-service.java b/codeql-custom-queries-java/android/avoid-everlasting-service.java
new file mode 100644
index 0000000..a8fc20b
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-everlasting-service.java
@@ -0,0 +1,61 @@
+class Context {
+ Object startService(Object service) { return null; }
+ boolean stopService(Object service) { return false; }
+}
+
+class Service extends Context {}
+
+class Intent {}
+
+// 🚫 Noncompliant - startService() without stopService() or stopSelf()
+class NoncompliantEverlastingService {
+
+ void leakingLaunch() {
+ Context ctx = new Context();
+ ctx.startService(new Intent()); // $ Alert
+ }
+
+ void leakingLaunchMultiple() {
+ Context ctx = new Context();
+ ctx.startService(new Intent()); // $ Alert
+ ctx.startService(new Intent()); // $ Alert
+ }
+
+ void leakingNoStopInSameMethod() {
+ Context ctx = new Context();
+ ctx.startService(new Intent()); // $ Alert
+ }
+
+ void stopElsewhere() {
+ Context ctx = new Context();
+ ctx.stopService(new Intent());
+ }
+}
+
+// ✅ Compliant - startService() with stopService() in same method
+class CompliantStopService {
+
+ void safeWithStopService() {
+ Context ctx = new Context();
+ ctx.startService(new Intent());
+ ctx.stopService(new Intent());
+ }
+
+ void safeMultiple() {
+ Context ctx = new Context();
+ ctx.startService(new Intent());
+ ctx.startService(new Intent());
+ ctx.stopService(new Intent());
+ }
+}
+
+// ✅ Compliant - startService() with stopSelf() in same method
+class CompliantStopSelf extends Service {
+
+ void safeWithStopSelf() {
+ startService(new Intent());
+ stopSelf();
+ }
+
+ void stopSelf() {}
+}
\ No newline at end of file
diff --git a/codeql-custom-queries-java/android/avoid-everlasting-service.ql b/codeql-custom-queries-java/android/avoid-everlasting-service.ql
new file mode 100644
index 0000000..89c1381
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-everlasting-service.ql
@@ -0,0 +1,28 @@
+/**
+ * @name Avoid Everlasting Service
+ * @description If someone calls Context#startService() then the service will continue
+ * running until Context#stopService() or Service#stopSelf() is called.
+ * Failing to call any of these methods can lead to uncontrolled energy leakage.
+ * @kind problem
+ * @problem.severity warning
+ * @precision medium
+ * @id java/android/avoid-everlasting-service
+ * @tags android
+ * @tags java
+ */
+
+import java
+
+from MethodCall startCall
+where
+ startCall.getMethod().getName() = "startService" and
+ not exists(MethodCall stopCall |
+ stopCall.getEnclosingCallable() = startCall.getEnclosingCallable() and
+ (
+ stopCall.getMethod().getName() = "stopService"
+ or
+ stopCall.getMethod().getName() = "stopSelf"
+ )
+ )
+select startCall,
+ "startService() is called here without a corresponding stopService() or stopSelf() in the same method. This may keep the service alive indefinitely and cause uncontrolled energy leakage."
\ No newline at end of file
diff --git a/codeql-custom-queries-java/android/avoid-internet-in-loop.expected b/codeql-custom-queries-java/android/avoid-internet-in-loop.expected
new file mode 100644
index 0000000..82a92be
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-internet-in-loop.expected
@@ -0,0 +1,5 @@
+| avoid-internet-in-loop.java:18:13:18:32 | openConnection(...) | URL#openConnection() is called inside a loop. Opening HTTP connections in a loop is battery-inefficient. Consider using push notifications instead of polling. |
+| avoid-internet-in-loop.java:26:13:26:32 | openConnection(...) | URL#openConnection() is called inside a loop. Opening HTTP connections in a loop is battery-inefficient. Consider using push notifications instead of polling. |
+| avoid-internet-in-loop.java:34:13:34:32 | openConnection(...) | URL#openConnection() is called inside a loop. Opening HTTP connections in a loop is battery-inefficient. Consider using push notifications instead of polling. |
+| avoid-internet-in-loop.java:43:13:43:32 | openConnection(...) | URL#openConnection() is called inside a loop. Opening HTTP connections in a loop is battery-inefficient. Consider using push notifications instead of polling. |
+| avoid-internet-in-loop.java:51:17:51:36 | openConnection(...) | URL#openConnection() is called inside a loop. Opening HTTP connections in a loop is battery-inefficient. Consider using push notifications instead of polling. |
diff --git a/codeql-custom-queries-java/android/avoid-internet-in-loop.java b/codeql-custom-queries-java/android/avoid-internet-in-loop.java
new file mode 100644
index 0000000..b2053f8
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-internet-in-loop.java
@@ -0,0 +1,81 @@
+class URL {
+ Object openConnection() { return null; }
+}
+
+class HttpURLConnection {
+ void connect() {}
+ void disconnect() {}
+ int getResponseCode() { return 200; }
+}
+
+// 🚫 Noncompliant - openConnection() inside loops
+class NoncompliantInternetInLoop {
+
+ void fetchInWhileLoop() throws Exception {
+ int i = 0;
+ while (i < 10) {
+ URL url = new URL();
+ url.openConnection(); // $ Alert
+ i++;
+ }
+ }
+
+ void fetchInForLoop() throws Exception {
+ for (int i = 0; i < 10; i++) {
+ URL url = new URL();
+ url.openConnection(); // $ Alert
+ }
+ }
+
+ void fetchInDoWhileLoop() throws Exception {
+ int i = 0;
+ do {
+ URL url = new URL();
+ url.openConnection(); // $ Alert
+ i++;
+ } while (i < 10);
+ }
+
+ void fetchInForEachLoop() throws Exception {
+ String[] endpoints = {"http://a.com", "http://b.com"};
+ for (String endpoint : endpoints) {
+ URL url = new URL();
+ url.openConnection(); // $ Alert
+ }
+ }
+
+ void fetchInNestedLoop() throws Exception {
+ for (int i = 0; i < 5; i++) {
+ for (int j = 0; j < 5; j++) {
+ URL url = new URL();
+ url.openConnection(); // $ Alert
+ }
+ }
+ }
+}
+
+// ✅ Compliant - openConnection() outside loops
+class CompliantInternetUsage {
+
+ void fetchOnce() throws Exception {
+ URL url = new URL();
+ url.openConnection();
+ }
+
+ void fetchBeforeLoop() throws Exception {
+ URL url = new URL();
+ url.openConnection();
+ for (int i = 0; i < 10; i++) {
+ // traitement sans nouvelle connexion
+ int x = i * 2;
+ }
+ }
+
+ void processItems() throws Exception {
+ String[] items = {"a", "b", "c"};
+ for (String item : items) {
+ // traitement sans ouvrir de connexion
+ String result = item.toUpperCase();
+ }
+ }
+}
\ No newline at end of file
diff --git a/codeql-custom-queries-java/android/avoid-internet-in-loop.ql b/codeql-custom-queries-java/android/avoid-internet-in-loop.ql
new file mode 100644
index 0000000..76acc6e
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-internet-in-loop.ql
@@ -0,0 +1,23 @@
+/**
+ * @name Internet In The Loop
+ * @description Opening and closing internet connections continuously is extremely battery-inefficient.
+ * Obtaining a new HttpURLConnection by calling URL#openConnection() within a loop
+ * control structure (while, for, do-while, for-each) is a bad practice that leads
+ * to uncontrolled energy leakage and prevents the use of push notifications.
+ * @kind problem
+ * @problem.severity warning
+ * @precision high
+ * @id java/android/internet-in-loop
+ * @link https://green-code-initiative.org/rules#id:GCI502
+ * @tags android
+ * @tags java
+ */
+
+import java
+
+from MethodCall openCall, LoopStmt loop
+where
+ openCall.getMethod().getName() = "openConnection" and
+ loop.getBody().getAChild*() = openCall.getEnclosingStmt()
+select openCall,
+ "URL#openConnection() is called inside a loop. Opening HTTP connections in a loop is battery-inefficient. Consider using push notifications instead of polling."
\ No newline at end of file
diff --git a/codeql-custom-queries-java/android/avoid-ligth-ui.expected b/codeql-custom-queries-java/android/avoid-ligth-ui.expected
new file mode 100644
index 0000000..c0c8fc8
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-ligth-ui.expected
@@ -0,0 +1,6 @@
+| avoid-day-night-mode.xml:5:5:5:65 | parent=Theme.AppCompat.Light | Avoid using light themes ('Theme.AppCompat.Light'). Light themes consume more energy on (AM)OLED screens. Prefer a dark theme instead. |
+| avoid-day-night-mode.xml:17:5:17:83 | parent=Theme.AppCompat.Light.DarkActionBar | Avoid using light themes ('Theme.AppCompat.Light.DarkActionBar'). Light themes consume more energy on (AM)OLED screens. Prefer a dark theme instead. |
+| avoid-ligth-ui.xml:5:5:5:65 | parent=Theme.AppCompat.Light | Avoid using light themes ('Theme.AppCompat.Light'). Light themes consume more energy on (AM)OLED screens. Prefer a dark theme instead. |
+| avoid-ligth-ui.xml:9:5:9:82 | parent=Theme.MaterialComponents.Light | Avoid using light themes ('Theme.MaterialComponents.Light'). Light themes consume more energy on (AM)OLED screens. Prefer a dark theme instead. |
+| avoid-ligth-ui.xml:13:5:13:83 | parent=Theme.AppCompat.Light.DarkActionBar | Avoid using light themes ('Theme.AppCompat.Light.DarkActionBar'). Light themes consume more energy on (AM)OLED screens. Prefer a dark theme instead. |
+| avoid-ligth-ui.xml:17:5:17:100 | parent=Theme.MaterialComponents.Light.DarkActionBar | Avoid using light themes ('Theme.MaterialComponents.Light.DarkActionBar'). Light themes consume more energy on (AM)OLED screens. Prefer a dark theme instead. |
diff --git a/codeql-custom-queries-java/android/avoid-ligth-ui.ql b/codeql-custom-queries-java/android/avoid-ligth-ui.ql
new file mode 100644
index 0000000..0a2697a
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-ligth-ui.ql
@@ -0,0 +1,24 @@
+/**
+ * @name Ligth UI
+ * @description Using a light theme (Theme.*.Light) increases energy consumption on (AM)OLED screens.
+ * By default Android sets a dark style — switching to a light theme should be avoided.
+ * Custom resources with bright colors or high-luminance bitmaps should also be avoided.
+ * @kind problem
+ * @problem.severity warning
+ * @precision high
+ * @id java/android/avoid-ligth-ui
+ * @tags android
+ * @tags java
+ *
+ * @note Test contains those for the day nigth theme detection too
+ */
+
+import semmle.code.xml.XML
+
+from XmlAttribute attr
+where
+ attr.getName() = "parent" and
+ attr.getValue().matches("%Light%") and
+ attr.getElement().getName() = "style"
+select attr,
+ "Avoid using light themes ('" + attr.getValue() + "'). Light themes consume more energy on (AM)OLED screens. Prefer a dark theme instead."
\ No newline at end of file
diff --git a/codeql-custom-queries-java/android/avoid-ligth-ui.xml b/codeql-custom-queries-java/android/avoid-ligth-ui.xml
new file mode 100644
index 0000000..78cfab6
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-ligth-ui.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/codeql-custom-queries-java/android/avoid-uncached-data-reception.expected b/codeql-custom-queries-java/android/avoid-uncached-data-reception.expected
new file mode 100644
index 0000000..dce98a9
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-uncached-data-reception.expected
@@ -0,0 +1,2 @@
+| avoid-uncached-data-reception.java:14:13:14:39 | getInputStream(...) | Avoid not caching HTTP responses. Use UncachedDataCache.install() in the same method to cache responses and save energy. |
+| avoid-uncached-data-reception.java:47:32:47:59 | getResponseCode(...) | Avoid not caching HTTP responses. Use UncachedDataCache.install() in the same method to cache responses and save energy. |
diff --git a/codeql-custom-queries-java/android/avoid-uncached-data-reception.java b/codeql-custom-queries-java/android/avoid-uncached-data-reception.java
new file mode 100644
index 0000000..c3d9172
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-uncached-data-reception.java
@@ -0,0 +1,72 @@
+// Stub minimal pour HttpResponseCache
+class UncachedDataCache {
+ static Object install(Object directory, long maxSize) { return null; }
+}
+
+// 🚫 Noncompliant - Not using HttpResponseCache
+class NoncompliantUncachedRequest {
+ void fetchData() {
+ try {
+ java.net.URL url = new java.net.URL("http://example.com");
+ java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
+
+ // $ Alert: No cache installed
+ connection.getInputStream();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
+
+// ✅ Compliant - Using HttpResponseCache
+class CompliantCachedRequest {
+ void fetchCachedData() {
+ try {
+ // OK: Cache installed at startup
+ java.io.File cacheDir = new java.io.File("cache");
+ UncachedDataCache.install(cacheDir, 1024 * 1024); // 1MB
+
+ java.net.URL url = new java.net.URL("http://example.com");
+ java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
+
+ connection.getInputStream();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
+
+// 🚫 Noncompliant - Not using HttpResponseCache
+class NoncompliantUncachedMethodRequest {
+ void fetchDataFromServer() {
+ try {
+ java.net.URL url = new java.net.URL("http://example.com");
+ java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
+
+ // $ Alert: No cache installed
+ int responseCode = connection.getResponseCode();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
+
+// ✅ Compliant - Using HttpResponseCache in a static block
+class CompliantStaticCachedRequest {
+ static {
+ // OK: Cache installed in static block
+ java.io.File cacheDir = new java.io.File("cache");
+ UncachedDataCache.install(cacheDir, 1024 * 1024); // 1MB
+ }
+
+ void fetchCachedData() {
+ try {
+ java.net.URL url = new java.net.URL("http://example.com");
+ java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
+
+ connection.getInputStream();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/codeql-custom-queries-java/android/avoid-uncached-data-reception.ql b/codeql-custom-queries-java/android/avoid-uncached-data-reception.ql
new file mode 100644
index 0000000..597efa5
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-uncached-data-reception.ql
@@ -0,0 +1,30 @@
+/**
+ * @name Uncached Data Reception
+ * @description Detects if an HTTP call (getInputStream or getResponseCode) is not directly associated with UncachedDataCache.install() in the same method.
+ * @kind problem
+ * @problem.severity warning
+ * @id java/android/avoid-uncached-data-reception
+ * @tags android
+ * @tags java
+ */
+
+import java
+
+from MethodCall httpCall
+where
+ (
+ httpCall.getMethod().hasName("getInputStream") or
+ httpCall.getMethod().hasName("getResponseCode")
+ ) and
+ not exists(MethodCall installCall |
+ installCall.getMethod().hasName("install") and
+ (
+ installCall.getEnclosingCallable() = httpCall.getEnclosingCallable()
+ or
+ installCall.getEnclosingCallable() instanceof StaticInitializer and
+ installCall.getEnclosingCallable().getDeclaringType() =
+ httpCall.getEnclosingCallable().getDeclaringType()
+ )
+ )
+select httpCall,
+ "Avoid not caching HTTP responses. Use UncachedDataCache.install() in the same method to cache responses and save energy."
\ No newline at end of file
diff --git a/codeql-custom-queries-java/android/avoid-uncompressed-data-transmission.expected b/codeql-custom-queries-java/android/avoid-uncompressed-data-transmission.expected
new file mode 100644
index 0000000..9bc79dc
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-uncompressed-data-transmission.expected
@@ -0,0 +1,3 @@
+| avoid-uncompressed-data-transmission.java:11:39:11:66 | getOutputStream(...) | Avoid using raw OutputStream for HTTP requests. Use GZIPOutputStream to compress data and reduce energy consumption. |
+| avoid-uncompressed-data-transmission.java:51:81:51:108 | getOutputStream(...) | Avoid using raw OutputStream for HTTP requests. Use GZIPOutputStream to compress data and reduce energy consumption. |
+| avoid-uncompressed-data-transmission.java:93:39:93:66 | getOutputStream(...) | Avoid using raw OutputStream for HTTP requests. Use GZIPOutputStream to compress data and reduce energy consumption. |
diff --git a/codeql-custom-queries-java/android/avoid-uncompressed-data-transmission.java b/codeql-custom-queries-java/android/avoid-uncompressed-data-transmission.java
new file mode 100644
index 0000000..94bee33
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-uncompressed-data-transmission.java
@@ -0,0 +1,125 @@
+// 🚫 Noncompliant - Using raw OutputStream for HTTP request
+class NoncompliantHttpRequest {
+
+ void sendData() {
+ try {
+ java.net.URL url = new java.net.URL("http://example.com");
+ java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
+ connection.setDoOutput(true);
+
+ // $ Alert: Using raw OutputStream
+ java.io.OutputStream os = connection.getOutputStream();
+
+ os.write("Hello, world!".getBytes());
+ os.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
+
+// ✅ Compliant - Using GZIPOutputStream for HTTP request
+class CompliantHttpRequest {
+
+ void sendCompressedData() {
+ try {
+ java.net.URL url = new java.net.URL("http://example.com");
+ java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
+ connection.setDoOutput(true);
+
+ // OK: Using GZIPOutputStream
+ java.util.zip.GZIPOutputStream gzipOs = new java.util.zip.GZIPOutputStream(connection.getOutputStream());
+
+ gzipOs.write("Hello, world!".getBytes());
+ gzipOs.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
+
+// 🚫 Noncompliant - Using raw OutputStream with BufferedOutputStream
+class NoncompliantBufferedRequest {
+
+ void sendBufferedData() {
+ try {
+ java.net.URL url = new java.net.URL("http://example.com");
+ java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
+ connection.setDoOutput(true);
+
+ // $ Alert: Using raw OutputStream (even with BufferedOutputStream)
+ java.io.BufferedOutputStream bos = new java.io.BufferedOutputStream(connection.getOutputStream());
+
+ bos.write("Hello, world!".getBytes());
+ bos.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
+
+// ✅ Compliant - Using GZIPOutputStream with BufferedOutputStream
+class CompliantBufferedRequest {
+
+ void sendCompressedBufferedData() {
+ try {
+ java.net.URL url = new java.net.URL("http://example.com");
+ java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
+ connection.setDoOutput(true);
+
+ // OK: Using GZIPOutputStream with BufferedOutputStream
+ java.io.BufferedOutputStream bos = new java.io.BufferedOutputStream(
+ new java.util.zip.GZIPOutputStream(connection.getOutputStream())
+ );
+
+ bos.write("Hello, world!".getBytes());
+ bos.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
+
+// 🚫 Noncompliant - Using raw OutputStream in a loop
+class NoncompliantLoopRequest {
+
+ void sendMultipleData() {
+ try {
+ java.net.URL url = new java.net.URL("http://example.com");
+ java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
+ connection.setDoOutput(true);
+
+ // $ Alert: Using raw OutputStream in a loop
+ java.io.OutputStream os = connection.getOutputStream();
+
+ for (int i = 0; i < 10; i++) {
+ os.write(("Data " + i).getBytes());
+ }
+ os.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
+
+// ✅ Compliant - Using GZIPOutputStream in a loop
+class CompliantLoopRequest {
+
+ void sendCompressedMultipleData() {
+ try {
+ java.net.URL url = new java.net.URL("http://example.com");
+ java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
+ connection.setDoOutput(true);
+
+ // OK: Using GZIPOutputStream in a loop
+ java.util.zip.GZIPOutputStream gzipOs = new java.util.zip.GZIPOutputStream(connection.getOutputStream());
+
+ for (int i = 0; i < 10; i++) {
+ gzipOs.write(("Data " + i).getBytes());
+ }
+ gzipOs.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/codeql-custom-queries-java/android/avoid-uncompressed-data-transmission.ql b/codeql-custom-queries-java/android/avoid-uncompressed-data-transmission.ql
new file mode 100644
index 0000000..8d2dedb
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-uncompressed-data-transmission.ql
@@ -0,0 +1,33 @@
+/**
+ * @name Uncompressed Data Transmission
+ * @description Transmitting a file over a network infrastructure without compressing it consumes more energy than with compression. Using GZIPOutputStream for HTTP requests reduces energy consumption by compressing data at least by 10% before transmission.
+ * @kind problem
+ * @problem.severity warning
+ * @precision high
+ * @id java/android/uncompressed-data-transmission
+ * @link https://green-code-initiative.org/rules#id:GCI504
+ * @tags android
+ * @tags java
+ * @tags energy
+ */
+
+import java
+
+from MethodCall mc
+where
+ mc.getMethod().getName() = "getOutputStream" and
+ not exists(
+ // Vérifie si le OutputStream est utilisé dans un appel de constructeur GZIPOutputStream
+ ConstructorCall gzipCtor |
+ gzipCtor.getConstructor().getDeclaringType().getName() = "GZIPOutputStream" and
+ gzipCtor.getAnArgument() = mc
+ ) and
+ not exists(
+ // Vérifie si le OutputStream est utilisé dans une méthode write()
+ MethodCall writeCall |
+ writeCall.getMethod().getName() = "write" and
+ writeCall.getAnArgument() instanceof Literal and
+ exists(Expr parent | parent = mc.getParent() and parent = writeCall)
+ )
+select mc,
+ "Avoid using raw OutputStream for HTTP requests. Use GZIPOutputStream to compress data and reduce energy consumption."
\ No newline at end of file
diff --git a/codeql-custom-queries-java/android/avoid-wifi-multicast-lock.expected b/codeql-custom-queries-java/android/avoid-wifi-multicast-lock.expected
new file mode 100644
index 0000000..01a20b2
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-wifi-multicast-lock.expected
@@ -0,0 +1,4 @@
+| avoid-wifi-multicast-lock.java:14:9:14:22 | acquire(...) | WifiManager.MulticastLock.acquire() is called here without a corresponding release() in the same method. This can cause significant battery drain. |
+| avoid-wifi-multicast-lock.java:27:9:27:22 | acquire(...) | WifiManager.MulticastLock.acquire() is called here without a corresponding release() in the same method. This can cause significant battery drain. |
+| avoid-wifi-multicast-lock.java:37:13:37:26 | acquire(...) | WifiManager.MulticastLock.acquire() is called here without a corresponding release() in the same method. This can cause significant battery drain. |
+| avoid-wifi-multicast-lock.java:50:17:50:30 | acquire(...) | WifiManager.MulticastLock.acquire() is called here without a corresponding release() in the same method. This can cause significant battery drain. |
diff --git a/codeql-custom-queries-java/android/avoid-wifi-multicast-lock.java b/codeql-custom-queries-java/android/avoid-wifi-multicast-lock.java
new file mode 100644
index 0000000..6723ecf
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-wifi-multicast-lock.java
@@ -0,0 +1,107 @@
+// Minimal stubs for Android SDK classes not available in javac
+class WifiManager {
+ class MulticastLock {
+ void acquire() {}
+ void release() {}
+ }
+}
+
+// 🚫 Noncompliant - acquire without release
+class Noncompliant1WifiMulticast {
+ void method1() {
+ WifiManager manager = new WifiManager();
+ WifiManager.MulticastLock lock = manager.new MulticastLock();
+ lock.acquire(); // $ Alert
+ }
+}
+
+// 🚫 Noncompliant - acquire in a separate method without release
+class Noncompliant2WifiMulticast {
+ void method1() {
+ acquireLock();
+ }
+
+ void acquireLock() {
+ WifiManager manager = new WifiManager();
+ WifiManager.MulticastLock lock = manager.new MulticastLock();
+ lock.acquire(); // $ Alert
+ }
+}
+
+// 🚫 Noncompliant - acquire in a loop without release
+class Noncompliant3WifiMulticast {
+ void method1() {
+ WifiManager manager = new WifiManager();
+ WifiManager.MulticastLock lock = manager.new MulticastLock();
+ for (int i = 0; i < 10; i++) {
+ lock.acquire(); // $ Alert
+ }
+ }
+}
+
+// 🚫 Noncompliant - acquire in an inner class without release
+class Noncompliant4WifiMulticast {
+ void method1() {
+ WifiManager manager = new WifiManager();
+ WifiManager.MulticastLock lock = manager.new MulticastLock();
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ lock.acquire(); // $ Alert
+ }
+ };
+ runnable.run();
+ }
+}
+
+// ✅ Compliant - acquire with release
+class Compliant1WifiMulticast {
+ void method1() {
+ WifiManager manager = new WifiManager();
+ WifiManager.MulticastLock lock = manager.new MulticastLock();
+ lock.acquire(); // OK
+ lock.release(); // OK
+ }
+}
+
+// ✅ Compliant - acquire and release in separate methods
+class Compliant2WifiMulticast {
+ void method1() {
+ acquireAndRelease();
+ }
+
+ void acquireAndRelease() {
+ WifiManager manager = new WifiManager();
+ WifiManager.MulticastLock lock = manager.new MulticastLock();
+ lock.acquire(); // OK
+ lock.release(); // OK
+ }
+}
+
+// ✅ Compliant - acquire and release in a loop
+class Compliant3WifiMulticast {
+ void method1() {
+ WifiManager manager = new WifiManager();
+ WifiManager.MulticastLock lock = manager.new MulticastLock();
+ for (int i = 0; i < 10; i++) {
+ lock.acquire(); // OK
+ lock.release(); // OK
+ }
+ }
+}
+
+// ✅ Compliant - acquire and release in an inner class
+class Compliant4WifiMulticast {
+ void method1() {
+ WifiManager manager = new WifiManager();
+ WifiManager.MulticastLock lock = manager.new MulticastLock();
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ lock.acquire(); // OK
+ lock.release(); // OK
+ }
+ };
+ runnable.run();
+ }
+}
diff --git a/codeql-custom-queries-java/android/avoid-wifi-multicast-lock.ql b/codeql-custom-queries-java/android/avoid-wifi-multicast-lock.ql
new file mode 100644
index 0000000..91c5a01
--- /dev/null
+++ b/codeql-custom-queries-java/android/avoid-wifi-multicast-lock.ql
@@ -0,0 +1,25 @@
+/**
+ * @name Unreleased Wifi Multicast Lock
+ * @description Acquiring a WifiManager.MulticastLock with `acquire()` allows the device to receive multicast packets,
+ * which can cause significant battery drain. The lock must be released with `release()` when no longer needed.
+ * Failing to do so can lead to uncontrolled energy consumption.
+ * @kind problem
+ * @problem.severity warning
+ * @precision high
+ * @id java/android/avoid-wifi-multicast-lock
+ * @link https://green-code-initiative.org/rules#id:GCI503
+ * @tags android
+ * @tags java
+ */
+
+import java
+
+from MethodCall acquireCall
+where
+ acquireCall.getMethod().getName() = "acquire" and
+ not exists(MethodCall releaseCall |
+ releaseCall.getEnclosingCallable() = acquireCall.getEnclosingCallable() and
+ releaseCall.getMethod().getName() = "release"
+ )
+select acquireCall,
+ "WifiManager.MulticastLock.acquire() is called here without a corresponding release() in the same method. This can cause significant battery drain."
diff --git a/codeql-custom-queries-java/android/prefer-bluetooth-low-energy.expected b/codeql-custom-queries-java/android/prefer-bluetooth-low-energy.expected
index c96a7dc..8911795 100644
--- a/codeql-custom-queries-java/android/prefer-bluetooth-low-energy.expected
+++ b/codeql-custom-queries-java/android/prefer-bluetooth-low-energy.expected
@@ -1,11 +1,11 @@
-| prefer-bluetooth-low-energy.java:25:28:25:49 | device | Avoid classic Bluetooth ('BluetoothDevice'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
-| prefer-bluetooth-low-energy.java:31:22:31:28 | adapter | Avoid classic Bluetooth ('BluetoothAdapter'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
-| prefer-bluetooth-low-energy.java:34:21:34:26 | device | Avoid classic Bluetooth ('BluetoothDevice'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
-| prefer-bluetooth-low-energy.java:37:21:37:26 | socket | Avoid classic Bluetooth ('BluetoothSocket'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
-| prefer-bluetooth-low-energy.java:40:27:40:38 | serverSocket | Avoid classic Bluetooth ('BluetoothServerSocket'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
-| prefer-bluetooth-low-energy.java:43:22:43:28 | profile | Avoid classic Bluetooth ('BluetoothProfile'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
-| prefer-bluetooth-low-energy.java:47:9:47:77 | BluetoothAdapter localAdapter | Avoid classic Bluetooth ('BluetoothAdapter'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
-| prefer-bluetooth-low-energy.java:53:9:53:66 | BluetoothAdapter a | Avoid classic Bluetooth ('BluetoothAdapter'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
-| prefer-bluetooth-low-energy.java:54:9:54:66 | BluetoothDevice remoteDevice | Avoid classic Bluetooth ('BluetoothDevice'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
-| prefer-bluetooth-low-energy.java:59:9:59:33 | BluetoothSocket s | Avoid classic Bluetooth ('BluetoothSocket'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
-| prefer-bluetooth-low-energy.java:65:9:65:40 | BluetoothServerSocket ss | Avoid classic Bluetooth ('BluetoothServerSocket'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
+| prefer-bluetooth-low-energy.java:23:28:23:49 | device | Avoid classic Bluetooth ('BluetoothDevice'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
+| prefer-bluetooth-low-energy.java:29:22:29:28 | adapter | Avoid classic Bluetooth ('BluetoothAdapter'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
+| prefer-bluetooth-low-energy.java:32:21:32:26 | device | Avoid classic Bluetooth ('BluetoothDevice'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
+| prefer-bluetooth-low-energy.java:35:21:35:26 | socket | Avoid classic Bluetooth ('BluetoothSocket'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
+| prefer-bluetooth-low-energy.java:38:27:38:38 | serverSocket | Avoid classic Bluetooth ('BluetoothServerSocket'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
+| prefer-bluetooth-low-energy.java:41:22:41:28 | profile | Avoid classic Bluetooth ('BluetoothProfile'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
+| prefer-bluetooth-low-energy.java:45:9:45:77 | BluetoothAdapter localAdapter | Avoid classic Bluetooth ('BluetoothAdapter'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
+| prefer-bluetooth-low-energy.java:51:9:51:66 | BluetoothAdapter a | Avoid classic Bluetooth ('BluetoothAdapter'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
+| prefer-bluetooth-low-energy.java:52:9:52:66 | BluetoothDevice remoteDevice | Avoid classic Bluetooth ('BluetoothDevice'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
+| prefer-bluetooth-low-energy.java:57:9:57:33 | BluetoothSocket s | Avoid classic Bluetooth ('BluetoothSocket'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
+| prefer-bluetooth-low-energy.java:63:9:63:40 | BluetoothServerSocket ss | Avoid classic Bluetooth ('BluetoothServerSocket'). Use Bluetooth Low Energy APIs from android.bluetooth.le instead to significantly reduce power consumption. |
diff --git a/codeql-custom-queries-java/android/prefer-bluetooth-low-energy.java b/codeql-custom-queries-java/android/prefer-bluetooth-low-energy.java
index 6b61fcf..9dacc6f 100644
--- a/codeql-custom-queries-java/android/prefer-bluetooth-low-energy.java
+++ b/codeql-custom-queries-java/android/prefer-bluetooth-low-energy.java
@@ -1,5 +1,3 @@
-package android.bluetooth;
-
class BluetoothAdapter {
public static BluetoothAdapter getDefaultAdapter() { return null; }
public BluetoothDevice getRemoteDevice(String address) { return null; }