Git at Google

commit61ecb02f544d9abd098506afb50cb514818f4eb4[log][tgz]
authorVictoria Lease <violets@google.com>Tue Nov 13 15:12:51 2012 -0800
committerVictoria Lease <violets@google.com>Tue Nov 13 15:12:51 2012 -0800
treecf92d9f93045d7387287284a236ad2da2bc51ac7
parent2c37f7b45522d908e1ffc5e63ffccfbe4cdea34b[diff]
Resolve LocationManager + ActivityManager conflict

LocationManagerService was serially stuffing the same Location into
multiple Intents, which it would immediately hand off to
ActivityManagerService, running as a different thread in the same
process. LocationManager would continue to work with that Location
while ActivityManagerService worked with a Parceled version of it.

However, Location.mExtras is also a Bundle, and both
ActivityManagerService and LocationManagerService ended up working
with references to the same Bundle. ActivityManagerService needs
it in Parceled form (ie mParceledData != null), but
LocationManagerService was triggering Bundle.unparcel() when
referencing the data contained within.

As a result, LocationManagerService was able to trigger NPE (or
worse) in ActivityManagerService by manipulating the mExtras
member of a Location that was in the process of being reported to
listeners.

To resolve this issue, I copy-construct a new Location to report to
each listener. This should prevent ActivityManagerService and
LocationManagerService from referencing the same Bundle data, as
Location's copy constructor also copyconstructs the mExtras member,
rather than simply share references.

Bug: 7518371
Change-Id: I1a92615cba361831494447d5de085a8d910b6b2c
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 89fa6d0..7a55497c 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -506,7 +506,7 @@
                 }
             } else {
                 Intent statusChanged = new Intent();
-                statusChanged.putExtras(extras);
+                statusChanged.putExtras(new Bundle(extras));
                 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
                 try {
                     synchronized (this) {
@@ -541,7 +541,7 @@
                 }
             } else {
                 Intent locationChanged = new Intent();
-                locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
+                locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, new Location(location));
                 try {
                     synchronized (this) {
                         // synchronize to ensure incrementPendingBroadcastsLocked()