summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt59
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java20
-rw-r--r--core/java/android/app/ActivityManagerNative.java21
-rw-r--r--core/java/android/app/ActivityThread.java15
-rw-r--r--core/java/android/app/IActivityManager.java2
-rw-r--r--core/java/android/net/NetworkStats.java20
-rw-r--r--core/java/android/provider/ContactsContract.java6
-rw-r--r--core/java/android/webkit/WebTextView.java24
-rw-r--r--core/java/android/widget/NumberPicker.java23
-rw-r--r--core/java/android/widget/SpellChecker.java8
-rw-r--r--core/tests/coretests/src/android/net/NetworkStatsTest.java16
-rw-r--r--graphics/java/android/graphics/SurfaceTexture.java13
-rw-r--r--opengl/include/EGL/eglext.h15
-rw-r--r--opengl/libs/EGL/egl_cache.cpp256
-rw-r--r--opengl/libs/EGL/egl_cache.h92
-rw-r--r--opengl/libs/EGL/egl_display.cpp1
-rw-r--r--opengl/libs/EGL/egl_display.h3
-rw-r--r--opengl/tests/EGLTest/Android.mk4
-rw-r--r--opengl/tests/EGLTest/egl_cache_test.cpp110
-rw-r--r--packages/SystemUI/res/values/donottranslate.xml7
-rw-r--r--policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java54
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java8
-rw-r--r--services/java/com/android/server/DockObserver.java4
-rw-r--r--services/java/com/android/server/NetworkManagementService.java6
-rw-r--r--services/java/com/android/server/PowerManagerService.java9
-rw-r--r--services/java/com/android/server/WifiService.java7
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java104
-rw-r--r--services/java/com/android/server/net/NetworkPolicyManagerService.java55
-rw-r--r--services/java/com/android/server/net/NetworkStatsService.java29
-rw-r--r--services/sensorservice/SensorService.cpp5
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp30
-rw-r--r--telephony/java/com/android/internal/telephony/DataConnectionTracker.java10
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java2
-rw-r--r--wifi/java/android/net/wifi/WifiApConfigStore.java245
-rw-r--r--wifi/java/android/net/wifi/WifiStateMachine.java109
35 files changed, 1041 insertions, 351 deletions
diff --git a/api/current.txt b/api/current.txt
index 507cdeb59418..d83659f64922 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8797,6 +8797,7 @@ package android.graphics {
method public long getTimestamp();
method public void getTransformMatrix(float[]);
method public void release();
+ method public void setDefaultBufferSize(int, int);
method public void setOnFrameAvailableListener(android.graphics.SurfaceTexture.OnFrameAvailableListener);
method public void updateTexImage();
}
@@ -16611,6 +16612,10 @@ package android.provider {
field public static final java.lang.String PHOTO_FILE_ID = "data14";
}
+ public static final class ContactsContract.Contacts.StreamItems implements android.provider.ContactsContract.StreamItemsColumns {
+ field public static final java.lang.String CONTENT_DIRECTORY = "stream_items";
+ }
+
protected static abstract interface ContactsContract.ContactsColumns {
field public static final java.lang.String DISPLAY_NAME = "display_name";
field public static final java.lang.String HAS_PHONE_NUMBER = "has_phone_number";
@@ -16868,6 +16873,10 @@ package android.provider {
field public static final java.lang.String DATA_ID = "data_id";
}
+ public static final class ContactsContract.RawContacts.StreamItems implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemsColumns {
+ field public static final java.lang.String CONTENT_DIRECTORY = "stream_items";
+ }
+
protected static abstract interface ContactsContract.RawContactsColumns {
field public static final java.lang.String AGGREGATION_MODE = "aggregation_mode";
field public static final java.lang.String CONTACT_ID = "contact_id";
@@ -16931,6 +16940,56 @@ package android.provider {
field public static final android.net.Uri PROFILE_CONTENT_URI;
}
+ public static final class ContactsContract.StreamItemPhotos implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemPhotosColumns {
+ field public static final java.lang.String PHOTO = "photo";
+ }
+
+ protected static abstract interface ContactsContract.StreamItemPhotosColumns {
+ field public static final java.lang.String PHOTO_FILE_ID = "photo_file_id";
+ field public static final java.lang.String PHOTO_URI = "photo_uri";
+ field public static final java.lang.String SORT_INDEX = "sort_index";
+ field public static final java.lang.String STREAM_ITEM_ID = "stream_item_id";
+ field public static final java.lang.String SYNC1 = "stream_item_photo_sync1";
+ field public static final java.lang.String SYNC2 = "stream_item_photo_sync2";
+ field public static final java.lang.String SYNC3 = "stream_item_photo_sync3";
+ field public static final java.lang.String SYNC4 = "stream_item_photo_sync4";
+ }
+
+ public static final class ContactsContract.StreamItems implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemsColumns {
+ field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/stream_item";
+ field public static final android.net.Uri CONTENT_LIMIT_URI;
+ field public static final android.net.Uri CONTENT_PHOTO_URI;
+ field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/stream_item";
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String MAX_ITEMS = "max_items";
+ }
+
+ public static final class ContactsContract.StreamItems.StreamItemPhotos implements android.provider.BaseColumns android.provider.ContactsContract.StreamItemPhotosColumns {
+ field public static final java.lang.String CONTENT_DIRECTORY = "photo";
+ field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/stream_item_photo";
+ field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/stream_item_photo";
+ }
+
+ protected static abstract interface ContactsContract.StreamItemsColumns {
+ field public static final java.lang.String ACCOUNT_NAME = "account_name";
+ field public static final java.lang.String ACCOUNT_TYPE = "account_type";
+ field public static final java.lang.String COMMENTS = "comments";
+ field public static final java.lang.String CONTACT_ID = "contact_id";
+ field public static final java.lang.String CONTACT_LOOKUP_KEY = "contact_lookup";
+ field public static final java.lang.String DATA_SET = "data_set";
+ field public static final java.lang.String RAW_CONTACT_ID = "raw_contact_id";
+ field public static final java.lang.String RAW_CONTACT_SOURCE_ID = "raw_contact_source_id";
+ field public static final java.lang.String RES_ICON = "icon";
+ field public static final java.lang.String RES_LABEL = "label";
+ field public static final java.lang.String RES_PACKAGE = "res_package";
+ field public static final java.lang.String SYNC1 = "stream_item_sync1";
+ field public static final java.lang.String SYNC2 = "stream_item_sync2";
+ field public static final java.lang.String SYNC3 = "stream_item_sync3";
+ field public static final java.lang.String SYNC4 = "stream_item_sync4";
+ field public static final java.lang.String TEXT = "text";
+ field public static final java.lang.String TIMESTAMP = "timestamp";
+ }
+
protected static abstract interface ContactsContract.SyncColumns implements android.provider.ContactsContract.BaseSyncColumns {
field public static final java.lang.String ACCOUNT_NAME = "account_name";
field public static final java.lang.String ACCOUNT_TYPE = "account_type";
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 4f722893d453..7c03a2ff2020 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -109,6 +109,10 @@ public class Am {
runStartService();
} else if (op.equals("force-stop")) {
runForceStop();
+ } else if (op.equals("kill")) {
+ runKill();
+ } else if (op.equals("kill-all")) {
+ runKillAll();
} else if (op.equals("instrument")) {
runInstrument();
} else if (op.equals("broadcast")) {
@@ -484,6 +488,14 @@ public class Am {
mAm.forceStopPackage(nextArgRequired());
}
+ private void runKill() throws Exception {
+ mAm.killBackgroundProcesses(nextArgRequired());
+ }
+
+ private void runKillAll() throws Exception {
+ mAm.killAllBackgroundProcesses();
+ }
+
private void sendBroadcast() throws Exception {
Intent intent = makeIntent();
IntentReceiver receiver = new IntentReceiver();
@@ -1179,6 +1191,8 @@ public class Am {
" [--R COUNT] [-S] <INTENT>\n" +
" am startservice <INTENT>\n" +
" am force-stop <PACKAGE>\n" +
+ " am kill <PACKAGE>\n" +
+ " am kill-all\n" +
" am broadcast <INTENT>\n" +
" am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" +
" [--no-window-animation] <COMPONENT>\n" +
@@ -1202,6 +1216,12 @@ public class Am {
"\n" +
"am force-stop: force stop everything associated with <PACKAGE>.\n" +
"\n" +
+ "am kill: Kill all processes associated with <PACKAGE>. Only kills.\n" +
+ " processes that are safe to kill -- that is, will not impact the user\n" +
+ " experience.\n" +
+ "\n" +
+ "am kill-all: Kill all background processes.\n" +
+ "\n" +
"am broadcast: send a broadcast Intent.\n" +
"\n" +
"am instrument: start an Instrumentation. Typically this target <COMPONENT>\n" +
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index b4471f096ad5..7994d7cd3bfb 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1092,6 +1092,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeNoException();
return true;
}
+
+ case KILL_ALL_BACKGROUND_PROCESSES_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ killAllBackgroundProcesses();
+ reply.writeNoException();
+ return true;
+ }
case FORCE_STOP_PACKAGE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
@@ -2906,7 +2913,7 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
-
+
public void killBackgroundProcesses(String packageName) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -2917,7 +2924,17 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
-
+
+ public void killAllBackgroundProcesses() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(KILL_ALL_BACKGROUND_PROCESSES_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
public void forceStopPackage(String packageName) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 00fe953f70e3..a4714cab3542 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3832,11 +3832,16 @@ public final class ActivityThread {
* Initialize the default http proxy in this process for the reasons we set the time zone.
*/
IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
- IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
- try {
- ProxyProperties proxyProperties = service.getProxy();
- Proxy.setHttpProxySystemProperty(proxyProperties);
- } catch (RemoteException e) {}
+ if (b != null) {
+ // In pre-boot mode (doing initial launch to collect password), not
+ // all system is up. This includes the connectivity service, so don't
+ // crash if we can't get it.
+ IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
+ try {
+ ProxyProperties proxyProperties = service.getProxy();
+ Proxy.setHttpProxySystemProperty(proxyProperties);
+ } catch (RemoteException e) {}
+ }
if (data.instrumentationName != null) {
ContextImpl appContext = new ContextImpl();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 26813bf117df..5222d375a439 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -234,6 +234,7 @@ public interface IActivityManager extends IInterface {
public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) throws RemoteException;
public void killBackgroundProcesses(final String packageName) throws RemoteException;
+ public void killAllBackgroundProcesses() throws RemoteException;
public void forceStopPackage(final String packageName) throws RemoteException;
// Note: probably don't want to allow applications access to these.
@@ -605,4 +606,5 @@ public interface IActivityManager extends IInterface {
int GET_PROCESS_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+136;
int SHOW_BOOT_MESSAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+137;
int DISMISS_KEYGUARD_ON_NEXT_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+138;
+ int KILL_ALL_BACKGROUND_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+139;
}
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 5c6ef1a9eac8..36056529c3a6 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -165,6 +165,17 @@ public class NetworkStats implements Parcelable {
dest.writeLongArray(operations);
}
+ @Override
+ public NetworkStats clone() {
+ final NetworkStats clone = new NetworkStats(elapsedRealtime, size);
+ NetworkStats.Entry entry = null;
+ for (int i = 0; i < size; i++) {
+ entry = getValues(i, entry);
+ clone.addValues(entry);
+ }
+ return clone;
+ }
+
// @VisibleForTesting
public NetworkStats addIfaceValues(
String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) {
@@ -455,7 +466,7 @@ public class NetworkStats implements Parcelable {
public NetworkStats subtract(NetworkStats value) throws NonMonotonicException {
final long deltaRealtime = this.elapsedRealtime - value.elapsedRealtime;
if (deltaRealtime < 0) {
- throw new IllegalArgumentException("found non-monotonic realtime");
+ throw new NonMonotonicException(this, value);
}
// result will have our rows, and elapsed time between snapshots
@@ -575,7 +586,8 @@ public class NetworkStats implements Parcelable {
pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
for (int i = 0; i < size; i++) {
pw.print(prefix);
- pw.print(" iface="); pw.print(iface[i]);
+ pw.print(" ["); pw.print(i); pw.print("]");
+ pw.print(" iface="); pw.print(iface[i]);
pw.print(" uid="); pw.print(uid[i]);
pw.print(" set="); pw.print(setToString(set[i]));
pw.print(" tag="); pw.print(tagToString(tag[i]));
@@ -638,6 +650,10 @@ public class NetworkStats implements Parcelable {
public final int leftIndex;
public final int rightIndex;
+ public NonMonotonicException(NetworkStats left, NetworkStats right) {
+ this(left, -1, right, -1);
+ }
+
public NonMonotonicException(
NetworkStats left, int leftIndex, NetworkStats right, int rightIndex) {
this.left = checkNotNull(left, "missing left");
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index ff28596a207f..821b6df5fd15 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1673,7 +1673,6 @@ public final class ContactsContract {
* Querying for social stream data requires android.permission.READ_SOCIAL_STREAM
* permission.
* </p>
- * @hide
*/
public static final class StreamItems implements StreamItemsColumns {
/**
@@ -2736,7 +2735,6 @@ public final class ContactsContract {
* inserting or updating social stream items requires android.permission.WRITE_SOCIAL_STREAM
* permission.
* </p>
- * @hide
*/
public static final class StreamItems implements BaseColumns, StreamItemsColumns {
/**
@@ -3149,7 +3147,6 @@ public final class ContactsContract {
* </pre>
* </dd>
* </dl>
- * @hide
*/
public static final class StreamItems implements BaseColumns, StreamItemsColumns {
/**
@@ -3247,7 +3244,6 @@ public final class ContactsContract {
* Columns in the StreamItems table.
*
* @see ContactsContract.StreamItems
- * @hide
*/
protected interface StreamItemsColumns {
/**
@@ -3538,7 +3534,6 @@ public final class ContactsContract {
* <pre>
* </dd>
* </dl>
- * @hide
*/
public static final class StreamItemPhotos implements BaseColumns, StreamItemPhotosColumns {
/**
@@ -3566,7 +3561,6 @@ public final class ContactsContract {
* Columns in the StreamItemPhotos table.
*
* @see ContactsContract.StreamItemPhotos
- * @hide
*/
protected interface StreamItemPhotosColumns {
/**
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 5ee1b8a66067..8aafc3d078fe 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -16,14 +16,9 @@
package android.webkit;
-import com.android.internal.widget.EditableInputConnection;
-
import android.content.Context;
-import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.ColorFilter;
import android.graphics.Paint;
-import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
@@ -60,12 +55,12 @@ import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.TextView;
+import junit.framework.Assert;
+
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
-import junit.framework.Assert;
-
/**
* WebTextView is a specialized version of EditText used by WebView
* to overlay html textfields (and textareas) to use our standard
@@ -926,18 +921,23 @@ import junit.framework.Assert;
*/
/* package */ void setRect(int x, int y, int width, int height) {
LayoutParams lp = (LayoutParams) getLayoutParams();
+ boolean needsUpdate = false;
if (null == lp) {
lp = new LayoutParams(width, height, x, y);
} else {
- lp.x = x;
- lp.y = y;
- lp.width = width;
- lp.height = height;
+ if ((lp.x != x) || (lp.y != y) || (lp.width != width)
+ || (lp.height != height)) {
+ needsUpdate = true;
+ lp.x = x;
+ lp.y = y;
+ lp.width = width;
+ lp.height = height;
+ }
}
if (getParent() == null) {
// Insert the view so that it's drawn first (at index 0)
mWebView.addView(this, 0, lp);
- } else {
+ } else if (needsUpdate) {
setLayoutParams(lp);
}
// Set up a measure spec so a layout can always be recreated.
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 5ab99dcfa184..1a1b8d04365f 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -741,9 +741,16 @@ public class NumberPicker extends LinearLayout {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final int newWidthMeasureSpec = makeMeasureSpec(widthMeasureSpec, mMinWidth, mMaxWidth);
- final int newHeightMeasureSpec = makeMeasureSpec(heightMeasureSpec, mMinHeight, mMaxHeight);
+ // Try greedily to fit the max width and height.
+ final int newWidthMeasureSpec = makeMeasureSpec(widthMeasureSpec, mMaxWidth);
+ final int newHeightMeasureSpec = makeMeasureSpec(heightMeasureSpec, mMaxHeight);
super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec);
+ // Flag if we are measured with width or height less than the respective min.
+ final int desiredWidth = Math.max(mMinWidth, getMeasuredWidth());
+ final int desiredHeight = Math.max(mMinHeight, getMeasuredHeight());
+ final int widthSize = resolveSizeAndState(desiredWidth, newWidthMeasureSpec, 0);
+ final int heightSize = resolveSizeAndState(desiredHeight, newHeightMeasureSpec, 0);
+ setMeasuredDimension(widthSize, heightSize);
}
@Override
@@ -1357,23 +1364,19 @@ public class NumberPicker extends LinearLayout {
* Makes a measure spec that tries greedily to use the max value.
*
* @param measureSpec The measure spec.
- * @param maxValue The max value for the size.
+ * @param maxSize The max value for the size.
* @return A measure spec greedily imposing the max size.
*/
- private int makeMeasureSpec(int measureSpec, int minValue, int maxValue) {
+ private int makeMeasureSpec(int measureSpec, int maxSize) {
final int size = MeasureSpec.getSize(measureSpec);
- if (size < minValue) {
- throw new IllegalArgumentException("Available space is less than min size: "
- + size + " < " + minValue);
- }
final int mode = MeasureSpec.getMode(measureSpec);
switch (mode) {
case MeasureSpec.EXACTLY:
return measureSpec;
case MeasureSpec.AT_MOST:
- return MeasureSpec.makeMeasureSpec(Math.min(size, maxValue), MeasureSpec.EXACTLY);
+ return MeasureSpec.makeMeasureSpec(Math.min(size, maxSize), MeasureSpec.EXACTLY);
case MeasureSpec.UNSPECIFIED:
- return MeasureSpec.makeMeasureSpec(maxValue, MeasureSpec.EXACTLY);
+ return MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.EXACTLY);
default:
throw new IllegalArgumentException("Unknown measure mode: " + mode);
}
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index e929e7d55b56..87c3e9bc8b25 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -82,6 +82,8 @@ public class SpellChecker implements SpellCheckerSessionListener {
}
private void setLocale(Locale locale) {
+ closeSession();
+
final TextServicesManager textServicesManager = (TextServicesManager)
mTextView.getContext().getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
if (!textServicesManager.isSpellCheckerEnabled()) {
@@ -104,12 +106,6 @@ public class SpellChecker implements SpellCheckerSessionListener {
// Change SpellParsers' wordIterator locale
mWordIterator = new WordIterator(locale);
- // Stop all SpellParsers
- final int length = mSpellParsers.length;
- for (int i = 0; i < length; i++) {
- mSpellParsers[i].finish();
- }
-
// Remove existing misspelled SuggestionSpans
mTextView.removeMisspelledSpans((Editable) mTextView.getText());
diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java
index b37eb466e1ca..098464f9f013 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java
@@ -294,6 +294,22 @@ public class NetworkStatsTest extends TestCase {
assertValues(after, 1, TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 128L, 8L, 0L, 0L, 0L);
}
+ public void testClone() throws Exception {
+ final NetworkStats original = new NetworkStats(TEST_START, 5)
+ .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L)
+ .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L);
+
+ // make clone and mutate original
+ final NetworkStats clone = original.clone();
+ original.addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L);
+
+ assertEquals(3, original.size());
+ assertEquals(2, clone.size());
+
+ assertEquals(128L + 512L + 128L, original.getTotalBytes());
+ assertEquals(128L + 512L, clone.getTotalBytes());
+ }
+
private static void assertValues(NetworkStats stats, int index, String iface, int uid, int set,
int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
final NetworkStats.Entry entry = stats.getValues(index, null);
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index f3b62ec10e51..29fab11603a4 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -130,10 +130,17 @@ public class SurfaceTexture {
}
/**
- * Set the size of buffers returned by requestBuffers when a width and height
- * of zero is requested.
+ * Set the default size of the image buffers. The image producer may override the buffer size,
+ * in which case the producer-set buffer size will be used, not the default size set by this
+ * method. Both video and camera based image producers do override the size. This method may
+ * be used to set the image size when producing images with {@link android.graphics.Canvas} (via
+ * {@link android.view.Surface#lockCanvas}), or OpenGL ES (via an EGLSurface).
*
- * @hide Pending approval by API council.
+ * The new default buffer size will take effect the next time the image producer requests a
+ * buffer to fill. For {@link android.graphics.Canvas} this will be the next time {@link
+ * android.view.Surface#lockCanvas} is called. For OpenGL ES, the EGLSurface should be
+ * destroyed (via eglDestroySurface), made not-current (via eglMakeCurrent), and then recreated
+ * (via eglCreateWindowSurface) to ensure that the new default size has taken effect.
*/
public void setDefaultBufferSize(int width, int height) {
nativeSetDefaultBufferSize(width, height);
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index a08932a3dd64..8e8e26c0a849 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -256,6 +256,21 @@ typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC)(void);
typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC)(void);
#endif
+
+/* EGL_ANDROID_blob_cache
+ */
+#ifndef EGL_ANDROID_blob_cache
+#define EGL_ANDROID_blob_cache 1
+typedef khronos_ssize_t EGLsizei;
+typedef void (*EGLSetBlobFunc) (const void* key, EGLsizei keySize, const void* value, EGLsizei valueSize);
+typedef EGLsizei (*EGLGetBlobFunc) (const void* key, EGLsizei keySize, void* value, EGLsizei valueSize);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI void EGLAPIENTRY eglSetBlobCacheFuncs(EGLDisplay dpy, EGLSetBlobFunc set, EGLGetBlobFunc get);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef void (EGLAPIENTRYP PFNEGLSETBLOBCACHEFUNCSPROC) (EGLDisplay dpy,
+ EGLSetBlobFunc set, EGLGetBlobFunc get);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index 1e64302f26a9..aa40d5888ce5 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -19,6 +19,21 @@
#include "egl_impl.h"
#include "egldefs.h"
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+// Cache size limits.
+static const size_t maxKeySize = 1024;
+static const size_t maxValueSize = 4096;
+static const size_t maxTotalSize = 64 * 1024;
+
+// Cache file header
+static const char* cacheFileMagic = "EGL$";
+static const size_t cacheFileHeaderSize = 8;
+
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
@@ -26,37 +41,37 @@ namespace android {
#define BC_EXT_STR "EGL_ANDROID_blob_cache"
//
-// EGL_ANDROID_blob_cache types and functions
+// Callback functions passed to EGL.
//
-typedef khronos_ssize_t EGLsizei;
-
-typedef void (*EGLSetBlobFunc) (const void* key, EGLsizei keySize,
- const void* value, EGLsizei valueSize);
-
-typedef EGLsizei (*EGLGetBlobFunc) (const void* key, EGLsizei keySize,
- void* value, EGLsizei valueSize);
+static void setBlob(const void* key, EGLsizei keySize, const void* value,
+ EGLsizei valueSize) {
+ egl_cache_t::get()->setBlob(key, keySize, value, valueSize);
+}
-typedef void (EGLAPIENTRYP PFNEGLSETBLOBCACHEFUNCSPROC) (EGLDisplay dpy,
- EGLSetBlobFunc set, EGLGetBlobFunc get);
+static EGLsizei getBlob(const void* key, EGLsizei keySize, void* value,
+ EGLsizei valueSize) {
+ return egl_cache_t::get()->getBlob(key, keySize, value, valueSize);
+}
//
// egl_cache_t definition
//
-static void setBlob(const void* key, EGLsizei keySize, const void* value,
- EGLsizei valueSize) {
+egl_cache_t::egl_cache_t() :
+ mInitialized(false),
+ mBlobCache(NULL) {
}
-static EGLsizei getBlob(const void* key, EGLsizei keySize, void* value,
- EGLsizei valueSize) {
- return 0;
+egl_cache_t::~egl_cache_t() {
}
+egl_cache_t egl_cache_t::sCache;
+
egl_cache_t* egl_cache_t::get() {
- static egl_cache_t theCache;
- return &theCache;
+ return &sCache;
}
void egl_cache_t::initialize(egl_display_t *display) {
+ Mutex::Autolock lock(mMutex);
for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
@@ -79,7 +94,8 @@ void egl_cache_t::initialize(egl_display_t *display) {
continue;
}
- eglSetBlobCacheFuncs(display->disp[i].dpy, setBlob, getBlob);
+ eglSetBlobCacheFuncs(display->disp[i].dpy, android::setBlob,
+ android::getBlob);
EGLint err = cnx->egl.eglGetError();
if (err != EGL_SUCCESS) {
LOGE("eglSetBlobCacheFuncs resulted in an error: %#x",
@@ -88,6 +104,210 @@ void egl_cache_t::initialize(egl_display_t *display) {
}
}
}
+ mInitialized = true;
+}
+
+void egl_cache_t::terminate() {
+ Mutex::Autolock lock(mMutex);
+ if (mBlobCache != NULL) {
+ saveBlobCacheLocked();
+ mBlobCache = NULL;
+ }
+ mInitialized = false;
+}
+
+void egl_cache_t::setBlob(const void* key, EGLsizei keySize, const void* value,
+ EGLsizei valueSize) {
+ Mutex::Autolock lock(mMutex);
+
+ if (keySize < 0 || valueSize < 0) {
+ LOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed");
+ return;
+ }
+
+ if (mInitialized) {
+ sp<BlobCache> bc = getBlobCacheLocked();
+ bc->set(key, keySize, value, valueSize);
+ }
+}
+
+EGLsizei egl_cache_t::getBlob(const void* key, EGLsizei keySize, void* value,
+ EGLsizei valueSize) {
+ Mutex::Autolock lock(mMutex);
+
+ if (keySize < 0 || valueSize < 0) {
+ LOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed");
+ return 0;
+ }
+
+ if (mInitialized) {
+ sp<BlobCache> bc = getBlobCacheLocked();
+ return bc->get(key, keySize, value, valueSize);
+ }
+ return 0;
+}
+
+void egl_cache_t::setCacheFilename(const char* filename) {
+ Mutex::Autolock lock(mMutex);
+ mFilename = filename;
+}
+
+sp<BlobCache> egl_cache_t::getBlobCacheLocked() {
+ if (mBlobCache == NULL) {
+ mBlobCache = new BlobCache(maxKeySize, maxValueSize, maxTotalSize);
+ loadBlobCacheLocked();
+ }
+ return mBlobCache;
+}
+
+static uint32_t crc32c(const uint8_t* buf, size_t len) {
+ const uint32_t polyBits = 0x82F63B78;
+ uint32_t r = 0;
+ for (size_t i = 0; i < len; i++) {
+ r ^= buf[i];
+ for (int j = 0; j < 8; j++) {
+ if (r & 1) {
+ r = (r >> 1) ^ polyBits;
+ } else {
+ r >>= 1;
+ }
+ }
+ }
+ return r;
+}
+
+void egl_cache_t::saveBlobCacheLocked() {
+ if (mFilename.length() > 0) {
+ size_t cacheSize = mBlobCache->getFlattenedSize();
+ size_t headerSize = cacheFileHeaderSize;
+ const char* fname = mFilename.string();
+
+ // Try to create the file with no permissions so we can write it
+ // without anyone trying to read it.
+ int fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0);
+ if (fd == -1) {
+ if (errno == EEXIST) {
+ // The file exists, delete it and try again.
+ if (unlink(fname) == -1) {
+ // No point in retrying if the unlink failed.
+ LOGE("error unlinking cache file %s: %s (%d)", fname,
+ strerror(errno), errno);
+ return;
+ }
+ // Retry now that we've unlinked the file.
+ fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0);
+ }
+ if (fd == -1) {
+ LOGE("error creating cache file %s: %s (%d)", fname,
+ strerror(errno), errno);
+ return;
+ }
+ }
+
+ size_t fileSize = headerSize + cacheSize;
+ if (ftruncate(fd, fileSize) == -1) {
+ LOGE("error setting cache file size: %s (%d)", strerror(errno),
+ errno);
+ close(fd);
+ unlink(fname);
+ return;
+ }
+
+ uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize,
+ PROT_WRITE, MAP_SHARED, fd, 0));
+ if (buf == MAP_FAILED) {
+ LOGE("error mmaping cache file: %s (%d)", strerror(errno),
+ errno);
+ close(fd);
+ unlink(fname);
+ return;
+ }
+
+ status_t err = mBlobCache->flatten(buf + headerSize, cacheSize, NULL,
+ 0);
+ if (err != OK) {
+ LOGE("error writing cache contents: %s (%d)", strerror(-err),
+ -err);
+ munmap(buf, fileSize);
+ close(fd);
+ unlink(fname);
+ return;
+ }
+
+ // Write the file magic and CRC
+ memcpy(buf, cacheFileMagic, 4);
+ uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
+ *crc = crc32c(buf + headerSize, cacheSize);
+
+ munmap(buf, fileSize);
+ fchmod(fd, S_IRUSR);
+ close(fd);
+ }
+}
+
+void egl_cache_t::loadBlobCacheLocked() {
+ if (mFilename.length() > 0) {
+ size_t headerSize = cacheFileHeaderSize;
+
+ int fd = open(mFilename.string(), O_RDONLY, 0);
+ if (fd == -1) {
+ if (errno != ENOENT) {
+ LOGE("error opening cache file %s: %s (%d)", mFilename.string(),
+ strerror(errno), errno);
+ }
+ return;
+ }
+
+ struct stat statBuf;
+ if (fstat(fd, &statBuf) == -1) {
+ LOGE("error stat'ing cache file: %s (%d)", strerror(errno), errno);
+ close(fd);
+ return;
+ }
+
+ // Sanity check the size before trying to mmap it.
+ size_t fileSize = statBuf.st_size;
+ if (fileSize > maxTotalSize * 2) {
+ LOGE("cache file is too large: %#llx", statBuf.st_size);
+ close(fd);
+ return;
+ }
+
+ uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize,
+ PROT_READ, MAP_PRIVATE, fd, 0));
+ if (buf == MAP_FAILED) {
+ LOGE("error mmaping cache file: %s (%d)", strerror(errno),
+ errno);
+ close(fd);
+ return;
+ }
+
+ // Check the file magic and CRC
+ size_t cacheSize = fileSize - headerSize;
+ if (memcmp(buf, cacheFileMagic, 4) != 0) {
+ LOGE("cache file has bad mojo");
+ close(fd);
+ return;
+ }
+ uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
+ if (crc32c(buf + headerSize, cacheSize) != *crc) {
+ LOGE("cache file failed CRC check");
+ close(fd);
+ return;
+ }
+
+ status_t err = mBlobCache->unflatten(buf + headerSize, cacheSize, NULL, 0);
+ if (err != OK) {
+ LOGE("error reading cache contents: %s (%d)", strerror(-err),
+ -err);
+ munmap(buf, fileSize);
+ close(fd);
+ return;
+ }
+
+ munmap(buf, fileSize);
+ close(fd);
+ }
}
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_cache.h b/opengl/libs/EGL/egl_cache.h
index 1fcfaccd8509..05d5873181e5 100644
--- a/opengl/libs/EGL/egl_cache.h
+++ b/opengl/libs/EGL/egl_cache.h
@@ -14,20 +14,110 @@
** limitations under the License.
*/
+#ifndef ANDROID_EGL_CACHE_H
+#define ANDROID_EGL_CACHE_H
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <utils/BlobCache.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
class egl_display_t;
-class egl_cache_t {
+class EGLAPI egl_cache_t {
public:
+ // get returns a pointer to the singleton egl_cache_t object. This
+ // singleton object will never be destroyed.
static egl_cache_t* get();
+ // initialize puts the egl_cache_t into an initialized state, such that it
+ // is able to insert and retrieve entries from the cache. This should be
+ // called when EGL is initialized. When not in the initialized state the
+ // getBlob and setBlob methods will return without performing any cache
+ // operations.
void initialize(egl_display_t* display);
+
+ // terminate puts the egl_cache_t back into the uninitialized state. When
+ // in this state the getBlob and setBlob methods will return without
+ // performing any cache operations.
+ void terminate();
+
+ // setBlob attempts to insert a new key/value blob pair into the cache.
+ // This will be called by the hardware vendor's EGL implementation via the
+ // EGL_ANDROID_blob_cache extension.
+ void setBlob(const void* key, EGLsizei keySize, const void* value,
+ EGLsizei valueSize);
+
+ // getBlob attempts to retrieve the value blob associated with a given key
+ // blob from cache. This will be called by the hardware vendor's EGL
+ // implementation via the EGL_ANDROID_blob_cache extension.
+ EGLsizei getBlob(const void* key, EGLsizei keySize, void* value,
+ EGLsizei valueSize);
+
+ // setCacheFilename sets the name of the file that should be used to store
+ // cache contents from one program invocation to another.
+ void setCacheFilename(const char* filename);
+
+private:
+ // Creation and (the lack of) destruction is handled internally.
+ egl_cache_t();
+ ~egl_cache_t();
+
+ // Copying is disallowed.
+ egl_cache_t(const egl_cache_t&); // not implemented
+ void operator=(const egl_cache_t&); // not implemented
+
+ // getBlobCacheLocked returns the BlobCache object being used to store the
+ // key/value blob pairs. If the BlobCache object has not yet been created,
+ // this will do so, loading the serialized cache contents from disk if
+ // possible.
+ sp<BlobCache> getBlobCacheLocked();
+
+ // saveBlobCache attempts to save the current contents of mBlobCache to
+ // disk.
+ void saveBlobCacheLocked();
+
+ // loadBlobCache attempts to load the saved cache contents from disk into
+ // mBlobCache.
+ void loadBlobCacheLocked();
+
+ // mInitialized indicates whether the egl_cache_t is in the initialized
+ // state. It is initialized to false at construction time, and gets set to
+ // true when initialize is called. It is set back to false when terminate
+ // is called. When in this state, the cache behaves as normal. When not,
+ // the getBlob and setBlob methods will return without performing any cache
+ // operations.
+ bool mInitialized;
+
+ // mBlobCache is the cache in which the key/value blob pairs are stored. It
+ // is initially NULL, and will be initialized by getBlobCacheLocked the
+ // first time it's needed.
+ sp<BlobCache> mBlobCache;
+
+ // mFilename is the name of the file for storing cache contents in between
+ // program invocations. It is initialized to an empty string at
+ // construction time, and can be set with the setCacheFilename method. An
+ // empty string indicates that the cache should not be saved to or restored
+ // from disk.
+ String8 mFilename;
+
+ // mMutex is the mutex used to prevent concurrent access to the member
+ // variables. It must be locked whenever the member variables are accessed.
+ mutable Mutex mMutex;
+
+ // sCache is the singleton egl_cache_t object.
+ static egl_cache_t sCache;
};
// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------
+
+#endif // ANDROID_EGL_CACHE_H
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 0f92864635c8..558ca77ff994 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -44,6 +44,7 @@ egl_display_t::egl_display_t() :
egl_display_t::~egl_display_t() {
magic = 0;
+ egl_cache_t::get()->terminate();
}
egl_display_t* egl_display_t::get(EGLDisplay dpy) {
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 113595f17907..1c1092cd428d 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -59,7 +59,7 @@ struct egl_config_t {
// ----------------------------------------------------------------------------
-class egl_display_t {
+class EGLAPI egl_display_t { // marked as EGLAPI for testing purposes
static egl_display_t sDisplay[NUM_DISPLAYS];
EGLDisplay getDisplay(EGLNativeDisplayType display);
@@ -141,4 +141,3 @@ EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface);
// ----------------------------------------------------------------------------
#endif // ANDROID_EGL_DISPLAY_H
-
diff --git a/opengl/tests/EGLTest/Android.mk b/opengl/tests/EGLTest/Android.mk
index 92d7eb12ac9d..14104d171ee0 100644
--- a/opengl/tests/EGLTest/Android.mk
+++ b/opengl/tests/EGLTest/Android.mk
@@ -7,6 +7,7 @@ LOCAL_MODULE := EGL_test
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := \
+ egl_cache_test.cpp \
EGL_test.cpp \
LOCAL_SHARED_LIBRARIES := \
@@ -21,9 +22,12 @@ LOCAL_STATIC_LIBRARIES := \
LOCAL_C_INCLUDES := \
bionic \
+ bionic/libc/private \
bionic/libstdc++/include \
external/gtest/include \
external/stlport/stlport \
+ frameworks/base/opengl/libs \
+ frameworks/base/opengl/libs/EGL \
include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/EGLTest/egl_cache_test.cpp b/opengl/tests/EGLTest/egl_cache_test.cpp
new file mode 100644
index 000000000000..c7d9e3e201dc
--- /dev/null
+++ b/opengl/tests/EGLTest/egl_cache_test.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define LOG_TAG "EGL_test"
+//#define LOG_NDEBUG 0
+
+#include <gtest/gtest.h>
+
+#include <utils/Log.h>
+
+#include "egl_cache.h"
+#include "egl_display.h"
+
+namespace android {
+
+class EGLCacheTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
+ mCache = egl_cache_t::get();
+ }
+
+ virtual void TearDown() {
+ mCache->setCacheFilename("");
+ mCache->terminate();
+ }
+
+ egl_cache_t* mCache;
+};
+
+TEST_F(EGLCacheTest, UninitializedCacheAlwaysMisses) {
+ char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ mCache->setBlob("abcd", 4, "efgh", 4);
+ ASSERT_EQ(0, mCache->getBlob("abcd", 4, buf, 4));
+ ASSERT_EQ(0xee, buf[0]);
+ ASSERT_EQ(0xee, buf[1]);
+ ASSERT_EQ(0xee, buf[2]);
+ ASSERT_EQ(0xee, buf[3]);
+}
+
+TEST_F(EGLCacheTest, InitializedCacheAlwaysHits) {
+ char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY));
+ mCache->setBlob("abcd", 4, "efgh", 4);
+ ASSERT_EQ(4, mCache->getBlob("abcd", 4, buf, 4));
+ ASSERT_EQ('e', buf[0]);
+ ASSERT_EQ('f', buf[1]);
+ ASSERT_EQ('g', buf[2]);
+ ASSERT_EQ('h', buf[3]);
+}
+
+TEST_F(EGLCacheTest, TerminatedCacheAlwaysMisses) {
+ char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY));
+ mCache->setBlob("abcd", 4, "efgh", 4);
+ mCache->terminate();
+ ASSERT_EQ(0, mCache->getBlob("abcd", 4, buf, 4));
+ ASSERT_EQ(0xee, buf[0]);
+ ASSERT_EQ(0xee, buf[1]);
+ ASSERT_EQ(0xee, buf[2]);
+ ASSERT_EQ(0xee, buf[3]);
+}
+
+class EGLCacheSerializationTest : public EGLCacheTest {
+
+protected:
+
+ virtual void SetUp() {
+ EGLCacheTest::SetUp();
+
+ char* tn = tempnam("/sdcard", "EGL_test-cache-");
+ mFilename = tn;
+ free(tn);
+ }
+
+ virtual void TearDown() {
+ unlink(mFilename.string());
+ EGLCacheTest::TearDown();
+ }
+
+ String8 mFilename;
+};
+
+TEST_F(EGLCacheSerializationTest, ReinitializedCacheContainsValues) {
+ char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ mCache->setCacheFilename(mFilename);
+ mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY));
+ mCache->setBlob("abcd", 4, "efgh", 4);
+ mCache->terminate();
+ mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY));
+ ASSERT_EQ(4, mCache->getBlob("abcd", 4, buf, 4));
+ ASSERT_EQ('e', buf[0]);
+ ASSERT_EQ('f', buf[1]);
+ ASSERT_EQ('g', buf[2]);
+ ASSERT_EQ('h', buf[3]);
+}
+
+}
diff --git a/packages/SystemUI/res/values/donottranslate.xml b/packages/SystemUI/res/values/donottranslate.xml
index 93ec481258f5..089a54db5e86 100644
--- a/packages/SystemUI/res/values/donottranslate.xml
+++ b/packages/SystemUI/res/values/donottranslate.xml
@@ -18,8 +18,9 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- For formatting day of week and date in DateView. %1$s is DOW, %2$s is date.
- In Roman locales we now show only the date, but DOW is available for other locales if
- necessary. -->
- <string name="status_bar_date_formatter">%2$s</string>
+ We show both (DOW on one line, then the date) but this can be overridden for locales as
+ necessary.
+ -->
+ <string name="status_bar_date_formatter">%1$s\n%2$s</string>
</resources>
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 81e1901f398a..0f21bdb475a4 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -360,8 +360,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler
mHasOverlay = true;
// Continue showing FaceLock area until dialer comes up or call is resumed
- if (mLockPatternUtils.usingBiometricWeak() &&
- mLockPatternUtils.isBiometricWeakInstalled() && mFaceLockServiceRunning) {
+ if (usingFaceLock() && mFaceLockServiceRunning) {
showFaceLockAreaWithTimeout(FACELOCK_VIEW_AREA_EMERGENCY_DIALER_TIMEOUT);
}
@@ -582,8 +581,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler
bindToFaceLock();
// Show FaceLock area, but only for a little bit so lockpattern will become visible if
// FaceLock fails to start or crashes
- if (mLockPatternUtils.usingBiometricWeak() &&
- mLockPatternUtils.isBiometricWeakInstalled()) {
+ if (usingFaceLock()) {
showFaceLockAreaWithTimeout(FACELOCK_VIEW_AREA_SERVICE_TIMEOUT);
}
} else {
@@ -653,11 +651,10 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler
((KeyguardScreen) mUnlockScreen).onResume();
}
- if (mLockPatternUtils.usingBiometricWeak() &&
- mLockPatternUtils.isBiometricWeakInstalled() && !mHasOverlay) {
+ if (usingFaceLock() && !mHasOverlay) {
// Note that show() gets called before the screen turns off to set it up for next time
// it is turned on. We don't want to set a timeout on the FaceLock area here because it
- // may be gone by the time the screen is turned on again. We set the timout when the
+ // may be gone by the time the screen is turned on again. We set the timeout when the
// screen turns on instead.
showFaceLockArea();
} else {
@@ -854,7 +851,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler
if (mode == Mode.UnlockScreen) {
final UnlockMode unlockMode = getUnlockMode();
if (force || mUnlockScreen == null || unlockMode != mUnlockScreenMode) {
+ boolean restartFaceLock = stopFaceLockIfRunning();
recreateUnlockScreen(unlockMode);
+ if (restartFaceLock) activateFaceLockIfAble();
}
}
@@ -1147,28 +1146,33 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler
// Everything below pertains to FaceLock - might want to separate this out
- // Take care of FaceLock area when layout is created
+ // Indicates whether FaceLock is in use
+ private boolean usingFaceLock() {
+ return (mLockPatternUtils.usingBiometricWeak() &&
+ mLockPatternUtils.isBiometricWeakInstalled());
+ }
+
+ // Takes care of FaceLock area when layout is created
private void initializeFaceLockAreaView(View view) {
- if (mLockPatternUtils.usingBiometricWeak() &&
- mLockPatternUtils.isBiometricWeakInstalled()) {
+ if (usingFaceLock()) {
mFaceLockAreaView = view.findViewById(R.id.faceLockAreaView);
if (mFaceLockAreaView == null) {
Log.e(TAG, "Layout does not have faceLockAreaView and FaceLock is enabled");
- } else {
- if (mBoundToFaceLockService) {
- // If we are creating a layout when we are already bound to FaceLock, then we
- // are undergoing an orientation change. Stop FaceLock and restart it in the
- // new location.
- if (DEBUG) Log.d(TAG, "Restarting FL - creating view while already bound");
- stopAndUnbindFromFaceLock();
- activateFaceLockIfAble();
- }
}
} else {
mFaceLockAreaView = null; // Set to null if not using FaceLock
}
}
+ // Stops FaceLock if it is running and reports back whether it was running or not
+ private boolean stopFaceLockIfRunning() {
+ if (usingFaceLock() && mBoundToFaceLockService) {
+ stopAndUnbindFromFaceLock();
+ return true;
+ }
+ return false;
+ }
+
// Handles covering or exposing FaceLock area on the client side when FaceLock starts or stops
// This needs to be done in a handler because the call could be coming from a callback from the
// FaceLock service that is in a thread that can't modify the UI
@@ -1221,8 +1225,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler
// Binds to FaceLock service. This call does not tell it to start, but it causes the service
// to call the onServiceConnected callback, which then starts FaceLock.
public void bindToFaceLock() {
- if (mLockPatternUtils.usingBiometricWeak() &&
- mLockPatternUtils.isBiometricWeakInstalled()) {
+ if (usingFaceLock()) {
if (!mBoundToFaceLockService) {
if (DEBUG) Log.d(TAG, "before bind to FaceLock service");
mContext.bindService(new Intent(IFaceLockInterface.class.getName()),
@@ -1238,8 +1241,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler
// Tells FaceLock to stop and then unbinds from the FaceLock service
public void stopAndUnbindFromFaceLock() {
- if (mLockPatternUtils.usingBiometricWeak() &&
- mLockPatternUtils.isBiometricWeakInstalled()) {
+ if (usingFaceLock()) {
stopFaceLock();
if (mBoundToFaceLockService) {
@@ -1300,8 +1302,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler
// Tells the FaceLock service to start displaying its UI and perform recognition
public void startFaceLock(IBinder windowToken, int x, int y, int h, int w)
{
- if (mLockPatternUtils.usingBiometricWeak() &&
- mLockPatternUtils.isBiometricWeakInstalled()) {
+ if (usingFaceLock()) {
synchronized (mFaceLockServiceRunningLock) {
if (!mFaceLockServiceRunning) {
if (DEBUG) Log.d(TAG, "Starting FaceLock");
@@ -1322,8 +1323,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase implements Handler
// Tells the FaceLock service to stop displaying its UI and stop recognition
public void stopFaceLock()
{
- if (mLockPatternUtils.usingBiometricWeak() &&
- mLockPatternUtils.isBiometricWeakInstalled()) {
+ if (usingFaceLock()) {
// Note that attempting to stop FaceLock when it's not running is not an issue.
// FaceLock can return, which stops it and then we try to stop it when the
// screen is turned off. That's why we check.
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 7d97246c1fa6..aa1c81c07b9e 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -493,7 +493,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return true;
}
if ((mCarDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_CAR) ||
- (mDeskDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_DESK)) {
+ (mDeskDockEnablesAccelerometer && (mDockMode == Intent.EXTRA_DOCK_STATE_DESK
+ || mDockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
+ || mDockMode == Intent.EXTRA_DOCK_STATE_HE_DESK))) {
// enable accelerometer if we are docked in a dock that enables accelerometer
// orientation management,
return true;
@@ -3137,7 +3139,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// enable 180 degree rotation while docked.
preferredRotation = mCarDockEnablesAccelerometer
? sensorRotation : mCarDockRotation;
- } else if (mDockMode == Intent.EXTRA_DOCK_STATE_DESK
+ } else if ((mDockMode == Intent.EXTRA_DOCK_STATE_DESK
+ || mDockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
+ || mDockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
&& (mDeskDockEnablesAccelerometer || mDeskDockRotation >= 0)) {
// Ignore sensor when in desk dock unless explicitly enabled.
// This case can override the behavior of NOSENSOR, and can also
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index dea900786874..64789d33692d 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -82,7 +82,9 @@ class DockObserver extends UEventObserver {
// Don't force screen on when undocking from the desk dock.
// The change in power state will do this anyway.
// FIXME - we should be configurable.
- if (mPreviousDockState != Intent.EXTRA_DOCK_STATE_DESK ||
+ if ((mPreviousDockState != Intent.EXTRA_DOCK_STATE_DESK
+ && mPreviousDockState != Intent.EXTRA_DOCK_STATE_LE_DESK
+ && mPreviousDockState != Intent.EXTRA_DOCK_STATE_HE_DESK) ||
mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
mPowerManager.userActivityWithForce(SystemClock.uptimeMillis(),
false, true);
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 6887de32e112..da960aeae5e3 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -1136,12 +1136,14 @@ public class NetworkManagementService extends INetworkManagementService.Stub
final StringBuilder command = new StringBuilder();
command.append("bandwidth removeiquota ").append(iface);
+ mActiveQuotaIfaces.remove(iface);
+ mActiveAlertIfaces.remove(iface);
+
try {
// TODO: support quota shared across interfaces
mConnector.doCommand(command.toString());
- mActiveQuotaIfaces.remove(iface);
- mActiveAlertIfaces.remove(iface);
} catch (NativeDaemonConnectorException e) {
+ // TODO: include current iptables state
throw new IllegalStateException("Error communicating to native daemon", e);
}
}
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 1b0addfdae4e..6b23b33ae7bb 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -100,10 +100,13 @@ public class PowerManagerService extends IPowerManager.Stub
private static final int LONG_KEYLIGHT_DELAY = 6000; // t+6 sec
private static final int LONG_DIM_TIME = 7000; // t+N-5 sec
- // How long to wait to debounce light sensor changes.
+ // How long to wait to debounce light sensor changes in milliseconds
private static final int LIGHT_SENSOR_DELAY = 2000;
- // For debouncing the proximity sensor.
+ // light sensor events rate in microseconds
+ private static final int LIGHT_SENSOR_RATE = 1000000;
+
+ // For debouncing the proximity sensor in milliseconds
private static final int PROXIMITY_SENSOR_DELAY = 1000;
// trigger proximity if distance is less than 5 cm
@@ -3049,7 +3052,7 @@ public class PowerManagerService extends IPowerManager.Stub
try {
if (enable) {
mSensorManager.registerListener(mLightListener, mLightSensor,
- SensorManager.SENSOR_DELAY_NORMAL);
+ LIGHT_SENSOR_RATE);
} else {
mSensorManager.unregisterListener(mLightListener);
mHandler.removeCallbacks(mAutoBrightnessTask);
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 01eade136f19..3c65255ca5bf 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -619,12 +619,7 @@ public class WifiService extends IWifiManager.Stub {
*/
public WifiConfiguration getWifiApConfiguration() {
enforceAccessPermission();
- if (mWifiStateMachineChannel != null) {
- return mWifiStateMachine.syncGetWifiApConfiguration(mWifiStateMachineChannel);
- } else {
- Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
- return null;
- }
+ return mWifiStateMachine.syncGetWifiApConfiguration();
}
/**
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 4fe8119ba19b..05d42ada146c 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1220,6 +1220,8 @@ public final class ActivityManagerService extends ActivityManagerNative
}
Thread thread = new Thread() {
@Override public void run() {
+ StringBuilder dropBuilder = new StringBuilder(1024);
+ StringBuilder logBuilder = new StringBuilder(1024);
try {
java.lang.Process proc = Runtime.getRuntime().exec(new String[] {
"procrank", });
@@ -1233,16 +1235,29 @@ public final class ActivityManagerService extends ActivityManagerNative
break;
}
if (line.length() > 0) {
- Slog.i(TAG, line);
+ logBuilder.append(line);
+ logBuilder.append('\n');
}
+ dropBuilder.append(line);
+ dropBuilder.append('\n');
}
converter.close();
} catch (IOException e) {
}
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
- dumpApplicationMemoryUsage(null, pw, " ", new String[] { }, true);
- Slog.i(TAG, sw.toString());
+ StringWriter catSw = new StringWriter();
+ PrintWriter catPw = new PrintWriter(catSw);
+ dumpApplicationMemoryUsage(null, pw, " ", new String[] { }, true, catPw);
+ String memUsage = sw.toString();
+ dropBuilder.append('\n');
+ dropBuilder.append(memUsage);
+ dropBuilder.append(catSw.toString());
+ logBuilder.append(memUsage);
+ addErrorToDropBox("watchdog", null, "system_server", null,
+ null, "Low on memory -- no more background processes",
+ dropBuilder.toString(), null, null);
+ Slog.i(TAG, logBuilder.toString());
synchronized (ActivityManagerService.this) {
long now = SystemClock.uptimeMillis();
if (mLastMemUsageReportTime < now) {
@@ -1394,7 +1409,7 @@ public final class ActivityManagerService extends ActivityManagerNative
return;
}
- mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, false);
+ mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, false, null);
}
}
@@ -3192,7 +3207,49 @@ public final class ActivityManagerService extends ActivityManagerNative
return;
}
killPackageProcessesLocked(packageName, pkgUid,
- ProcessList.SERVICE_ADJ, false, true, true, false);
+ ProcessList.SERVICE_ADJ, false, true, true, false, "kill background");
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ public void killAllBackgroundProcesses() {
+ if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
+ != PackageManager.PERMISSION_GRANTED) {
+ String msg = "Permission Denial: killAllBackgroundProcesses() from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+
+ long callingId = Binder.clearCallingIdentity();
+ try {
+ synchronized(this) {
+ ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
+ for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
+ final int NA = apps.size();
+ for (int ia=0; ia<NA; ia++) {
+ ProcessRecord app = apps.valueAt(ia);
+ if (app.persistent) {
+ // we don't kill persistent processes
+ continue;
+ }
+ if (app.removed) {
+ procs.add(app);
+ } else if (app.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
+ app.removed = true;
+ procs.add(app);
+ }
+ }
+ }
+
+ int N = procs.size();
+ for (int i=0; i<N; i++) {
+ removeProcessLocked(procs.get(i), false, true, "kill all background");
+ }
}
} finally {
Binder.restoreCallingIdentity(callingId);
@@ -3364,7 +3421,7 @@ public final class ActivityManagerService extends ActivityManagerNative
private final boolean killPackageProcessesLocked(String packageName, int uid,
int minOomAdj, boolean callerWillRestart, boolean allowRestart, boolean doit,
- boolean evenPersistent) {
+ boolean evenPersistent, String reason) {
ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
// Remove all processes this package may have touched: all with the
@@ -3399,7 +3456,7 @@ public final class ActivityManagerService extends ActivityManagerNative
int N = procs.size();
for (int i=0; i<N; i++) {
- removeProcessLocked(procs.get(i), callerWillRestart, allowRestart);
+ removeProcessLocked(procs.get(i), callerWillRestart, allowRestart, reason);
}
return N > 0;
}
@@ -3430,7 +3487,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
boolean didSomething = killPackageProcessesLocked(name, uid, -100,
- callerWillRestart, false, doit, evenPersistent);
+ callerWillRestart, false, doit, evenPersistent, "force stop");
TaskRecord lastTask = null;
for (i=0; i<mMainStack.mHistory.size(); i++) {
@@ -3518,11 +3575,11 @@ public final class ActivityManagerService extends ActivityManagerNative
}
private final boolean removeProcessLocked(ProcessRecord app,
- boolean callerWillRestart, boolean allowRestart) {
+ boolean callerWillRestart, boolean allowRestart, String reason) {
final String name = app.processName;
final int uid = app.info.uid;
if (DEBUG_PROCESSES) Slog.d(
- TAG, "Force removing process " + app + " (" + name
+ TAG, "Force removing proc " + app.toShortString() + " (" + name
+ "/" + uid + ")");
mProcessNames.remove(name, uid);
@@ -3537,9 +3594,10 @@ public final class ActivityManagerService extends ActivityManagerNative
mPidsSelfLocked.remove(pid);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
+ Slog.i(TAG, "Killing proc " + app.toShortString() + ": " + reason);
handleAppDiedLocked(app, true, allowRestart);
mLruProcesses.remove(app);
- Process.killProcess(pid);
+ Process.killProcessQuiet(pid);
if (app.persistent) {
if (!callerWillRestart) {
@@ -6846,7 +6904,7 @@ public final class ActivityManagerService extends ActivityManagerNative
for (int i=procsToKill.size()-1; i>=0; i--) {
ProcessRecord proc = procsToKill.get(i);
Slog.i(TAG, "Removing system update proc: " + proc);
- removeProcessLocked(proc, true, false);
+ removeProcessLocked(proc, true, false, "system update done");
}
}
@@ -7042,7 +7100,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// Don't let services in this process be restarted and potentially
// annoy the user repeatedly. Unless it is persistent, since those
// processes run critical code.
- removeProcessLocked(app, false, false);
+ removeProcessLocked(app, false, false, "crash");
mMainStack.resumeTopActivityLocked(null);
return false;
}
@@ -9298,8 +9356,10 @@ public final class ActivityManagerService extends ActivityManagerNative
}
final void dumpApplicationMemoryUsage(FileDescriptor fd,
- PrintWriter pw, String prefix, String[] args, boolean brief) {
+ PrintWriter pw, String prefix, String[] args, boolean brief,
+ PrintWriter categoryPw) {
boolean dumpAll = false;
+ boolean oomOnly = false;
int opti = 0;
while (opti < args.length) {
@@ -9310,9 +9370,12 @@ public final class ActivityManagerService extends ActivityManagerNative
opti++;
if ("-a".equals(opt)) {
dumpAll = true;
+ } else if ("--oom".equals(opt)) {
+ oomOnly = true;
} else if ("-h".equals(opt)) {
- pw.println("meminfo dump options: [-a] [process]");
+ pw.println("meminfo dump options: [-a] [--oom] [process]");
pw.println(" -a: include all available information for each process.");
+ pw.println(" --oom: only show processes organized by oom adj.");
pw.println("If [process] is specified it can be the name or ");
pw.println("pid of a specific process to dump.");
return;
@@ -9438,7 +9501,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- if (!brief) {
+ if (!brief && !oomOnly) {
pw.println();
pw.println("Total PSS by process:");
dumpMemItems(pw, " ", procMems, true);
@@ -9446,10 +9509,11 @@ public final class ActivityManagerService extends ActivityManagerNative
}
pw.println("Total PSS by OOM adjustment:");
dumpMemItems(pw, " ", oomMems, false);
- if (!brief) {
- pw.println();
- pw.println("Total PSS by category:");
- dumpMemItems(pw, " ", catMems, true);
+ if (!oomOnly) {
+ PrintWriter out = categoryPw != null ? categoryPw : pw;
+ out.println();
+ out.println("Total PSS by category:");
+ dumpMemItems(out, " ", catMems, true);
}
pw.println();
pw.print("Total PSS: "); pw.print(totalPss); pw.println(" Kb");
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 289ea1fe1019..2a1b1db0bf77 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -190,6 +190,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final int MSG_METERED_IFACES_CHANGED = 2;
private static final int MSG_FOREGROUND_ACTIVITIES_CHANGED = 3;
private static final int MSG_PROCESS_DIED = 4;
+ private static final int MSG_LIMIT_REACHED = 5;
private final Context mContext;
private final IActivityManager mActivityManager;
@@ -225,8 +226,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
/** Set of currently active {@link Notification} tags. */
private HashSet<String> mActiveNotifs = Sets.newHashSet();
- /** Current values from {@link #setPolicyDataEnable(int, boolean)}. */
- private SparseBooleanArray mActiveNetworkEnabled = new SparseBooleanArray();
/** Foreground at both UID and PID granularity. */
private SparseBooleanArray mUidForeground = new SparseBooleanArray();
@@ -424,19 +423,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// only someone like NMS should be calling us
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- synchronized (mRulesLock) {
- if (mMeteredIfaces.contains(iface) && !LIMIT_GLOBAL_ALERT.equals(limitName)) {
- try {
- // force stats update to make sure we have numbers that
- // caused alert to trigger.
- mNetworkStats.forceUpdate();
- } catch (RemoteException e) {
- // ignored; service lives in system_server
- }
-
- updateNetworkEnabledLocked();
- updateNotificationsLocked();
- }
+ if (!LIMIT_GLOBAL_ALERT.equals(limitName)) {
+ mHandler.obtainMessage(MSG_LIMIT_REACHED, iface).sendToTarget();
}
}
};
@@ -1481,6 +1469,25 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
return true;
}
+ case MSG_LIMIT_REACHED: {
+ final String iface = (String) msg.obj;
+
+ synchronized (mRulesLock) {
+ if (mMeteredIfaces.contains(iface)) {
+ try {
+ // force stats update to make sure we have
+ // numbers that caused alert to trigger.
+ mNetworkStats.forceUpdate();
+ } catch (RemoteException e) {
+ // ignored; service lives in system_server
+ }
+
+ updateNetworkEnabledLocked();
+ updateNotificationsLocked();
+ }
+ }
+ return true;
+ }
default: {
return false;
}
@@ -1519,21 +1526,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
/**
- * Control {@link IConnectivityManager#setPolicyDataEnable(int, boolean)},
- * dispatching only when actually changed.
+ * Control {@link IConnectivityManager#setPolicyDataEnable(int, boolean)}.
*/
private void setPolicyDataEnable(int networkType, boolean enabled) {
- synchronized (mActiveNetworkEnabled) {
- final boolean prevEnabled = mActiveNetworkEnabled.get(networkType, true);
- if (prevEnabled == enabled) return;
-
- try {
- mConnManager.setPolicyDataEnable(networkType, enabled);
- } catch (RemoteException e) {
- // ignored; service lives in system_server
- }
-
- mActiveNetworkEnabled.put(networkType, enabled);
+ try {
+ mConnManager.setPolicyDataEnable(networkType, enabled);
+ } catch (RemoteException e) {
+ // ignored; service lives in system_server
}
}
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 494c655ba048..77b0d96f4242 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -152,10 +152,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private static final String TAG_NETSTATS_ERROR = "netstats_error";
- private static final String DEV = "dev";
- private static final String XT = "xt";
- private static final String UID = "uid";
-
private final Context mContext;
private final INetworkManagementService mNetworkManager;
private final IAlarmManager mAlarmManager;
@@ -278,6 +274,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
readNetworkXtStatsLocked();
}
+ // bootstrap initial stats to prevent double-counting later
+ bootstrapStats();
+
// watch for network interfaces to be claimed
final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE);
mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
@@ -311,9 +310,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
registerPollAlarmLocked();
registerGlobalAlert();
- // bootstrap initial stats to prevent double-counting later
- bootstrapStats();
-
mDropBox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
}
@@ -837,9 +833,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// persist when enough network data has occurred
final long persistNetworkDevDelta = computeStatsDelta(
- mLastPersistNetworkDevSnapshot, networkDevSnapshot, true, DEV).getTotalBytes();
+ mLastPersistNetworkDevSnapshot, networkDevSnapshot, true, "devp").getTotalBytes();
final long persistNetworkXtDelta = computeStatsDelta(
- mLastPersistNetworkXtSnapshot, networkXtSnapshot, true, XT).getTotalBytes();
+ mLastPersistNetworkXtSnapshot, networkXtSnapshot, true, "xtp").getTotalBytes();
final boolean networkOverThreshold = persistNetworkDevDelta > threshold
|| persistNetworkXtDelta > threshold;
if (persistForce || (persistNetwork && networkOverThreshold)) {
@@ -851,7 +847,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// persist when enough uid data has occurred
final long persistUidDelta = computeStatsDelta(
- mLastPersistUidSnapshot, uidSnapshot, true, UID).getTotalBytes();
+ mLastPersistUidSnapshot, uidSnapshot, true, "uidp").getTotalBytes();
if (persistForce || (persistUid && persistUidDelta > threshold)) {
writeUidStatsLocked();
mLastPersistUidSnapshot = uidSnapshot;
@@ -880,7 +876,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final HashSet<String> unknownIface = Sets.newHashSet();
final NetworkStats delta = computeStatsDelta(
- mLastPollNetworkDevSnapshot, networkDevSnapshot, false, DEV);
+ mLastPollNetworkDevSnapshot, networkDevSnapshot, false, "dev");
final long timeStart = currentTime - delta.getElapsedRealtime();
NetworkStats.Entry entry = null;
@@ -910,7 +906,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final HashSet<String> unknownIface = Sets.newHashSet();
final NetworkStats delta = computeStatsDelta(
- mLastPollNetworkXtSnapshot, networkXtSnapshot, false, XT);
+ mLastPollNetworkXtSnapshot, networkXtSnapshot, false, "xt");
final long timeStart = currentTime - delta.getElapsedRealtime();
NetworkStats.Entry entry = null;
@@ -940,9 +936,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
ensureUidStatsLoadedLocked();
final NetworkStats delta = computeStatsDelta(
- mLastPollUidSnapshot, uidSnapshot, false, UID);
+ mLastPollUidSnapshot, uidSnapshot, false, "uid");
final NetworkStats operationsDelta = computeStatsDelta(
- mLastPollOperationsSnapshot, mOperations, false, UID);
+ mLastPollOperationsSnapshot, mOperations, false, "uidop");
final long timeStart = currentTime - delta.getElapsedRealtime();
NetworkStats.Entry entry = null;
@@ -971,8 +967,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
mLastPollUidSnapshot = uidSnapshot;
- mLastPollOperationsSnapshot = mOperations;
- mOperations = new NetworkStats(0L, 10);
+ mLastPollOperationsSnapshot = mOperations.clone();
}
/**
@@ -1516,7 +1511,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// record error for debugging
final StringBuilder builder = new StringBuilder();
- builder.append("found non-monotonic " + type + "values at left[" + e.leftIndex
+ builder.append("found non-monotonic " + type + " values at left[" + e.leftIndex
+ "] - right[" + e.rightIndex + "]\n");
builder.append("left=").append(e.left).append('\n');
builder.append("right=").append(e.right).append('\n');
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index d2d2d8baa066..c2c6b4d469be 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -478,8 +478,9 @@ status_t SensorService::setEventRate(const sp<SensorEventConnection>& connection
if (ns < 0)
return BAD_VALUE;
- if (ns == 0) {
- ns = sensor->getSensor().getMinDelayNs();
+ nsecs_t minDelayNs = sensor->getSensor().getMinDelayNs();
+ if (ns < minDelayNs) {
+ ns = minDelayNs;
}
if (ns < MINIMUM_EVENTS_PERIOD)
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 8f4fdb8fed5c..1b00e9380a62 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1217,23 +1217,25 @@ void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& state,
sp<Client> client( static_cast<Client *>(s.client.get()) );
transactionFlags |= setClientStateLocked(client, s.state);
}
+
if (transactionFlags) {
+ // this triggers the transaction
setTransactionFlags(transactionFlags);
- }
- // if this is a synchronous transaction, wait for it to take effect before
- // returning.
- if (flags & eSynchronous) {
- mTransationPending = true;
- }
- while (mTransationPending) {
- status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
- if (CC_UNLIKELY(err != NO_ERROR)) {
- // just in case something goes wrong in SF, return to the
- // called after a few seconds.
- LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!");
- mTransationPending = false;
- break;
+ // if this is a synchronous transaction, wait for it to take effect
+ // before returning.
+ if (flags & eSynchronous) {
+ mTransationPending = true;
+ }
+ while (mTransationPending) {
+ status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+ if (CC_UNLIKELY(err != NO_ERROR)) {
+ // just in case something goes wrong in SF, return to the
+ // called after a few seconds.
+ LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!");
+ mTransationPending = false;
+ break;
+ }
}
}
}
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 5b13603a924f..410e9614e9dd 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -167,7 +167,9 @@ public abstract class DataConnectionTracker extends Handler {
// independent of mInternalDataEnabled and requests for APN access
// persisted
protected boolean mUserDataEnabled = true;
- protected boolean mPolicyDataEnabled = true;
+
+ // TODO: move away from static state once 5587429 is fixed.
+ protected static boolean sPolicyDataEnabled = true;
private boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
@@ -766,7 +768,7 @@ public abstract class DataConnectionTracker extends Handler {
public boolean getAnyDataEnabled() {
final boolean result;
synchronized (mDataEnabledLock) {
- result = (mInternalDataEnabled && mUserDataEnabled && mPolicyDataEnabled
+ result = (mInternalDataEnabled && mUserDataEnabled && sPolicyDataEnabled
&& (enabledCount != 0));
}
if (!result && DBG) log("getAnyDataEnabled " + result);
@@ -1132,8 +1134,8 @@ public abstract class DataConnectionTracker extends Handler {
protected void onSetPolicyDataEnabled(boolean enabled) {
synchronized (mDataEnabledLock) {
final boolean prevEnabled = getAnyDataEnabled();
- if (mPolicyDataEnabled != enabled) {
- mPolicyDataEnabled = enabled;
+ if (sPolicyDataEnabled != enabled) {
+ sPolicyDataEnabled = enabled;
if (prevEnabled != getAnyDataEnabled()) {
if (!prevEnabled) {
resetAllRetryCounts();
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 865caf63224c..7cd01a167d78 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -549,7 +549,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
@Override
public boolean getAnyDataEnabled() {
synchronized (mDataEnabledLock) {
- if (!(mInternalDataEnabled && mUserDataEnabled && mPolicyDataEnabled)) return false;
+ if (!(mInternalDataEnabled && mUserDataEnabled && sPolicyDataEnabled)) return false;
for (ApnContext apnContext : mApnContexts.values()) {
// Make sure we dont have a context that going down
// and is explicitly disabled.
diff --git a/wifi/java/android/net/wifi/WifiApConfigStore.java b/wifi/java/android/net/wifi/WifiApConfigStore.java
index bb5427d01879..0531ca376149 100644
--- a/wifi/java/android/net/wifi/WifiApConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiApConfigStore.java
@@ -19,11 +19,16 @@ package android.net.wifi;
import android.content.Context;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.os.Environment;
-import android.os.Message;
import android.os.Handler;
-import android.os.HandlerThread;
+import android.os.Message;
+import android.os.Messenger;
import android.util.Log;
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.R;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
@@ -34,16 +39,13 @@ import java.io.IOException;
import java.net.InetAddress;
import java.util.UUID;
-import com.android.internal.R;
-
-
/**
* Provides API to the WifiStateMachine for doing read/write access
* to soft access point configuration
*/
-class WifiApConfigStore {
+class WifiApConfigStore extends StateMachine {
- private static Context sContext;
+ private Context mContext;
private static final String TAG = "WifiApConfigStore";
private static final String AP_CONFIG_FILE = Environment.getDataDirectory() +
@@ -51,131 +53,160 @@ class WifiApConfigStore {
private static final int AP_CONFIG_FILE_VERSION = 1;
- private static WifiConfiguration sApConfig = new WifiConfiguration();
- private static final Object sApConfigLock = new Object();
+ private State mDefaultState = new DefaultState();
+ private State mInactiveState = new InactiveState();
+ private State mActiveState = new ActiveState();
+
+ private WifiConfiguration mWifiApConfig = null;
+ private AsyncChannel mReplyChannel = new AsyncChannel();
- private static FileReadWriteHandler sFileReadWriteHandler;
- private static final int READ_AP_CONFIG = 1;
- private static final int WRITE_AP_CONFIG = 2;
+ WifiApConfigStore(Context context, Handler target) {
+ super(TAG, target.getLooper());
- static void initialize(Context context) {
- sContext = context;
+ mContext = context;
+ addState(mDefaultState);
+ addState(mInactiveState, mDefaultState);
+ addState(mActiveState, mDefaultState);
- /* File operations happen on a seperate thread */
- HandlerThread configThread = new HandlerThread("WifiApConfigStore");
- configThread.start();
- sFileReadWriteHandler = new FileReadWriteHandler(configThread.getLooper());
- Message.obtain(sFileReadWriteHandler, READ_AP_CONFIG).sendToTarget();
+ setInitialState(mInactiveState);
}
+ public static WifiApConfigStore makeWifiApConfigStore(Context context, Handler target) {
+ WifiApConfigStore s = new WifiApConfigStore(context, target);
+ s.start();
+ return s;
+ }
- static void setApConfiguration(WifiConfiguration config) {
- synchronized (sApConfigLock) {
- sApConfig = config;
+ class DefaultState extends State {
+ public boolean processMessage(Message message) {
+ switch (message.what) {
+ case WifiStateMachine.CMD_SET_AP_CONFIG:
+ case WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED:
+ Log.e(TAG, "Unexpected message: " + message);
+ break;
+ case WifiStateMachine.CMD_REQUEST_AP_CONFIG:
+ mReplyChannel.replyToMessage(message,
+ WifiStateMachine.CMD_RESPONSE_AP_CONFIG, mWifiApConfig);
+ break;
+ default:
+ Log.e(TAG, "Failed to handle " + message);
+ break;
+ }
+ return HANDLED;
}
- Message.obtain(sFileReadWriteHandler, WRITE_AP_CONFIG, new WifiConfiguration(config))
- .sendToTarget();
}
- static WifiConfiguration getApConfiguration() {
- synchronized (sApConfigLock) {
- return new WifiConfiguration(sApConfig);
+ class InactiveState extends State {
+ public boolean processMessage(Message message) {
+ switch (message.what) {
+ case WifiStateMachine.CMD_SET_AP_CONFIG:
+ mWifiApConfig = (WifiConfiguration) message.obj;
+ transitionTo(mActiveState);
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return HANDLED;
}
}
- /**
- * File read/write handler
- */
- private static class FileReadWriteHandler extends Handler {
-
- public FileReadWriteHandler(android.os.Looper looper) {
- super(looper);
+ class ActiveState extends State {
+ public void enter() {
+ new Thread(new Runnable() {
+ public void run() {
+ writeApConfiguration(mWifiApConfig);
+ sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED);
+ }
+ }).start();
}
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case WRITE_AP_CONFIG:
- writeApConfiguration((WifiConfiguration) msg.obj);
+ public boolean processMessage(Message message) {
+ switch (message.what) {
+ //TODO: have feedback to the user when we do this
+ //to indicate the write is currently in progress
+ case WifiStateMachine.CMD_SET_AP_CONFIG:
+ deferMessage(message);
break;
- case READ_AP_CONFIG:
- readApConfiguration();
+ case WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED:
+ transitionTo(mInactiveState);
break;
default:
- Log.e(TAG, "Unknown command in FileReadWriteHandler: " + msg);
- break;
+ return NOT_HANDLED;
}
+ return HANDLED;
}
+ }
- private static void writeApConfiguration(final WifiConfiguration config) {
- DataOutputStream out = null;
- try {
- out = new DataOutputStream(new BufferedOutputStream(
- new FileOutputStream(AP_CONFIG_FILE)));
-
- out.writeInt(AP_CONFIG_FILE_VERSION);
- out.writeUTF(config.SSID);
- int authType = config.getAuthType();
- out.writeInt(authType);
- if(authType != KeyMgmt.NONE) {
- out.writeUTF(config.preSharedKey);
- }
- } catch (IOException e) {
- Log.e(TAG, "Error writing hotspot configuration" + e);
- } finally {
- if (out != null) {
- try {
- out.close();
- } catch (IOException e) {}
- }
- }
- }
+ void loadApConfiguration() {
+ DataInputStream in = null;
+ try {
+ WifiConfiguration config = new WifiConfiguration();
+ in = new DataInputStream(new BufferedInputStream(new FileInputStream(
+ AP_CONFIG_FILE)));
- private static void readApConfiguration() {
- DataInputStream in = null;
- try {
- WifiConfiguration config = new WifiConfiguration();
- in = new DataInputStream(new BufferedInputStream(new FileInputStream(
- AP_CONFIG_FILE)));
-
- int version = in.readInt();
- if (version != 1) {
- Log.e(TAG, "Bad version on hotspot configuration file, set defaults");
- setDefaultApConfiguration();
- return;
- }
- config.SSID = in.readUTF();
- int authType = in.readInt();
- config.allowedKeyManagement.set(authType);
- if (authType != KeyMgmt.NONE) {
- config.preSharedKey = in.readUTF();
- }
- synchronized (sApConfigLock) {
- sApConfig = config;
- }
- } catch (IOException ignore) {
+ int version = in.readInt();
+ if (version != 1) {
+ Log.e(TAG, "Bad version on hotspot configuration file, set defaults");
setDefaultApConfiguration();
- } finally {
- if (in != null) {
- try {
- in.close();
- } catch (IOException e) {}
- }
+ return;
+ }
+ config.SSID = in.readUTF();
+ int authType = in.readInt();
+ config.allowedKeyManagement.set(authType);
+ if (authType != KeyMgmt.NONE) {
+ config.preSharedKey = in.readUTF();
+ }
+ mWifiApConfig = config;
+ } catch (IOException ignore) {
+ setDefaultApConfiguration();
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {}
}
}
+ }
- /* Generate a default WPA2 based configuration with a random password.
- We are changing the Wifi Ap configuration storage from secure settings to a
- flat file accessible only by the system. A WPA2 based default configuration
- will keep the device secure after the update */
- private static void setDefaultApConfiguration() {
- WifiConfiguration config = new WifiConfiguration();
- config.SSID = sContext.getString(R.string.wifi_tether_configure_ssid_default);
- config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
- String randomUUID = UUID.randomUUID().toString();
- //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
- config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9,13);
- setApConfiguration(config);
+ Messenger getMessenger() {
+ return new Messenger(getHandler());
+ }
+
+ private void writeApConfiguration(final WifiConfiguration config) {
+ DataOutputStream out = null;
+ try {
+ out = new DataOutputStream(new BufferedOutputStream(
+ new FileOutputStream(AP_CONFIG_FILE)));
+
+ out.writeInt(AP_CONFIG_FILE_VERSION);
+ out.writeUTF(config.SSID);
+ int authType = config.getAuthType();
+ out.writeInt(authType);
+ if(authType != KeyMgmt.NONE) {
+ out.writeUTF(config.preSharedKey);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Error writing hotspot configuration" + e);
+ } finally {
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException e) {}
+ }
}
}
+
+ /* Generate a default WPA2 based configuration with a random password.
+ We are changing the Wifi Ap configuration storage from secure settings to a
+ flat file accessible only by the system. A WPA2 based default configuration
+ will keep the device secure after the update */
+ private void setDefaultApConfiguration() {
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = mContext.getString(R.string.wifi_tether_configure_ssid_default);
+ config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
+ String randomUUID = UUID.randomUUID().toString();
+ //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
+ config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9,13);
+ sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG, config);
+ }
}
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 00fae2ee2ddb..aadcaadaa663 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -184,6 +184,7 @@ public class WifiStateMachine extends StateMachine {
private WifiP2pManager mWifiP2pManager;
//Used to initiate a connection with WifiP2pService
private AsyncChannel mWifiP2pChannel = new AsyncChannel();
+ private AsyncChannel mWifiApConfigChannel = new AsyncChannel();
// Event log tags (must be in sync with event-log-tags)
private static final int EVENTLOG_WIFI_STATE_CHANGED = 50021;
@@ -233,12 +234,16 @@ public class WifiStateMachine extends StateMachine {
static final int CMD_STOP_AP = BASE + 24;
/* Set the soft access point configuration */
static final int CMD_SET_AP_CONFIG = BASE + 25;
- /* Get the soft access point configuration */
- static final int CMD_GET_AP_CONFIG = BASE + 26;
+ /* Soft access point configuration set completed */
+ static final int CMD_SET_AP_CONFIG_COMPLETED = BASE + 26;
+ /* Request the soft access point configuration */
+ static final int CMD_REQUEST_AP_CONFIG = BASE + 27;
+ /* Response to access point configuration request */
+ static final int CMD_RESPONSE_AP_CONFIG = BASE + 28;
/* Set configuration on tether interface */
- static final int CMD_TETHER_INTERFACE = BASE + 27;
+ static final int CMD_TETHER_INTERFACE = BASE + 29;
- static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 28;
+ static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 30;
/* Supplicant commands */
/* Is supplicant alive ? */
@@ -530,6 +535,11 @@ public class WifiStateMachine extends StateMachine {
mWpsStateMachine = new WpsStateMachine(context, this, getHandler());
mLinkProperties = new LinkProperties();
+ WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore(
+ context, getHandler());
+ wifiApConfigStore.loadApConfiguration();
+ mWifiApConfigChannel.connectSync(mContext, getHandler(), wifiApConfigStore.getMessenger());
+
mNetworkInfo.setIsAvailable(false);
mLinkProperties.clear();
mLastBssid = null;
@@ -659,11 +669,11 @@ public class WifiStateMachine extends StateMachine {
}
public void setWifiApConfiguration(WifiConfiguration config) {
- sendMessage(obtainMessage(CMD_SET_AP_CONFIG, config));
+ mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
}
- public WifiConfiguration syncGetWifiApConfiguration(AsyncChannel channel) {
- Message resultMsg = channel.sendMessageSynchronously(CMD_GET_AP_CONFIG);
+ public WifiConfiguration syncGetWifiApConfiguration() {
+ Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG);
WifiConfiguration ret = (WifiConfiguration) resultMsg.obj;
resultMsg.recycle();
return ret;
@@ -1714,25 +1724,27 @@ public class WifiStateMachine extends StateMachine {
* TODO: Add control channel setup through hostapd that allows changing config
* on a running daemon
*/
- private boolean startSoftApWithConfig(WifiConfiguration config) {
- if (config == null) {
- config = WifiApConfigStore.getApConfiguration();
- } else {
- WifiApConfigStore.setApConfiguration(config);
- }
- try {
- mNwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
- } catch (Exception e) {
- loge("Exception in softap start " + e);
- try {
- mNwService.stopAccessPoint(mInterfaceName);
- mNwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
- } catch (Exception e1) {
- loge("Exception in softap re-start " + e1);
- return false;
+ private void startSoftApWithConfig(final WifiConfiguration config) {
+ // start hostapd on a seperate thread
+ new Thread(new Runnable() {
+ public void run() {
+ try {
+ mNwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
+ } catch (Exception e) {
+ loge("Exception in softap start " + e);
+ try {
+ mNwService.stopAccessPoint(mInterfaceName);
+ mNwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
+ } catch (Exception e1) {
+ loge("Exception in softap re-start " + e1);
+ sendMessage(CMD_START_AP_FAILURE);
+ return;
+ }
+ }
+ if (DBG) log("Soft AP start successful");
+ sendMessage(CMD_START_AP_SUCCESS);
}
- }
- return true;
+ }).start();
}
/********************************************************
@@ -1775,13 +1787,6 @@ public class WifiStateMachine extends StateMachine {
case CMD_ENABLE_BACKGROUND_SCAN:
mEnableBackgroundScan = (message.arg1 == 1);
break;
- case CMD_SET_AP_CONFIG:
- WifiApConfigStore.setApConfiguration((WifiConfiguration) message.obj);
- break;
- case CMD_GET_AP_CONFIG:
- WifiConfiguration config = WifiApConfigStore.getApConfiguration();
- mReplyChannel.replyToMessage(message, message.what, config);
- break;
/* Discard */
case CMD_LOAD_DRIVER:
case CMD_UNLOAD_DRIVER:
@@ -1823,6 +1828,11 @@ public class WifiStateMachine extends StateMachine {
case CMD_ENABLE_ALL_NETWORKS:
case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
case DhcpStateMachine.CMD_POST_DHCP_ACTION:
+ /* Handled by WifiApConfigStore */
+ case CMD_SET_AP_CONFIG:
+ case CMD_SET_AP_CONFIG_COMPLETED:
+ case CMD_REQUEST_AP_CONFIG:
+ case CMD_RESPONSE_AP_CONFIG:
break;
case WifiMonitor.DRIVER_HUNG_EVENT:
setWifiEnabled(false);
@@ -1856,8 +1866,6 @@ public class WifiStateMachine extends StateMachine {
// 50021 wifi_state_changed (custom|1|5)
EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
- WifiApConfigStore.initialize(mContext);
-
if (WifiNative.isDriverLoaded()) {
transitionTo(mDriverLoadedState);
}
@@ -3243,21 +3251,19 @@ public class WifiStateMachine extends StateMachine {
if (DBG) log(getName() + "\n");
EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
- final Message message = Message.obtain(getCurrentMessage());
- final WifiConfiguration config = (WifiConfiguration) message.obj;
+ final Message message = getCurrentMessage();
+ if (message.what == CMD_START_AP) {
+ final WifiConfiguration config = (WifiConfiguration) message.obj;
- // start hostapd on a seperate thread
- new Thread(new Runnable() {
- public void run() {
- if (startSoftApWithConfig(config)) {
- if (DBG) log("Soft AP start successful");
- sendMessage(CMD_START_AP_SUCCESS);
- } else {
- loge("Soft AP start failed");
- sendMessage(CMD_START_AP_FAILURE);
- }
+ if (config == null) {
+ mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG);
+ } else {
+ mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
+ startSoftApWithConfig(config);
}
- }).start();
+ } else {
+ throw new RuntimeException("Illegal transition to SoftApStartingState: " + message);
+ }
}
@Override
public boolean processMessage(Message message) {
@@ -3282,6 +3288,15 @@ public class WifiStateMachine extends StateMachine {
case WifiP2pService.P2P_ENABLE_PENDING:
deferMessage(message);
break;
+ case WifiStateMachine.CMD_RESPONSE_AP_CONFIG:
+ WifiConfiguration config = (WifiConfiguration) message.obj;
+ if (config != null) {
+ startSoftApWithConfig(config);
+ } else {
+ loge("Softap config is null!");
+ sendMessage(CMD_START_AP_FAILURE);
+ }
+ break;
case CMD_START_AP_SUCCESS:
setWifiApState(WIFI_AP_STATE_ENABLED);
transitionTo(mSoftApStartedState);