diff options
| -rw-r--r-- | core/java/android/GoogleLocationSettingManager.java | 156 | ||||
| -rw-r--r-- | core/java/android/content/AbstractThreadedSyncAdapter.java | 9 | ||||
| -rwxr-xr-x | core/java/android/webkit/GeolocationPermissions.java | 63 | ||||
| -rw-r--r-- | core/java/android/webkit/WebSettings.java | 8 | ||||
| -rw-r--r-- | include/media/stagefright/OMXCodec.h | 1 | ||||
| -rw-r--r-- | media/libstagefright/OMXCodec.cpp | 50 | ||||
| -rw-r--r-- | services/java/com/android/server/LocationManagerService.java | 31 |
7 files changed, 300 insertions, 18 deletions
diff --git a/core/java/android/GoogleLocationSettingManager.java b/core/java/android/GoogleLocationSettingManager.java new file mode 100644 index 000000000000..fe7fce6b88b7 --- /dev/null +++ b/core/java/android/GoogleLocationSettingManager.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.webkit; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; +import android.database.ContentObserver; +import android.os.Handler; +import android.preference.PreferenceManager; +import android.provider.Settings; + +import java.util.HashSet; + +/** + * A class to manage the interaction between the system setting 'Location & + * Security - Share with Google' and the browser. When this setting is set + * to true, we allow Geolocation for Google origins. When this setting is + * set to false, we clear Geolocation permissions for Google origins. + * @hide pending API council review + */ +class GoogleLocationSettingManager { + // The application context. + private Context mContext; + // The observer used to listen to the system setting. + private GoogleLocationSettingObserver mSettingObserver; + + // The value of the system setting that indicates true. + private final static int sSystemSettingTrue = 1; + // The value of the system setting that indicates false. + private final static int sSystemSettingFalse = 0; + // The value of the USE_LOCATION_FOR_SERVICES system setting last read + // by the browser. + private final static String LAST_READ_USE_LOCATION_FOR_SERVICES = + "lastReadUseLocationForServices"; + // The Google origins we consider. + private static HashSet<String> sGoogleOrigins; + static { + sGoogleOrigins = new HashSet<String>(); + // NOTE: DO NOT ADD A "/" AT THE END! + sGoogleOrigins.add("http://www.google.com"); + sGoogleOrigins.add("http://www.google.co.uk"); + } + + GoogleLocationSettingManager(Context context) { + mContext = context; + } + + /** + * Starts the manager. Checks whether the setting has changed and + * installs an observer to listen for future changes. + */ + public void start() { + maybeApplySetting(); + + mSettingObserver = new GoogleLocationSettingObserver(); + mSettingObserver.observe(); + } + + /** + * Checks to see if the system setting has changed and if so, + * updates the Geolocation permissions accordingly. + */ + private void maybeApplySetting() { + int setting = getSystemSetting(); + if (settingChanged(setting)) { + applySetting(setting); + } + } + + /** + * Gets the current system setting for 'Use location for Google services'. + * @return The system setting. + */ + private int getSystemSetting() { + return Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.USE_LOCATION_FOR_SERVICES, + sSystemSettingFalse); + } + + /** + * Determines whether the supplied setting has changed from the last + * value read by the browser. + * @param setting The setting. + * @return Whether the setting has changed from the last value read + * by the browser. + */ + private boolean settingChanged(int setting) { + SharedPreferences preferences = + PreferenceManager.getDefaultSharedPreferences(mContext); + // Default to false. If the system setting is false the first time it is ever read by the + // browser, there's nothing to do. + int lastReadSetting = sSystemSettingFalse; + lastReadSetting = preferences.getInt(LAST_READ_USE_LOCATION_FOR_SERVICES, + lastReadSetting); + + if (lastReadSetting == setting) { + return false; + } + + Editor editor = preferences.edit(); + editor.putInt(LAST_READ_USE_LOCATION_FOR_SERVICES, setting); + editor.commit(); + return true; + } + + /** + * Applies the supplied setting to the Geolocation permissions. + * @param setting The setting. + */ + private void applySetting(int setting) { + for (String origin : sGoogleOrigins) { + if (setting == sSystemSettingTrue) { + GeolocationPermissions.getInstance().allow(origin); + } else { + GeolocationPermissions.getInstance().clear(origin); + } + } + } + + /** + * This class implements an observer to listen for changes to the + * system setting. + */ + class GoogleLocationSettingObserver extends ContentObserver { + GoogleLocationSettingObserver() { + super(new Handler()); + } + + void observe() { + ContentResolver resolver = mContext.getContentResolver(); + resolver.registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.USE_LOCATION_FOR_SERVICES), false, this); + } + + @Override + public void onChange(boolean selfChange) { + maybeApplySetting(); + } + } +} diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java index 424cb190e0f8..b01fc08defff 100644 --- a/core/java/android/content/AbstractThreadedSyncAdapter.java +++ b/core/java/android/content/AbstractThreadedSyncAdapter.java @@ -39,8 +39,9 @@ public abstract class AbstractThreadedSyncAdapter { private final AtomicInteger mNumSyncStarts; private final ISyncAdapterImpl mISyncAdapterImpl; - // all accesses to this member variable must be synchronized on "this" + // all accesses to this member variable must be synchronized on mSyncThreadLock private SyncThread mSyncThread; + private final Object mSyncThreadLock = new Object(); /** Kernel event log tag. Also listed in data/etc/event-log-tags. */ public static final int LOG_SYNC_DETAILS = 2743; @@ -71,7 +72,7 @@ public abstract class AbstractThreadedSyncAdapter { boolean alreadyInProgress; // synchronize to make sure that mSyncThread doesn't change between when we // check it and when we use it - synchronized (this) { + synchronized (mSyncThreadLock) { if (mSyncThread == null) { if (mAutoInitialize && extras != null @@ -102,7 +103,7 @@ public abstract class AbstractThreadedSyncAdapter { public void cancelSync(ISyncContext syncContext) { // synchronize to make sure that mSyncThread doesn't change between when we // check it and when we use it - synchronized (this) { + synchronized (mSyncThreadLock) { if (mSyncThread != null && mSyncThread.mSyncContext.getISyncContext() == syncContext) { mSyncThread.interrupt(); @@ -158,7 +159,7 @@ public abstract class AbstractThreadedSyncAdapter { } // synchronize so that the assignment will be seen by other threads // that also synchronize accesses to mSyncThread - synchronized (this) { + synchronized (mSyncThreadLock) { mSyncThread = null; } } diff --git a/core/java/android/webkit/GeolocationPermissions.java b/core/java/android/webkit/GeolocationPermissions.java index d06d7e2e9f0f..e985ccce6831 100755 --- a/core/java/android/webkit/GeolocationPermissions.java +++ b/core/java/android/webkit/GeolocationPermissions.java @@ -22,6 +22,7 @@ import android.util.Log; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import java.util.HashSet; import java.util.Set; @@ -50,6 +51,8 @@ public final class GeolocationPermissions { // Members used to transfer the origins and permissions between threads. private Set<String> mOrigins; private boolean mAllowed; + private Set<String> mOriginsToClear; + private Set<String> mOriginsToAllow; private static Lock mLock = new ReentrantLock(); private static boolean mUpdated; private static Condition mUpdatedCondition = mLock.newCondition(); @@ -58,7 +61,8 @@ public final class GeolocationPermissions { static final int GET_ORIGINS = 0; static final int GET_ALLOWED = 1; static final int CLEAR = 2; - static final int CLEAR_ALL = 3; + static final int ALLOW = 3; + static final int CLEAR_ALL = 4; /** * Gets the singleton instance of the class. @@ -74,6 +78,7 @@ public final class GeolocationPermissions { * Creates the message handler. Must be called on the WebKit thread. */ public void createHandler() { + mLock.lock(); if (mHandler == null) { mHandler = new Handler() { @Override @@ -89,13 +94,28 @@ public final class GeolocationPermissions { case CLEAR: nativeClear((String) msg.obj); break; + case ALLOW: + nativeAllow((String) msg.obj); + break; case CLEAR_ALL: nativeClearAll(); break; } } }; + + if (mOriginsToClear != null) { + for (String origin : mOriginsToClear) { + nativeClear(origin); + } + } + if (mOriginsToAllow != null) { + for (String origin : mOriginsToAllow) { + nativeAllow(origin); + } + } } + mLock.unlock(); } /** @@ -179,11 +199,47 @@ public final class GeolocationPermissions { } /** - * Clears the permission state for the specified origin. + * Clears the permission state for the specified origin. This method may be + * called before the WebKit thread has intialized the message handler. + * Messages will be queued until this time. */ public void clear(String origin) { // Called on the UI thread. - postMessage(Message.obtain(null, CLEAR, origin)); + mLock.lock(); + if (mHandler == null) { + if (mOriginsToClear == null) { + mOriginsToClear = new HashSet<String>(); + } + mOriginsToClear.add(origin); + if (mOriginsToAllow != null) { + mOriginsToAllow.remove(origin); + } + } else { + postMessage(Message.obtain(null, CLEAR, origin)); + } + mLock.unlock(); + } + + /** + * Allows the specified origin. This method may be called before the WebKit + * thread has intialized the message handler. Messages will be queued until + * this time. + */ + public void allow(String origin) { + // Called on the UI thread. + mLock.lock(); + if (mHandler == null) { + if (mOriginsToAllow == null) { + mOriginsToAllow = new HashSet<String>(); + } + mOriginsToAllow.add(origin); + if (mOriginsToClear != null) { + mOriginsToClear.remove(origin); + } + } else { + postMessage(Message.obtain(null, ALLOW, origin)); + } + mLock.unlock(); } /** @@ -198,5 +254,6 @@ public final class GeolocationPermissions { private static native Set nativeGetOrigins(); private static native boolean nativeGetAllowed(String origin); private static native void nativeClear(String origin); + private static native void nativeAllow(String origin); private static native void nativeClearAll(); } diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index e8b2702f5bc5..050a88644965 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -167,7 +167,7 @@ public class WebSettings { private boolean mDatabaseEnabled = false; private boolean mDomStorageEnabled = false; private boolean mWorkersEnabled = false; // only affects V8. - private boolean mGeolocationEnabled = false; + private boolean mGeolocationEnabled = true; // HTML5 configuration parameters private long mAppCacheMaxSize = Long.MAX_VALUE; private String mAppCachePath = ""; @@ -189,6 +189,10 @@ public class WebSettings { private boolean mAllowFileAccess = true; private boolean mLoadWithOverviewMode = true; + // Manages interaction of the system setting 'Location & security - Share + // with Google' and the browser. + static GoogleLocationSettingManager sGoogleLocationSettingManager; + // Class to handle messages before WebCore is ready. private class EventHandler { // Message id for syncing @@ -1315,6 +1319,8 @@ public class WebSettings { if (DebugFlags.WEB_SETTINGS) { junit.framework.Assert.assertTrue(frame.mNativeFrame != 0); } + sGoogleLocationSettingManager = new GoogleLocationSettingManager(mContext); + sGoogleLocationSettingManager.start(); nativeSync(frame.mNativeFrame); mSyncPending = false; mEventHandler.createHandler(); diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h index ff94e1000198..08d550c8f4b7 100644 --- a/include/media/stagefright/OMXCodec.h +++ b/include/media/stagefright/OMXCodec.h @@ -84,6 +84,7 @@ private: kRequiresAllocateBufferOnInputPorts = 8, kRequiresFlushCompleteEmulation = 16, kRequiresAllocateBufferOnOutputPorts = 32, + kRequiresFlushBeforeShutdown = 64, }; struct BufferInfo { diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index cdaba7c923a9..90ebd7e1feca 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -194,6 +194,11 @@ sp<OMXCodec> OMXCodec::Create( if (!strcmp(componentName, "OMX.TI.AAC.decode")) { quirks |= kNeedsFlushBeforeDisable; quirks |= kRequiresFlushCompleteEmulation; + + // The following is currently necessary for proper shutdown + // behaviour, but NOT enabled by default in order to make the + // bug reproducible... + // quirks |= kRequiresFlushBeforeShutdown; } if (!strncmp(componentName, "OMX.qcom.video.encoder.", 23)) { quirks |= kRequiresLoadedToIdleAfterAllocation; @@ -1015,6 +1020,19 @@ void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) { CHECK_EQ(portIndex, kPortIndexOutput); disablePortAsync(portIndex); + } else if (mState == EXECUTING_TO_IDLE) { + if (mPortStatus[kPortIndexInput] == ENABLED + && mPortStatus[kPortIndexOutput] == ENABLED) { + LOGV("Finished flushing both ports, now completing " + "transition from EXECUTING to IDLE."); + + mPortStatus[kPortIndexInput] = SHUTTING_DOWN; + mPortStatus[kPortIndexOutput] = SHUTTING_DOWN; + + status_t err = + mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle); + CHECK_EQ(err, OK); + } } else { // We're flushing both ports in preparation for seeking. @@ -1180,7 +1198,8 @@ void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) { } bool OMXCodec::flushPortAsync(OMX_U32 portIndex) { - CHECK(mState == EXECUTING || mState == RECONFIGURING); + CHECK(mState == EXECUTING || mState == RECONFIGURING + || mState == EXECUTING_TO_IDLE); LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.", portIndex, countBuffersWeOwn(mPortBuffers[portIndex]), @@ -1625,12 +1644,31 @@ status_t OMXCodec::stop() { { setState(EXECUTING_TO_IDLE); - mPortStatus[kPortIndexInput] = SHUTTING_DOWN; - mPortStatus[kPortIndexOutput] = SHUTTING_DOWN; + if (mQuirks & kRequiresFlushBeforeShutdown) { + LOGV("This component requires a flush before transitioning " + "from EXECUTING to IDLE..."); - status_t err = - mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle); - CHECK_EQ(err, OK); + bool emulateInputFlushCompletion = + !flushPortAsync(kPortIndexInput); + + bool emulateOutputFlushCompletion = + !flushPortAsync(kPortIndexOutput); + + if (emulateInputFlushCompletion) { + onCmdComplete(OMX_CommandFlush, kPortIndexInput); + } + + if (emulateOutputFlushCompletion) { + onCmdComplete(OMX_CommandFlush, kPortIndexOutput); + } + } else { + mPortStatus[kPortIndexInput] = SHUTTING_DOWN; + mPortStatus[kPortIndexOutput] = SHUTTING_DOWN; + + status_t err = + mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle); + CHECK_EQ(err, OK); + } while (mState != LOADED && mState != ERROR) { mAsyncCompletion.wait(mLock); diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index 2201b55beaa2..c65c2beb397d 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -120,6 +120,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run private IGpsStatusProvider mGpsStatusProvider; private LocationWorkerHandler mLocationHandler; + // Cache the real providers for use in addTestProvider() and removeTestProvider() + LocationProviderProxy mNetworkLocationProvider; + LocationProviderProxy mGpsLocationProvider; + // Handler messages private static final int MESSAGE_LOCATION_CHANGED = 1; @@ -539,6 +543,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run mGpsStatusProvider = provider.getGpsStatusProvider(); LocationProviderProxy proxy = new LocationProviderProxy(LocationManager.GPS_PROVIDER, provider); addProvider(proxy); + mGpsLocationProvider = proxy; } updateProvidersLocked(); @@ -616,6 +621,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run LocationProviderProxy proxy = new LocationProviderProxy(name, provider); addProvider(proxy); updateProvidersLocked(); + if (LocationManager.NETWORK_PROVIDER.equals(name)) { + mNetworkLocationProvider = proxy; + } // notify provider of current network state proxy.updateNetworkState(mNetworkState); @@ -1794,16 +1802,22 @@ public class LocationManagerService extends ILocationManager.Stub implements Run requiresNetwork, requiresSatellite, requiresCell, hasMonetaryCost, supportsAltitude, supportsSpeed, supportsBearing, powerRequirement, accuracy); + // remove the real provider if we are replacing GPS or network provider + if (LocationManager.GPS_PROVIDER.equals(name) + || LocationManager.NETWORK_PROVIDER.equals(name)) { + LocationProviderProxy proxy = mProvidersByName.get(name); + if (proxy != null) { + proxy.enableLocationTracking(false); + removeProvider(proxy); + } + } if (mProvidersByName.get(name) != null) { throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); } - - // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required - long identity = Binder.clearCallingIdentity(); addProvider(new LocationProviderProxy(name, provider)); mMockProviders.put(name, provider); + mLastKnownLocation.put(name, null); updateProvidersLocked(); - Binder.restoreCallingIdentity(identity); } } @@ -1816,6 +1830,15 @@ public class LocationManagerService extends ILocationManager.Stub implements Run } removeProvider(mProvidersByName.get(provider)); mMockProviders.remove(mockProvider); + // reinstall real provider if we were mocking GPS or network provider + if (LocationManager.GPS_PROVIDER.equals(provider) && + mGpsLocationProvider != null) { + addProvider(mGpsLocationProvider); + } else if (LocationManager.NETWORK_PROVIDER.equals(provider) && + mNetworkLocationProvider != null) { + addProvider(mNetworkLocationProvider); + } + mLastKnownLocation.put(provider, null); updateProvidersLocked(); } } |