diff options
author | Svetoslav Ganov <svetoslavganov@google.com> | 2011-03-02 12:58:40 -0800 |
---|---|---|
committer | Svetoslav Ganov <svetoslavganov@google.com> | 2011-03-02 18:22:49 -0800 |
commit | 54d068ec6af0ee6d261a135400efe6816c6f5ffe (patch) | |
tree | 066b6a2ef26c1b18c446a46803cf7429c0fe5bae | |
parent | 5a39c95c004d856b47a844c962b1c2b18f4e96aa (diff) | |
download | frameworks_base-54d068ec6af0ee6d261a135400efe6816c6f5ffe.zip frameworks_base-54d068ec6af0ee6d261a135400efe6816c6f5ffe.tar.gz frameworks_base-54d068ec6af0ee6d261a135400efe6816c6f5ffe.tar.bz2 |
Add system wide management of core settings
bug:3505060
Since we want to have some settings that are used very frequently
by many applications (long-press timeout is one example) these should
be managed efficiently to reduce lookups from different processes
because in the case of a cache miss a disk I/O is performed. Now
the system manages such core settings and propagates them to the
application processes.
Change-Id: Ie793211baf8770f2181ac8ba9d7c2609dfaa32a7
10 files changed, 233 insertions, 12 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 8f9a76b..b409f2f 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -98,7 +98,6 @@ import java.util.TimeZone; import java.util.regex.Pattern; import dalvik.system.CloseGuard; -import dalvik.system.SamplingProfiler; final class SuperNotCalledException extends AndroidRuntimeException { public SuperNotCalledException(String msg) { @@ -355,6 +354,7 @@ public final class ActivityThread { boolean restrictedBackupMode; Configuration config; boolean handlingProfiling; + Bundle coreSettings; public String toString() { return "AppBindData{appInfo=" + appInfo + "}"; } @@ -552,7 +552,7 @@ public final class ActivityThread { ComponentName instrumentationName, String profileFile, Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher, int debugMode, boolean isRestrictedBackupMode, Configuration config, - Map<String, IBinder> services) { + Map<String, IBinder> services, Bundle coreSettings) { if (services != null) { // Setup the service cache in the ServiceManager @@ -570,6 +570,7 @@ public final class ActivityThread { data.debugMode = debugMode; data.restrictedBackupMode = isRestrictedBackupMode; data.config = config; + data.coreSettings = coreSettings; queueOrSendMessage(H.BIND_APPLICATION, data); } @@ -896,6 +897,10 @@ public final class ActivityThread { private void printRow(PrintWriter pw, String format, Object...objs) { pw.println(String.format(format, objs)); } + + public void setCoreSettings(Bundle settings) { + queueOrSendMessage(H.SET_CORE_SETTINGS, settings); + } } private final class H extends Handler { @@ -937,6 +942,7 @@ public final class ActivityThread { public static final int DUMP_HEAP = 135; public static final int DUMP_ACTIVITY = 136; public static final int SLEEPING = 137; + public static final int SET_CORE_SETTINGS = 138; String codeToString(int code) { if (DEBUG_MESSAGES) { switch (code) { @@ -978,6 +984,7 @@ public final class ActivityThread { case DUMP_HEAP: return "DUMP_HEAP"; case DUMP_ACTIVITY: return "DUMP_ACTIVITY"; case SLEEPING: return "SLEEPING"; + case SET_CORE_SETTINGS: return "SET_CORE_SETTINGS"; } } return "(unknown)"; @@ -1113,6 +1120,9 @@ public final class ActivityThread { case SLEEPING: handleSleeping((IBinder)msg.obj, msg.arg1 != 0); break; + case SET_CORE_SETTINGS: + handleSetCoreSettings((Bundle) msg.obj); + break; } if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what); } @@ -2709,6 +2719,14 @@ public final class ActivityThread { } } + private void handleSetCoreSettings(Bundle coreSettings) { + if (mBoundApplication != null) { + synchronized (mBoundApplication) { + mBoundApplication.coreSettings = coreSettings; + } + } + } + private final void deliverResults(ActivityClientRecord r, List<ResultInfo> results) { final int N = results.size(); for (int i=0; i<N; i++) { @@ -3971,6 +3989,20 @@ public final class ActivityThread { } } + public int getIntCoreSetting(String key, int defaultValue) { + if (mBoundApplication == null) { + return defaultValue; + } + synchronized (mBoundApplication) { + Bundle coreSettings = mBoundApplication.coreSettings; + if (coreSettings != null) { + return coreSettings.getInt(key, defaultValue); + } else { + return defaultValue; + } + } + } + public static final void main(String[] args) { SamplingProfilerIntegration.start(); diff --git a/core/java/android/app/AppGlobals.java b/core/java/android/app/AppGlobals.java index 9a39129..55515b8 100644 --- a/core/java/android/app/AppGlobals.java +++ b/core/java/android/app/AppGlobals.java @@ -38,12 +38,23 @@ public class AppGlobals { public static String getInitialPackage() { return ActivityThread.currentPackageName(); } - + /** * Return the raw interface to the package manager. - * @return + * @return The package manager. */ public static IPackageManager getPackageManager() { return ActivityThread.getPackageManager(); } + + /** + * Gets the value of an integer core setting. + * + * @param key The setting key. + * @param defaultValue The setting default value. + * @return The core settings. + */ + public static int getIntCoreSetting(String key, int defaultValue) { + return ActivityThread.currentActivityThread().getIntCoreSetting(key, defaultValue); + } } diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index ef92933..aa26b04 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -257,10 +257,11 @@ public abstract class ApplicationThreadNative extends Binder boolean restrictedBackupMode = (data.readInt() != 0); Configuration config = Configuration.CREATOR.createFromParcel(data); HashMap<String, IBinder> services = data.readHashMap(null); + Bundle coreSettings = data.readBundle(); bindApplication(packageName, info, providers, testName, profileName, testArgs, testWatcher, testMode, restrictedBackupMode, - config, services); + config, services, coreSettings); return true; } @@ -454,6 +455,13 @@ public abstract class ApplicationThreadNative extends Binder } return true; } + + case SET_CORE_SETTINGS: { + data.enforceInterface(IApplicationThread.descriptor); + Bundle settings = data.readBundle(); + setCoreSettings(settings); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -712,7 +720,7 @@ class ApplicationThreadProxy implements IApplicationThread { List<ProviderInfo> providers, ComponentName testName, String profileName, Bundle testArgs, IInstrumentationWatcher testWatcher, int debugMode, boolean restrictedBackupMode, Configuration config, - Map<String, IBinder> services) throws RemoteException { + Map<String, IBinder> services, Bundle coreSettings) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); data.writeString(packageName); @@ -731,6 +739,7 @@ class ApplicationThreadProxy implements IApplicationThread { data.writeInt(restrictedBackupMode ? 1 : 0); config.writeToParcel(data, 0); data.writeMap(services); + data.writeBundle(coreSettings); mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); @@ -938,4 +947,11 @@ class ApplicationThreadProxy implements IApplicationThread { mRemote.transact(DUMP_ACTIVITY_TRANSACTION, data, null, 0); data.recycle(); } + + public void setCoreSettings(Bundle coreSettings) throws RemoteException { + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(IApplicationThread.descriptor); + data.writeBundle(coreSettings); + mRemote.transact(SET_CORE_SETTINGS, data, null, IBinder.FLAG_ONEWAY); + } } diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index 16c3c5c..55177a9 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -82,7 +82,8 @@ public interface IApplicationThread extends IInterface { void bindApplication(String packageName, ApplicationInfo info, List<ProviderInfo> providers, ComponentName testName, String profileName, Bundle testArguments, IInstrumentationWatcher testWatcher, int debugMode, boolean restrictedBackupMode, - Configuration config, Map<String, IBinder> services) throws RemoteException; + Configuration config, Map<String, IBinder> services, + Bundle coreSettings) throws RemoteException; void scheduleExit() throws RemoteException; void scheduleSuicide() throws RemoteException; void requestThumbnail(IBinder token) throws RemoteException; @@ -110,6 +111,7 @@ public interface IApplicationThread extends IInterface { void scheduleCrash(String msg) throws RemoteException; void dumpActivity(FileDescriptor fd, IBinder servicetoken, String prefix, String[] args) throws RemoteException; + void setCoreSettings(Bundle coreSettings) throws RemoteException; String descriptor = "android.app.IApplicationThread"; @@ -151,4 +153,5 @@ public interface IApplicationThread extends IInterface { int DUMP_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+36; int CLEAR_DNS_CACHE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+37; int SET_HTTP_PROXY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+38; + int SET_CORE_SETTINGS = IBinder.FIRST_CALL_TRANSACTION+39; } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 1718189..6deb5a0 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -2698,6 +2698,12 @@ public final class Settings { "accessibility_web_content_key_bindings"; /** + * The timout for considering a press to be a long press in milliseconds. + * @hide + */ + public static final String LONG_PRESS_TIMEOUT = "long_press_timeout"; + + /** * Setting to always use the default text-to-speech settings regardless * of the application settings. * 1 = override application settings, diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index cc4e89c..d95c5b0 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -16,8 +16,11 @@ package android.view; +import android.app.AppGlobals; import android.content.Context; import android.content.res.Configuration; +import android.os.Bundle; +import android.provider.Settings; import android.util.DisplayMetrics; import android.util.SparseArray; @@ -74,7 +77,7 @@ public class ViewConfiguration { * Defines the duration in milliseconds before a press turns into * a long press */ - private static final int LONG_PRESS_TIMEOUT = 500; + private static final int DEFAULTLONG_PRESS_TIMEOUT = 500; /** * Defines the duration in milliseconds a user needs to hold down the @@ -320,15 +323,16 @@ public class ViewConfiguration { public static int getPressedStateDuration() { return PRESSED_STATE_DURATION; } - + /** * @return the duration in milliseconds before a press turns into * a long press */ public static int getLongPressTimeout() { - return LONG_PRESS_TIMEOUT; + return AppGlobals.getIntCoreSetting(Settings.Secure.LONG_PRESS_TIMEOUT, + DEFAULTLONG_PRESS_TIMEOUT); } - + /** * @return the duration in milliseconds we will wait to see if a touch event * is a tap or a scroll. If the user does not move within this interval, it is diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index 2df6d68..bf06f947 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -121,4 +121,8 @@ <integer name="def_download_manager_max_bytes_over_mobile">-1</integer> <!-- Default for Settings.Secure.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE. <=0 if no limit --> <integer name="def_download_manager_recommended_max_bytes_over_mobile">-1</integer> + + <!-- Default for Settings.Secure.LONG_PRESS_TIMEOUT_MILLIS --> + <integer name="def_long_press_timeout_millis">500</integer> + </resources> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index f336f06..d901c2c 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -819,6 +819,24 @@ public class DatabaseHelper extends SQLiteOpenHelper { upgradeVersion = 64; } + if (upgradeVersion == 64) { + // New setting to configure the long press timeout. + db.beginTransaction(); + SQLiteStatement stmt = null; + try { + stmt = db.compileStatement("INSERT INTO secure(name,value)" + + " VALUES(?,?);"); + loadIntegerSetting(stmt, Settings.Secure.LONG_PRESS_TIMEOUT, + R.integer.def_long_press_timeout_millis); + stmt.close(); + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + if (stmt != null) stmt.close(); + } + upgradeVersion = 65; + } + // *** Remember to update DATABASE_VERSION above! if (upgradeVersion != currentVersion) { @@ -1332,6 +1350,9 @@ public class DatabaseHelper extends SQLiteOpenHelper { loadSetting(stmt, Settings.Secure.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE, Integer.toString(recommendedMaxBytes)); } + + loadIntegerSetting(stmt, Settings.Secure.LONG_PRESS_TIMEOUT, + R.integer.def_long_press_timeout_millis); } finally { if (stmt != null) stmt.close(); } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index e6dfb7f..40417b1 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -717,6 +717,8 @@ public final class ActivityManagerService extends ActivityManagerNative final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions = new SparseArray<HashMap<Uri, UriPermission>>(); + CoreSettingsObserver mCoreSettingsObserver; + /** * Thread-local storage used to carry caller permissions over through * indirect content-provider access. @@ -3589,7 +3591,8 @@ public final class ActivityManagerService extends ActivityManagerNative app.instrumentationClass, app.instrumentationProfileFile, app.instrumentationArguments, app.instrumentationWatcher, testMode, isRestrictedBackupMode || !normalMode, - mConfiguration, getCommonServicesLocked()); + mConfiguration, getCommonServicesLocked(), + mCoreSettingsObserver.getCoreSettingsLocked()); updateLruProcessLocked(app, false, true); app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis(); } catch (Exception e) { @@ -5772,6 +5775,8 @@ public final class ActivityManagerService extends ActivityManagerNative if (providers != null) { mSystemThread.installSystemProviders(providers); } + + mSelf.mCoreSettingsObserver = new CoreSettingsObserver(mSelf); } /** @@ -13030,4 +13035,17 @@ public final class ActivityManagerService extends ActivityManagerNative public void monitor() { synchronized (this) { } } + + public void onCoreSettingsChange(Bundle settings) { + for (int i = mLruProcesses.size() - 1; i >= 0; i--) { + ProcessRecord processRecord = mLruProcesses.get(i); + try { + if (processRecord.thread != null) { + processRecord.thread.setCoreSettings(settings); + } + } catch (RemoteException re) { + /* ignore */ + } + } + } } diff --git a/services/java/com/android/server/am/CoreSettingsObserver.java b/services/java/com/android/server/am/CoreSettingsObserver.java new file mode 100644 index 0000000..25db84a --- /dev/null +++ b/services/java/com/android/server/am/CoreSettingsObserver.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2006-2011 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 com.android.server.am; + +import android.content.Context; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Bundle; +import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; +import android.util.Log; + +import java.util.HashMap; +import java.util.Map; + +/** + * Helper class for watching a set of core settings which the framework + * propagates to application processes to avoid multiple lookups and potentially + * disk I/O operations. Note: This class assumes that all core settings reside + * in {@link Settings.Secure}. + */ +class CoreSettingsObserver extends ContentObserver { + private static final String LOG_TAG = CoreSettingsObserver.class.getSimpleName(); + + // mapping form property name to its type + private static final Map<String, Class<?>> sCoreSettingToTypeMap = new HashMap< + String, Class<?>>(); + static { + sCoreSettingToTypeMap.put(Settings.Secure.LONG_PRESS_TIMEOUT, int.class); + // add other core settings here... + } + + private final Bundle mCoreSettings = new Bundle(); + + private final ActivityManagerService mActivityManagerService; + + public CoreSettingsObserver(ActivityManagerService activityManagerService) { + super(activityManagerService.mHandler); + mActivityManagerService = activityManagerService; + beginObserveCoreSettings(); + populateCoreSettings(mCoreSettings); + } + + public Bundle getCoreSettingsLocked() { + return (Bundle) mCoreSettings.clone(); + } + + @Override + public void onChange(boolean selfChange) { + synchronized (mActivityManagerService) { + populateCoreSettings(mCoreSettings); + mActivityManagerService.onCoreSettingsChange(mCoreSettings); + } + } + + private void beginObserveCoreSettings() { + for (String setting : sCoreSettingToTypeMap.keySet()) { + Uri uri = Settings.Secure.getUriFor(setting); + mActivityManagerService.mContext.getContentResolver().registerContentObserver( + uri, false, this); + } + } + + private void populateCoreSettings(Bundle snapshot) { + Context context = mActivityManagerService.mContext; + for (Map.Entry<String, Class<?>> entry : sCoreSettingToTypeMap.entrySet()) { + String setting = entry.getKey(); + Class<?> type = entry.getValue(); + try { + if (type == String.class) { + String value = Settings.Secure.getString(context.getContentResolver(), + setting); + snapshot.putString(setting, value); + } else if (type == int.class) { + int value = Settings.Secure.getInt(context.getContentResolver(), + setting); + snapshot.putInt(setting, value); + } else if (type == float.class) { + float value = Settings.Secure.getFloat(context.getContentResolver(), + setting); + snapshot.putFloat(setting, value); + } else if (type == long.class) { + long value = Settings.Secure.getLong(context.getContentResolver(), + setting); + snapshot.putLong(setting, value); + } + } catch (SettingNotFoundException snfe) { + Log.w(LOG_TAG, "Cannot find setting \"" + setting + "\"", snfe); + } + } + } +} |