summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSvetoslav Ganov <svetoslavganov@google.com>2011-03-02 12:58:40 -0800
committerSvetoslav Ganov <svetoslavganov@google.com>2011-03-02 18:22:49 -0800
commit54d068ec6af0ee6d261a135400efe6816c6f5ffe (patch)
tree066b6a2ef26c1b18c446a46803cf7429c0fe5bae
parent5a39c95c004d856b47a844c962b1c2b18f4e96aa (diff)
downloadframeworks_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
-rw-r--r--core/java/android/app/ActivityThread.java36
-rw-r--r--core/java/android/app/AppGlobals.java15
-rw-r--r--core/java/android/app/ApplicationThreadNative.java20
-rw-r--r--core/java/android/app/IApplicationThread.java5
-rw-r--r--core/java/android/provider/Settings.java6
-rw-r--r--core/java/android/view/ViewConfiguration.java12
-rw-r--r--packages/SettingsProvider/res/values/defaults.xml4
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java21
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java20
-rw-r--r--services/java/com/android/server/am/CoreSettingsObserver.java106
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);
+ }
+ }
+ }
+}