I've merged the patch from here: https://android.googlesource.com/platform/frameworks/base/+/a40cfeb to the Replicant sources and successfully recompiled Replicant after that. I've analyzed my device one day without the patch:
http://redmine.replicant.us/boards/9/topics/7953?r=8259#message-8259
and one other day, trying to use the device mostly the same as in the first test, (same minutes in voice calls, same nightly flight mode, same way [with the train] and so on):
http://redmine.replicant.us/boards/9/topics/7953?r=9021#message-9021

So I don't really know. IMHO the patch has merit, but sadly I can't offer a benchmark which shows that you save 50% of battery power at one charge. Probably this patch has more effect on devices with more [directly|indirectly] installed app widgets...

I just can say, that everything works great after the patch. Tested several weeks on my productive device.

Ticket reference (Bug #1245): http://redmine.replicant.us/issues/1245
Please review the patch attached and apply it, if you like.
From 3a4b1bf8c318f9752e7d81a5d4765586f7e07cf3 Mon Sep 17 00:00:00 2001
From: Dianne Hackborn <[email protected]>
Date: Mon, 25 Mar 2013 17:49:36 -0700
Subject: [PATCH] Fix issue #8470131: Process thrash kills battery

Protect app widget broadcasts from abuse.

In this case the app was sending an APPWIDGET_UPDATE broadcast
without specifying a target, which (a) should not be allowed (you
should not be able to send updates to other apps), and (b) resulted
in every single potential app widget in the system being launched...
which was about 75 of them.

Change-Id: I9d48733610ce6d5a7c32e69a3e06b9f33bd79a34
Signed-off-by: Dianne Hackborn <[email protected]> Signed-off-by: Moritz Bandemer <[email protected]>
---
 core/java/android/appwidget/AppWidgetManager.java  | 17 ++++++++++----
 core/res/AndroidManifest.xml                       |  5 ++++
 .../android/server/am/ActivityManagerService.java  | 27 ++++++++++++++++++++++
 .../java/com/android/server/am/BroadcastQueue.java |  4 +++-
 .../com/android/server/am/BroadcastRecord.java     |  7 +++++-
 5 files changed, 54 insertions(+), 6 deletions(-)

diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 6b1c3e2..1f7d1ba 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -48,8 +48,8 @@ public class AppWidgetManager {
     static final String TAG = "AppWidgetManager";
 
     /**
-     * Send this from your {@link AppWidgetHost} activity when you want to pick an AppWidget to display.
-     * The AppWidget picker activity will be launched.
+     * Activity action to launch from your {@link AppWidgetHost} activity when you want to
+     * pick an AppWidget to display.  The AppWidget picker activity will be launched.
      * <p>
      * You must supply the following extras:
      * <table>
@@ -88,8 +88,8 @@ public class AppWidgetManager {
             ACTION_KEYGUARD_APPWIDGET_PICK = "android.appwidget.action.KEYGUARD_APPWIDGET_PICK";
 
     /**
-     * Send this from your {@link AppWidgetHost} activity when you want to bind an AppWidget to
-     * display and bindAppWidgetIdIfAllowed returns false.
+     * Activity action to launch from your {@link AppWidgetHost} activity when you want to bind
+     * an AppWidget to display and bindAppWidgetIdIfAllowed returns false.
      * <p>
      * You must supply the following extras:
      * <table>
@@ -268,6 +268,9 @@ public class AppWidgetManager {
     /**
      * Sent when the custom extras for an AppWidget change.
      *
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
+     *
      * @see AppWidgetProvider#onAppWidgetOptionsChanged 
      *      AppWidgetProvider.onAppWidgetOptionsChanged(Context context, 
      *      AppWidgetManager appWidgetManager, int appWidgetId, Bundle newExtras)
@@ -284,6 +287,9 @@ public class AppWidgetManager {
     /**
      * Sent when an instance of an AppWidget is removed from the last host.
      *
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
+     *
      * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
      */
     public static final String ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED";
@@ -293,6 +299,9 @@ public class AppWidgetManager {
      * This broadcast is sent at boot time if there is a AppWidgetHost installed with
      * an instance for this provider.
      *
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
+     *
      * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
      */
     public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED";
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index bd2b315..b434294 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -75,6 +75,11 @@
     <protected-broadcast android:name="android.app.action.ENTER_DESK_MODE" />
     <protected-broadcast android:name="android.app.action.EXIT_DESK_MODE" />
 
+    <protected-broadcast android:name="android.appwidget.action.APPWIDGET_UPDATE_OPTIONS" />
+    <protected-broadcast android:name="android.appwidget.action.APPWIDGET_DELETED" />
+    <protected-broadcast android:name="android.appwidget.action.APPWIDGET_DISABLED" />
+    <protected-broadcast android:name="android.appwidget.action.APPWIDGET_ENABLED" />
+
     <protected-broadcast android:name="android.backup.intent.RUN" />
     <protected-broadcast android:name="android.backup.intent.CLEAR" />
     <protected-broadcast android:name="android.backup.intent.INIT" />
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 4c83116..dc4661f 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -19,6 +19,7 @@ package com.android.server.am;
 
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
+import android.appwidget.AppWidgetManager;
 import com.android.internal.R;
 import com.android.internal.app.ThemeUtils;
 import com.android.internal.os.BatteryStatsImpl;
@@ -11737,6 +11738,32 @@ public final class ActivityManagerService extends ActivityManagerNative
                             + callingPid + ", uid=" + callingUid;
                     Slog.w(TAG, msg);
                     throw new SecurityException(msg);
+                } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(intent.getAction())) {
+                    // Special case for compatibility: we don't want apps to send this,
+                    // but historically it has not been protected and apps may be using it
+                    // to poke their own app widget.  So, instead of making it protected,
+                    // just limit it to the caller.
+                    if (callerApp == null) {
+                        String msg = "Permission Denial: not allowed to send broadcast "
+                                + intent.getAction() + " from unknown caller.";
+                        Slog.w(TAG, msg);
+                        throw new SecurityException(msg);
+                    } else if (intent.getComponent() != null) {
+                        // They are good enough to send to an explicit component...  verify
+                        // it is being sent to the calling app.
+                        if (!intent.getComponent().getPackageName().equals(
+                                callerApp.info.packageName)) {
+                            String msg = "Permission Denial: not allowed to send broadcast "
+                                    + intent.getAction() + " to "
+                                    + intent.getComponent().getPackageName() + " from "
+                                    + callerApp.info.packageName;
+                            Slog.w(TAG, msg);
+                            throw new SecurityException(msg);
+                        }
+                    } else {
+                        // Limit broadcast to their own package.
+                        intent.setPackage(callerApp.info.packageName);
+                    }
                 }
             } catch (RemoteException e) {
                 Slog.w(TAG, "Remote exception", e);
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index fc4ecda..468fd17 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -29,7 +29,6 @@ import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -1071,6 +1070,9 @@ public class BroadcastQueue {
                 pw.print("  #"); pw.print(i); pw.print(": "); pw.println(r);
                 pw.print("    ");
                 pw.println(r.intent.toShortString(false, true, true, false));
+                if (r.targetComp != null && r.targetComp != r.intent.getComponent()) {
+                    pw.print("    targetComp: "); pw.println(r.targetComp.toShortString());
+                }
                 Bundle bundle = r.intent.getExtras();
                 if (bundle != null) {
                     pw.print("    extras: "); pw.println(bundle.toString());
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index 1cf5b9c..ce14074 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -37,6 +37,7 @@ import java.util.List;
  */
 class BroadcastRecord extends Binder {
     final Intent intent;    // the original intent that generated us
+    final ComponentName targetComp; // original component name set on the intent
     final ProcessRecord callerApp; // process that sent this
     final String callerPackage; // who sent this
     final int callingPid;   // the pid of who sent this
@@ -82,9 +83,12 @@ class BroadcastRecord extends Binder {
 
         pw.print(prefix); pw.print(this); pw.print(" to user "); pw.println(userId);
         pw.print(prefix); pw.println(intent.toInsecureString());
+        if (targetComp != null && targetComp != intent.getComponent()) {
+            pw.print(prefix); pw.print("  targetComp: "); pw.println(targetComp.toShortString());
+        }
         Bundle bundle = intent.getExtras();
         if (bundle != null) {
-            pw.print(prefix); pw.print("extras: "); pw.println(bundle.toString());
+            pw.print(prefix); pw.print("  extras: "); pw.println(bundle.toString());
         }
         pw.print(prefix); pw.print("caller="); pw.print(callerPackage); pw.print(" ");
                 pw.print(callerApp != null ? callerApp.toShortString() : "null");
@@ -171,6 +175,7 @@ class BroadcastRecord extends Binder {
             int _userId) {
         queue = _queue;
         intent = _intent;
+        targetComp = _intent.getComponent();
         callerApp = _callerApp;
         callerPackage = _callerPackage;
         callingPid = _callingPid;
-- 
1.9.1

_______________________________________________
Replicant mailing list
[email protected]
http://lists.osuosl.org/mailman/listinfo/replicant

Reply via email to