summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk4
-rw-r--r--api/current.xml171
-rw-r--r--cmds/svc/src/com/android/commands/svc/PowerCommand.java2
-rw-r--r--core/java/android/app/ActivityThread.java11
-rw-r--r--core/java/android/app/SearchDialog.java4
-rw-r--r--core/java/android/app/SearchManager.java8
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java33
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java58
-rw-r--r--core/java/android/bluetooth/IBluetooth.aidl4
-rw-r--r--core/java/android/content/SyncManager.java7
-rw-r--r--core/java/android/content/pm/PackageManager.java44
-rw-r--r--core/java/android/net/SSLCertificateSocketFactory.java4
-rw-r--r--core/java/android/net/http/CertificateChainValidator.java4
-rw-r--r--core/java/android/net/http/HttpsConnection.java3
-rw-r--r--core/java/android/os/AsyncTask.java2
-rw-r--r--core/java/android/os/BatteryStats.java3
-rw-r--r--core/java/android/os/IPowerManager.aidl5
-rw-r--r--core/java/android/os/PowerManager.java29
-rw-r--r--core/java/android/os/StrictMode.java19
-rw-r--r--core/java/android/os/WorkSource.aidl18
-rw-r--r--core/java/android/os/WorkSource.java311
-rw-r--r--core/java/android/provider/Calendar.java74
-rw-r--r--core/java/android/server/BluetoothEventLoop.java132
-rw-r--r--core/java/android/server/BluetoothService.java182
-rw-r--r--core/java/android/util/CalendarUtils.java332
-rw-r--r--core/java/android/view/View.java3
-rw-r--r--core/java/android/webkit/JWebCoreJavaBridge.java22
-rw-r--r--core/java/android/webkit/WebView.java4
-rw-r--r--core/java/com/android/internal/app/IBatteryStats.aidl10
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java67
-rw-r--r--core/jni/android_app_NativeActivity.cpp40
-rw-r--r--core/jni/android_hardware_SensorManager.cpp4
-rw-r--r--core/jni/android_os_MessageQueue.cpp22
-rw-r--r--core/jni/android_os_MessageQueue.h4
-rw-r--r--core/jni/android_server_BluetoothEventLoop.cpp60
-rw-r--r--core/jni/android_server_BluetoothService.cpp113
-rw-r--r--core/jni/android_view_InputQueue.cpp42
-rw-r--r--core/res/AndroidManifest.xml2
-rw-r--r--docs/html/sdk/eclipse-adt.jd2
-rw-r--r--include/android_runtime/android_app_NativeActivity.h5
-rw-r--r--include/gui/SensorEventQueue.h6
-rw-r--r--include/ui/FramebufferNativeWindow.h4
-rw-r--r--include/ui/GraphicLog.h70
-rw-r--r--include/ui/InputDispatcher.h8
-rw-r--r--include/ui/InputTransport.h1
-rw-r--r--include/utils/Looper.h210
-rw-r--r--include/utils/PollLoop.h219
-rw-r--r--libs/gui/SensorEventQueue.cpp22
-rw-r--r--libs/surfaceflinger_client/Surface.cpp19
-rw-r--r--libs/ui/Android.mk1
-rw-r--r--libs/ui/FramebufferNativeWindow.cpp35
-rw-r--r--libs/ui/GraphicLog.cpp84
-rw-r--r--libs/ui/InputDispatcher.cpp42
-rw-r--r--libs/utils/Android.mk2
-rw-r--r--libs/utils/Looper.cpp368
-rw-r--r--libs/utils/PollLoop.cpp377
-rw-r--r--libs/utils/tests/Android.mk2
-rw-r--r--libs/utils/tests/Looper_test.cpp433
-rw-r--r--libs/utils/tests/PollLoop_test.cpp370
-rw-r--r--location/java/android/location/ILocationProvider.aidl3
-rw-r--r--location/java/android/location/provider/LocationProvider.java18
-rw-r--r--media/java/android/media/AudioEffect.java130
-rw-r--r--media/java/android/media/MediaPlayer.java1
-rw-r--r--native/android/input.cpp4
-rw-r--r--native/android/looper.cpp75
-rw-r--r--native/android/sensor.cpp6
-rw-r--r--native/include/android/input.h2
-rw-r--r--native/include/android/looper.h189
-rw-r--r--native/include/android/sensor.h2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java3
-rw-r--r--services/java/com/android/server/BackupManagerService.java6
-rw-r--r--services/java/com/android/server/LocationManagerService.java27
-rw-r--r--services/java/com/android/server/PackageManagerService.java39
-rw-r--r--services/java/com/android/server/PowerManagerService.java145
-rw-r--r--services/java/com/android/server/SystemServer.java10
-rwxr-xr-xservices/java/com/android/server/VibratorService.java24
-rw-r--r--services/java/com/android/server/WallpaperManagerService.java8
-rw-r--r--services/java/com/android/server/WifiService.java101
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java18
-rw-r--r--services/java/com/android/server/am/ActivityStack.java2
-rw-r--r--services/java/com/android/server/am/BatteryStatsService.java57
-rwxr-xr-xservices/java/com/android/server/location/GpsLocationProvider.java5
-rw-r--r--services/java/com/android/server/location/LocationProviderInterface.java3
-rw-r--r--services/java/com/android/server/location/LocationProviderProxy.java12
-rw-r--r--services/java/com/android/server/location/MockProvider.java3
-rw-r--r--services/java/com/android/server/location/PassiveProvider.java3
-rw-r--r--services/java/com/android/server/sip/SipService.java24
-rw-r--r--services/java/com/android/server/sip/SipSessionGroup.java33
-rw-r--r--services/sensorservice/SensorService.cpp2
-rw-r--r--services/sensorservice/tests/sensorservicetest.cpp17
-rw-r--r--services/surfaceflinger/DisplayHardware/DisplayHardware.cpp4
-rw-r--r--services/surfaceflinger/DisplayHardware/DisplayHardware.h3
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp19
-rw-r--r--telephony/java/android/telephony/gsm/GsmCellLocation.java4
-rw-r--r--telephony/java/com/android/internal/telephony/CallManager.java109
-rwxr-xr-xtelephony/java/com/android/internal/telephony/sip/SipPhone.java13
-rw-r--r--tests/CoreTests/android/core/SSLPerformanceTest.java12
-rw-r--r--tests/CoreTests/android/core/SSLSocketTest.java15
-rw-r--r--voip/java/android/net/sip/ISipSession.aidl1
-rw-r--r--voip/java/android/net/sip/SipAudioCall.java7
-rw-r--r--voip/java/android/net/sip/SipAudioCallImpl.java82
-rw-r--r--voip/java/android/net/sip/SipErrorCode.java5
-rw-r--r--voip/java/android/net/sip/SipManager.java5
-rw-r--r--voip/java/android/net/sip/SipProfile.java18
-rw-r--r--voip/java/android/net/sip/SipRegistrationListener.java4
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl6
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java30
107 files changed, 3872 insertions, 1574 deletions
diff --git a/Android.mk b/Android.mk
index 29c8cb4..84376ce 100644
--- a/Android.mk
+++ b/Android.mk
@@ -431,8 +431,8 @@ framework_docs_SDK_PREVIEW:=0
## Latest ADT version identifiers, for reference from published docs
framework_docs_ADT_VERSION:=0.9.8
framework_docs_ADT_DOWNLOAD:=ADT-0.9.8.zip
-framework_docs_ADT_BYTES:=8703591
-framework_docs_ADT_CHECKSUM:=22070f8e52924605a3b3abf87c1ba39f
+framework_docs_ADT_BYTES:=8301417
+framework_docs_ADT_CHECKSUM:=27e0de800512f13feae46fb554e6ee2f
framework_docs_LOCAL_DROIDDOC_OPTIONS += \
-hdf sdk.version $(framework_docs_SDK_VERSION) \
diff --git a/api/current.xml b/api/current.xml
index d2e1f05..8e8a671 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -84326,6 +84326,8 @@
>
<parameter name="uid" type="int">
</parameter>
+<parameter name="ws" type="android.os.WorkSource">
+</parameter>
</method>
<method name="onDisable"
return="void"
@@ -84455,6 +84457,8 @@
>
<parameter name="uid" type="int">
</parameter>
+<parameter name="ws" type="android.os.WorkSource">
+</parameter>
</method>
<method name="onRequiresCell"
return="boolean"
@@ -84516,6 +84520,8 @@
>
<parameter name="minTime" type="long">
</parameter>
+<parameter name="ws" type="android.os.WorkSource">
+</parameter>
</method>
<method name="onSupportsAltitude"
return="boolean"
@@ -101636,6 +101642,19 @@
<parameter name="refCounted" type="boolean">
</parameter>
</method>
+<method name="setWorkSource"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="ws" type="android.os.WorkSource">
+</parameter>
+</method>
</class>
</package>
<package name="android.opengl"
@@ -128447,6 +128466,19 @@
<parameter name="value" type="boolean">
</parameter>
</method>
+<method name="setWorkSource"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="ws" type="android.os.WorkSource">
+</parameter>
+</method>
</class>
<class name="Process"
extends="java.lang.Object"
@@ -129595,6 +129627,134 @@
</parameter>
</method>
</class>
+<class name="WorkSource"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="WorkSource"
+ type="android.os.WorkSource"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="WorkSource"
+ type="android.os.WorkSource"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="orig" type="android.os.WorkSource">
+</parameter>
+</constructor>
+<method name="add"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="other" type="android.os.WorkSource">
+</parameter>
+</method>
+<method name="clear"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="diff"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="other" type="android.os.WorkSource">
+</parameter>
+</method>
+<method name="remove"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="other" type="android.os.WorkSource">
+</parameter>
+</method>
+<method name="set"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="other" type="android.os.WorkSource">
+</parameter>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
</package>
<package name="android.os.storage"
>
@@ -151863,6 +152023,17 @@
visibility="public"
>
</method>
+<method name="getPsc"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="setLacAndCid"
return="void"
abstract="false"
diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
index d3ec3d9..e1d6619 100644
--- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
@@ -64,7 +64,7 @@ public class PowerCommand extends Svc.Command {
= IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE));
try {
IBinder lock = new Binder();
- pm.acquireWakeLock(PowerManager.FULL_WAKE_LOCK, lock, "svc power");
+ pm.acquireWakeLock(PowerManager.FULL_WAKE_LOCK, lock, "svc power", null);
pm.setStayOnSetting(val);
pm.releaseWakeLock(lock, 0);
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index f8407c2..d8b5253 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3107,18 +3107,11 @@ public final class ActivityThread {
/**
* For system applications on userdebug/eng builds, log stack
* traces of disk and network access to dropbox for analysis.
- *
- * Similar logic exists in SystemServer.java.
*/
if ((data.appInfo.flags &
(ApplicationInfo.FLAG_SYSTEM |
- ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0 &&
- !"user".equals(Build.TYPE)) {
- StrictMode.setThreadPolicy(
- StrictMode.DISALLOW_DISK_WRITE |
- StrictMode.DISALLOW_DISK_READ |
- StrictMode.DISALLOW_NETWORK |
- StrictMode.PENALTY_DROPBOX);
+ ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) {
+ StrictMode.conditionallyEnableDebugLogging();
}
/**
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 7625c04..cd22fa1 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -588,7 +588,9 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
*/
private void updateVoiceButton(boolean empty) {
int visibility = View.GONE;
- if (mSearchable.getVoiceSearchEnabled() && empty) {
+ if ((mAppSearchData == null || !mAppSearchData.getBoolean(
+ SearchManager.DISABLE_VOICE_SEARCH, false))
+ && mSearchable.getVoiceSearchEnabled() && empty) {
Intent testIntent = null;
if (mSearchable.getVoiceSearchLaunchWebSearch()) {
testIntent = mVoiceWebSearchIntent;
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index a1ca707..2e9cd96 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -395,6 +395,14 @@ public class SearchManager
public final static String CONTEXT_IS_VOICE = "android.search.CONTEXT_IS_VOICE";
/**
+ * This means that the voice icon should not be shown at all, because the
+ * current search engine does not support voice search.
+ * @hide
+ */
+ public final static String DISABLE_VOICE_SEARCH
+ = "android.search.DISABLE_VOICE_SEARCH";
+
+ /**
* Reference to the shared system search service.
*/
private static ISearchManager mService;
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 03bcadc..16a8c57 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -26,8 +26,10 @@ import android.os.ParcelUuid;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
+import android.util.Pair;
import java.io.IOException;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
@@ -863,6 +865,37 @@ public final class BluetoothAdapter {
return socket;
}
+ /**
+ * Read the local Out of Band Pairing Data
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+ *
+ * @return Pair<byte[], byte[]> of Hash and Randomizer
+ *
+ * @hide
+ */
+ public Pair<byte[], byte[]> readOutOfBandData() {
+ if (getState() != STATE_ON) return null;
+ try {
+ byte[] hash = new byte[16];
+ byte[] randomizer = new byte[16];
+
+ byte[] ret = mService.readOutOfBandData();
+
+ if (ret == null || ret.length != 32) return null;
+
+ hash = Arrays.copyOfRange(ret, 0, 16);
+ randomizer = Arrays.copyOfRange(ret, 16, 32);
+
+ if (DBG) {
+ Log.d(TAG, "readOutOfBandData:" + Arrays.toString(hash) +
+ ":" + Arrays.toString(randomizer));
+ }
+ return new Pair<byte[], byte[]>(hash, randomizer);
+
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return null;
+ }
+
private Set<BluetoothDevice> toDeviceSet(String[] addresses) {
Set<BluetoothDevice> devices = new HashSet<BluetoothDevice>(addresses.length);
for (int i = 0; i < addresses.length; i++) {
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index e77e76f..e577ec4 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -325,7 +325,9 @@ public final class BluetoothDevice implements Parcelable {
/** The user will be prompted to enter the passkey displayed on remote device
* @hide */
public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
-
+ /** The user will be prompted to accept or deny the OOB pairing request
+ * @hide */
+ public static final int PAIRING_VARIANT_OOB_CONSENT = 5;
/**
* Used as an extra field in {@link #ACTION_UUID} intents,
* Contains the {@link android.os.ParcelUuid}s of the remote device which
@@ -464,6 +466,52 @@ public final class BluetoothDevice implements Parcelable {
}
/**
+ * Start the bonding (pairing) process with the remote device using the
+ * Out Of Band mechanism.
+ *
+ * <p>This is an asynchronous call, it will return immediately. Register
+ * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
+ * the bonding process completes, and its result.
+ *
+ * <p>Android system services will handle the necessary user interactions
+ * to confirm and complete the bonding process.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
+ *
+ * @param hash - Simple Secure pairing hash
+ * @param randomizer - The random key obtained using OOB
+ * @return false on immediate error, true if bonding will begin
+ *
+ * @hide
+ */
+ public boolean createBondOutOfBand(byte[] hash, byte[] randomizer) {
+ try {
+ return sService.createBondOutOfBand(mAddress, hash, randomizer);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
+ /**
+ * Set the Out Of Band data for a remote device to be used later
+ * in the pairing mechanism. Users can obtain this data through other
+ * trusted channels
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
+ *
+ * @param hash Simple Secure pairing hash
+ * @param randomizer The random key obtained using OOB
+ * @return false on error; true otherwise
+ *
+ * @hide
+ */
+ public boolean setDeviceOutOfBandData(byte[] hash, byte[] randomizer) {
+ try {
+ return sService.setDeviceOutOfBandData(mAddress, hash, randomizer);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
+ /**
* Cancel an in-progress bonding request started with {@link #createBond}.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
*
@@ -617,6 +665,14 @@ public final class BluetoothDevice implements Parcelable {
}
/** @hide */
+ public boolean setRemoteOutOfBandData() {
+ try {
+ return sService.setRemoteOutOfBandData(mAddress);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
+ /** @hide */
public boolean cancelPairingUserInput() {
try {
return sService.cancelPairingUserInput(mAddress);
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index ea71034..6dd8dd6 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -44,12 +44,15 @@ interface IBluetooth
boolean startDiscovery();
boolean cancelDiscovery();
boolean isDiscovering();
+ byte[] readOutOfBandData();
boolean createBond(in String address);
+ boolean createBondOutOfBand(in String address, in byte[] hash, in byte[] randomizer);
boolean cancelBondProcess(in String address);
boolean removeBond(in String address);
String[] listBonds();
int getBondState(in String address);
+ boolean setDeviceOutOfBandData(in String address, in byte[] hash, in byte[] randomizer);
String getRemoteName(in String address);
int getRemoteClass(in String address);
@@ -60,6 +63,7 @@ interface IBluetooth
boolean setPin(in String address, in byte[] pin);
boolean setPasskey(in String address, int passkey);
boolean setPairingConfirmation(in String address, boolean confirm);
+ boolean setRemoteOutOfBandData(in String addres);
boolean cancelPairingUserInput(in String address);
boolean setTrust(in String address, in boolean value);
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index d0b67cc..26b6ad7 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -45,6 +45,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.WorkSource;
import android.provider.Settings;
import android.text.format.DateUtils;
import android.text.format.Time;
@@ -126,8 +127,8 @@ public class SyncManager implements OnAccountsUpdateListener {
private static final int INITIALIZATION_UNBIND_DELAY_MS = 5000;
- private static final String SYNC_WAKE_LOCK = "SyncManagerSyncWakeLock";
- private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarmWakeLock";
+ private static final String SYNC_WAKE_LOCK = "*sync*";
+ private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm";
private Context mContext;
@@ -1700,10 +1701,12 @@ public class SyncManager implements OnAccountsUpdateListener {
mActiveSyncContext.close();
mActiveSyncContext = null;
mSyncStorageEngine.setActiveSync(mActiveSyncContext);
+ mSyncWakeLock.setWorkSource(null);
runStateIdle();
return;
}
+ mSyncWakeLock.setWorkSource(new WorkSource(syncAdapterInfo.uid));
mSyncWakeLock.acquire();
// no need to schedule an alarm, as that will be done by our caller.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index ef72013..4bd9bd9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -192,7 +192,7 @@ public abstract class PackageManager {
/**
* Signature check result: this is returned by {@link #checkSignatures}
- * if the two packages have a matching signature.
+ * if all signatures on the two packages match.
*/
public static final int SIGNATURE_MATCH = 0;
@@ -204,25 +204,25 @@ public abstract class PackageManager {
/**
* Signature check result: this is returned by {@link #checkSignatures}
- * if the first package is not signed, but the second is.
+ * if the first package is not signed but the second is.
*/
public static final int SIGNATURE_FIRST_NOT_SIGNED = -1;
/**
* Signature check result: this is returned by {@link #checkSignatures}
- * if the second package is not signed, but the first is.
+ * if the second package is not signed but the first is.
*/
public static final int SIGNATURE_SECOND_NOT_SIGNED = -2;
/**
* Signature check result: this is returned by {@link #checkSignatures}
- * if both packages are signed but there is no matching signature.
+ * if not all signatures on both packages match.
*/
public static final int SIGNATURE_NO_MATCH = -3;
/**
* Signature check result: this is returned by {@link #checkSignatures}
- * if either of the given package names are not valid.
+ * if either of the packages are not valid.
*/
public static final int SIGNATURE_UNKNOWN_PACKAGE = -4;
@@ -1230,20 +1230,14 @@ public abstract class PackageManager {
*
* @param pkg1 First package name whose signature will be compared.
* @param pkg2 Second package name whose signature will be compared.
- * @return Returns an integer indicating whether there is a matching
- * signature: the value is >= 0 if there is a match (or neither package
- * is signed), or < 0 if there is not a match. The match result can be
- * further distinguished with the success (>= 0) constants
- * {@link #SIGNATURE_MATCH}, {@link #SIGNATURE_NEITHER_SIGNED}; or
- * failure (< 0) constants {@link #SIGNATURE_FIRST_NOT_SIGNED},
- * {@link #SIGNATURE_SECOND_NOT_SIGNED}, {@link #SIGNATURE_NO_MATCH},
- * or {@link #SIGNATURE_UNKNOWN_PACKAGE}.
+ *
+ * @return Returns an integer indicating whether all signatures on the
+ * two packages match. The value is >= 0 ({@link #SIGNATURE_MATCH}) if
+ * all signatures match or < 0 if there is not a match ({@link
+ * #SIGNATURE_NO_MATCH} or {@link #SIGNATURE_UNKNOWN_PACKAGE}).
*
* @see #checkSignatures(int, int)
* @see #SIGNATURE_MATCH
- * @see #SIGNATURE_NEITHER_SIGNED
- * @see #SIGNATURE_FIRST_NOT_SIGNED
- * @see #SIGNATURE_SECOND_NOT_SIGNED
* @see #SIGNATURE_NO_MATCH
* @see #SIGNATURE_UNKNOWN_PACKAGE
*/
@@ -1258,20 +1252,14 @@ public abstract class PackageManager {
*
* @param uid1 First UID whose signature will be compared.
* @param uid2 Second UID whose signature will be compared.
- * @return Returns an integer indicating whether there is a matching
- * signature: the value is >= 0 if there is a match (or neither package
- * is signed), or < 0 if there is not a match. The match result can be
- * further distinguished with the success (>= 0) constants
- * {@link #SIGNATURE_MATCH}, {@link #SIGNATURE_NEITHER_SIGNED}; or
- * failure (< 0) constants {@link #SIGNATURE_FIRST_NOT_SIGNED},
- * {@link #SIGNATURE_SECOND_NOT_SIGNED}, {@link #SIGNATURE_NO_MATCH},
- * or {@link #SIGNATURE_UNKNOWN_PACKAGE}.
*
- * @see #checkSignatures(int, int)
+ * @return Returns an integer indicating whether all signatures on the
+ * two packages match. The value is >= 0 ({@link #SIGNATURE_MATCH}) if
+ * all signatures match or < 0 if there is not a match ({@link
+ * #SIGNATURE_NO_MATCH} or {@link #SIGNATURE_UNKNOWN_PACKAGE}).
+ *
+ * @see #checkSignatures(String, String)
* @see #SIGNATURE_MATCH
- * @see #SIGNATURE_NEITHER_SIGNED
- * @see #SIGNATURE_FIRST_NOT_SIGNED
- * @see #SIGNATURE_SECOND_NOT_SIGNED
* @see #SIGNATURE_NO_MATCH
* @see #SIGNATURE_UNKNOWN_PACKAGE
*/
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 9166019..b822b27 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -49,7 +49,6 @@ import javax.net.ssl.X509TrustManager;
import org.apache.harmony.xnet.provider.jsse.OpenSSLContextImpl;
import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl;
import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
-import org.apache.harmony.xnet.provider.jsse.SSLParameters;
/**
* SSLSocketFactory implementation with several extra features:
@@ -211,7 +210,8 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
private SSLSocketFactory makeSocketFactory(TrustManager[] trustManagers) {
try {
OpenSSLContextImpl sslContext = new OpenSSLContextImpl();
- sslContext.engineInit(null, trustManagers, null, mSessionCache, null);
+ sslContext.engineInit(null, trustManagers, null);
+ sslContext.engineGetClientSessionContext().setPersistentCache(mSessionCache);
return sslContext.engineGetSocketFactory();
} catch (KeyManagementException e) {
Log.wtf(TAG, e);
diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java
index c527fe4..4ca5903 100644
--- a/core/java/android/net/http/CertificateChainValidator.java
+++ b/core/java/android/net/http/CertificateChainValidator.java
@@ -19,7 +19,7 @@ package android.net.http;
import com.android.internal.net.DomainNameValidator;
-import org.apache.harmony.xnet.provider.jsse.SSLParameters;
+import org.apache.harmony.xnet.provider.jsse.SSLParametersImpl;
import java.io.IOException;
@@ -191,7 +191,7 @@ class CertificateChainValidator {
// report back to the user.
//
try {
- SSLParameters.getDefaultTrustManager().checkServerTrusted(
+ SSLParametersImpl.getDefaultTrustManager().checkServerTrusted(
newServerCertificates, "RSA");
// no errors!!!
diff --git a/core/java/android/net/http/HttpsConnection.java b/core/java/android/net/http/HttpsConnection.java
index 8c9d013f..b361dca 100644
--- a/core/java/android/net/http/HttpsConnection.java
+++ b/core/java/android/net/http/HttpsConnection.java
@@ -98,7 +98,8 @@ public class HttpsConnection extends Connection {
}
};
- sslContext.engineInit(null, trustManagers, null, cache, null);
+ sslContext.engineInit(null, trustManagers, null);
+ sslContext.engineGetClientSessionContext().setPersistentCache(cache);
synchronized (HttpsConnection.class) {
mSslSocketFactory = sslContext.engineGetSocketFactory();
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index d28148c..5fb1d7c 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -129,7 +129,7 @@ public abstract class AsyncTask<Params, Progress, Result> {
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
- private static final int KEEP_ALIVE = 10;
+ private static final int KEEP_ALIVE = 1;
private static final BlockingQueue<Runnable> sWorkQueue =
new LinkedBlockingQueue<Runnable>(10);
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index f5b1e57..f182a7a 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -404,6 +404,7 @@ public abstract class BatteryStats implements Parcelable {
public static final byte CMD_UPDATE = 0;
public static final byte CMD_START = 1;
+ public static final byte CMD_OVERFLOW = 2;
public byte cmd;
@@ -1703,6 +1704,8 @@ public abstract class BatteryStats implements Parcelable {
pw.print(" ");
if (rec.cmd == HistoryItem.CMD_START) {
pw.println(" START");
+ } else if (rec.cmd == HistoryItem.CMD_OVERFLOW) {
+ pw.println(" *OVERFLOW*");
} else {
if (rec.batteryLevel < 10) pw.print("00");
else if (rec.batteryLevel < 100) pw.print("0");
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 01cc408..0067e94 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -17,10 +17,13 @@
package android.os;
+import android.os.WorkSource;
+
/** @hide */
interface IPowerManager
{
- void acquireWakeLock(int flags, IBinder lock, String tag);
+ void acquireWakeLock(int flags, IBinder lock, String tag, in WorkSource ws);
+ void updateWakeLockWorkSource(IBinder lock, in WorkSource ws);
void goToSleep(long time);
void goToSleepWithReason(long time, int reason);
void releaseWakeLock(IBinder lock, int flags);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index f4ca8bc..3876a3e 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -209,6 +209,7 @@ public class PowerManager
int mCount = 0;
boolean mRefCounted = true;
boolean mHeld = false;
+ WorkSource mWorkSource;
WakeLock(int flags, String tag)
{
@@ -247,7 +248,7 @@ public class PowerManager
synchronized (mToken) {
if (!mRefCounted || mCount++ == 0) {
try {
- mService.acquireWakeLock(mFlags, mToken, mTag);
+ mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource);
} catch (RemoteException e) {
}
mHeld = true;
@@ -313,6 +314,32 @@ public class PowerManager
}
}
+ public void setWorkSource(WorkSource ws) {
+ synchronized (mToken) {
+ if (ws != null && ws.size() == 0) {
+ ws = null;
+ }
+ boolean changed = true;
+ if (ws == null) {
+ mWorkSource = null;
+ } else if (mWorkSource == null) {
+ changed = mWorkSource != null;
+ mWorkSource = new WorkSource(ws);
+ } else {
+ changed = mWorkSource.diff(ws);
+ if (changed) {
+ mWorkSource.set(ws);
+ }
+ }
+ if (changed && mHeld) {
+ try {
+ mService.updateWakeLockWorkSource(mToken, mWorkSource);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+
public String toString() {
synchronized (mToken) {
return "WakeLock{"
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 7f7b02b..f571c42 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -201,6 +201,25 @@ public final class StrictMode {
}
/**
+ * Enable DropBox logging for debug phone builds.
+ *
+ * @hide
+ */
+ public static boolean conditionallyEnableDebugLogging() {
+ // For debug builds, log event loop stalls to dropbox for analysis.
+ // Similar logic also appears in ActivityThread.java for system apps.
+ if ("user".equals(Build.TYPE)) {
+ return false;
+ }
+ StrictMode.setThreadPolicy(
+ StrictMode.DISALLOW_DISK_WRITE |
+ StrictMode.DISALLOW_DISK_READ |
+ StrictMode.DISALLOW_NETWORK |
+ StrictMode.PENALTY_DROPBOX);
+ return true;
+ }
+
+ /**
* Parses the BlockGuard policy mask out from the Exception's
* getMessage() String value. Kinda gross, but least
* invasive. :/
diff --git a/core/java/android/os/WorkSource.aidl b/core/java/android/os/WorkSource.aidl
new file mode 100644
index 0000000..1e7fabc
--- /dev/null
+++ b/core/java/android/os/WorkSource.aidl
@@ -0,0 +1,18 @@
+/* Copyright 2010, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.os;
+
+parcelable WorkSource;
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
new file mode 100644
index 0000000..287c136
--- /dev/null
+++ b/core/java/android/os/WorkSource.java
@@ -0,0 +1,311 @@
+package android.os;
+
+/**
+ * Describes the source of some work that may be done by someone else.
+ * Currently the public representation of what a work source is is not
+ * defined; this is an opaque container.
+ */
+public class WorkSource implements Parcelable {
+ int mNum;
+ int[] mUids;
+
+ /**
+ * Internal statics to avoid object allocations in some operations.
+ * The WorkSource object itself is not thread safe, but we need to
+ * hold sTmpWorkSource lock while working with these statics.
+ */
+ static final WorkSource sTmpWorkSource = new WorkSource(0);
+ /**
+ * For returning newbie work from a modification operation.
+ */
+ static WorkSource sNewbWork;
+ /**
+ * For returning gone work form a modification operation.
+ */
+ static WorkSource sGoneWork;
+
+ /**
+ * Create an empty work source.
+ */
+ public WorkSource() {
+ mNum = 0;
+ }
+
+ /**
+ * Create a new WorkSource that is a copy of an existing one.
+ * If <var>orig</var> is null, an empty WorkSource is created.
+ */
+ public WorkSource(WorkSource orig) {
+ if (orig == null) {
+ mNum = 0;
+ return;
+ }
+ mNum = orig.mNum;
+ if (orig.mUids != null) {
+ mUids = orig.mUids.clone();
+ } else {
+ mUids = null;
+ }
+ }
+
+ /** @hide */
+ public WorkSource(int uid) {
+ mNum = 1;
+ mUids = new int[] { uid, 0 };
+ }
+
+ WorkSource(Parcel in) {
+ mNum = in.readInt();
+ mUids = in.createIntArray();
+ }
+
+ /** @hide */
+ public int size() {
+ return mNum;
+ }
+
+ /** @hide */
+ public int get(int index) {
+ return mUids[index];
+ }
+
+ /**
+ * Clear this WorkSource to be empty.
+ */
+ public void clear() {
+ mNum = 0;
+ }
+
+ /**
+ * Compare this WorkSource with another.
+ * @param other The WorkSource to compare against.
+ * @return If there is a difference, true is returned.
+ */
+ public boolean diff(WorkSource other) {
+ int N = mNum;
+ if (N != other.mNum) {
+ return true;
+ }
+ final int[] uids1 = mUids;
+ final int[] uids2 = other.mUids;
+ for (int i=0; i<N; i++) {
+ if (uids1[i] != uids2[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Replace the current contents of this work source with the given
+ * work source. If <var>other</var> is null, the current work source
+ * will be made empty.
+ */
+ public void set(WorkSource other) {
+ if (other == null) {
+ mNum = 0;
+ return;
+ }
+ mNum = other.mNum;
+ if (other.mUids != null) {
+ if (mUids != null && mUids.length >= mNum) {
+ System.arraycopy(other.mUids, 0, mUids, 0, mNum);
+ } else {
+ mUids = other.mUids.clone();
+ }
+ } else {
+ mUids = null;
+ }
+ }
+
+ /** @hide */
+ public void set(int uid) {
+ mNum = 1;
+ if (mUids == null) mUids = new int[2];
+ mUids[0] = uid;
+ }
+
+ /** @hide */
+ public WorkSource[] setReturningDiffs(WorkSource other) {
+ synchronized (sTmpWorkSource) {
+ sNewbWork = null;
+ sGoneWork = null;
+ updateLocked(other, true, true);
+ if (sNewbWork != null || sGoneWork != null) {
+ WorkSource[] diffs = new WorkSource[2];
+ diffs[0] = sNewbWork;
+ diffs[1] = sGoneWork;
+ return diffs;
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Merge the contents of <var>other</var> WorkSource in to this one.
+ *
+ * @param other The other WorkSource whose contents are to be merged.
+ * @return Returns true if any new sources were added.
+ */
+ public boolean add(WorkSource other) {
+ synchronized (sTmpWorkSource) {
+ return updateLocked(other, false, false);
+ }
+ }
+
+ /** @hide */
+ public WorkSource addReturningNewbs(WorkSource other) {
+ synchronized (sTmpWorkSource) {
+ sNewbWork = null;
+ updateLocked(other, false, true);
+ return sNewbWork;
+ }
+ }
+
+ /** @hide */
+ public boolean add(int uid) {
+ synchronized (sTmpWorkSource) {
+ sTmpWorkSource.mUids[0] = uid;
+ return updateLocked(sTmpWorkSource, false, false);
+ }
+ }
+
+ /** @hide */
+ public WorkSource addReturningNewbs(int uid) {
+ synchronized (sTmpWorkSource) {
+ sNewbWork = null;
+ sTmpWorkSource.mUids[0] = uid;
+ updateLocked(sTmpWorkSource, false, true);
+ return sNewbWork;
+ }
+ }
+
+ public boolean remove(WorkSource other) {
+ int N1 = mNum;
+ final int[] uids1 = mUids;
+ final int N2 = other.mNum;
+ final int[] uids2 = other.mUids;
+ boolean changed = false;
+ int i1 = 0;
+ for (int i2=0; i2<N2 && i1<N1; i2++) {
+ if (uids2[i2] == uids1[i1]) {
+ N1--;
+ if (i1 < N1) System.arraycopy(uids1, i1+1, uids1, i1, N1-i1);
+ }
+ while (i1 < N1 && uids2[i2] > uids1[i1]) {
+ i1++;
+ }
+ }
+
+ mNum = N1;
+
+ return changed;
+ }
+
+ private boolean updateLocked(WorkSource other, boolean set, boolean returnNewbs) {
+ int N1 = mNum;
+ int[] uids1 = mUids;
+ final int N2 = other.mNum;
+ final int[] uids2 = other.mUids;
+ boolean changed = false;
+ int i1 = 0;
+ for (int i2=0; i2<N2; i2++) {
+ if (i1 >= N1 || uids2[i2] < uids1[i1]) {
+ // Need to insert a new uid.
+ changed = true;
+ if (uids1 == null) {
+ uids1 = new int[4];
+ uids1[0] = uids2[i2];
+ } else if (i1 >= uids1.length) {
+ int[] newuids = new int[(uids1.length*3)/2];
+ if (i1 > 0) System.arraycopy(uids1, 0, newuids, 0, i1);
+ if (i1 < N1) System.arraycopy(uids1, i1, newuids, i1+1, N1-i1);
+ uids1 = newuids;
+ uids1[i1] = uids2[i2];
+ } else {
+ if (i1 < N1) System.arraycopy(uids1, i1, uids1, i1+1, N1-i1);
+ uids1[i1] = uids2[i2];
+ }
+ if (returnNewbs) {
+ if (sNewbWork == null) {
+ sNewbWork = new WorkSource(uids2[i2]);
+ } else {
+ sNewbWork.addLocked(uids2[i2]);
+ }
+ }
+ N1++;
+ i1++;
+ } else {
+ if (!set) {
+ // Skip uids that already exist or are not in 'other'.
+ do {
+ i1++;
+ } while (i1 < N1 && uids2[i2] >= uids1[i1]);
+ } else {
+ // Remove any uids that don't exist in 'other'.
+ int start = i1;
+ while (i1 < N1 && uids2[i2] > uids1[i1]) {
+ if (sGoneWork == null) {
+ sGoneWork = new WorkSource(uids1[i1]);
+ } else {
+ sGoneWork.addLocked(uids1[i1]);
+ }
+ i1++;
+ }
+ if (start < i1) {
+ System.arraycopy(uids1, i1, uids1, start, i1-start);
+ N1 -= i1-start;
+ i1 = start;
+ }
+ // If there is a matching uid, skip it.
+ if (i1 < N1 && uids2[i1] == uids1[i1]) {
+ i1++;
+ }
+ }
+ }
+ }
+
+ mNum = N1;
+ mUids = uids1;
+
+ return changed;
+ }
+
+ private void addLocked(int uid) {
+ if (mUids == null) {
+ mUids = new int[4];
+ mUids[0] = uid;
+ mNum = 1;
+ return;
+ }
+ if (mNum >= mUids.length) {
+ int[] newuids = new int[(mNum*3)/2];
+ System.arraycopy(mUids, 0, newuids, 0, mNum);
+ mUids = newuids;
+ }
+
+ mUids[mNum] = uid;
+ mNum++;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mNum);
+ dest.writeIntArray(mUids);
+ }
+
+ public static final Parcelable.Creator<WorkSource> CREATOR
+ = new Parcelable.Creator<WorkSource>() {
+ public WorkSource createFromParcel(Parcel in) {
+ return new WorkSource(in);
+ }
+ public WorkSource[] newArray(int size) {
+ return new WorkSource[size];
+ }
+ };
+}
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index 9a09805..6355a9c 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -943,6 +943,80 @@ public final class Calendar {
}
/**
+ * CalendarCache stores some settings for calendar including the current
+ * time zone for the app. These settings are stored using a key/value
+ * scheme.
+ */
+ public interface CalendarCacheColumns {
+ /**
+ * The key for the setting. Keys are defined in CalendarChache in the
+ * Calendar provider.
+ * TODO Add keys to this file
+ */
+ public static final String KEY = "key";
+
+ /**
+ * The value of the given setting.
+ */
+ public static final String VALUE = "value";
+ }
+
+ public static class CalendarCache implements CalendarCacheColumns {
+ /**
+ * The URI to use for retrieving the properties from the Calendar db.
+ */
+ public static final Uri URI =
+ Uri.parse("content://" + AUTHORITY + "/properties");
+ public static final String[] POJECTION = { KEY, VALUE };
+
+ /**
+ * If updating a property, this must be provided as the selection. All
+ * other selections will fail. For queries this field can be omitted to
+ * retrieve all properties or used to query a single property. Valid
+ * keys include {@link #TIMEZONE_KEY_TYPE},
+ * {@link #TIMEZONE_KEY_INSTANCES}, and
+ * {@link #TIMEZONE_KEY_INSTANCES_PREVIOUS}, though the last one can
+ * only be read, not written.
+ */
+ public static final String WHERE = "key=?";
+
+ /**
+ * They key for updating the use of auto/home time zones in Calendar.
+ * Valid values are {@link #TIMEZONE_TYPE_AUTO} or
+ * {@link #TIMEZONE_TYPE_HOME}.
+ */
+ public static final String TIMEZONE_KEY_TYPE = "timezoneType";
+
+ /**
+ * The key for updating the time zone used by the provider when it
+ * generates the instances table. This should only be written if the
+ * type is set to {@link #TIMEZONE_TYPE_HOME}. A valid time zone id
+ * should be written to this field.
+ */
+ public static final String TIMEZONE_KEY_INSTANCES = "timezoneInstances";
+
+ /**
+ * The key for reading the last time zone set by the user. This should
+ * only be read by apps and it will be automatically updated whenever
+ * {@link #TIMEZONE_KEY_INSTANCES} is updated with
+ * {@link #TIMEZONE_TYPE_HOME} set.
+ */
+ public static final String TIMEZONE_KEY_INSTANCES_PREVIOUS = "timezoneInstancesPrevious";
+
+ /**
+ * The value to write to {@link #TIMEZONE_KEY_TYPE} if the provider
+ * should stay in sync with the device's time zone.
+ */
+ public static final String TIMEZONE_TYPE_AUTO = "auto";
+
+ /**
+ * The value to write to {@link #TIMEZONE_KEY_TYPE} if the provider
+ * should use a fixed time zone set by the user.
+ */
+ public static final String TIMEZONE_TYPE_HOME = "home";
+ }
+
+ /**
* A few Calendar globals are needed in the CalendarProvider for expanding
* the Instances table and these are all stored in the first (and only)
* row of the CalendarMetaData table.
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 094258b..e05fe7b 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -52,22 +52,14 @@ class BluetoothEventLoop {
private final BluetoothAdapter mAdapter;
private final Context mContext;
- private static final int EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 1;
- private static final int EVENT_RESTART_BLUETOOTH = 2;
- private static final int EVENT_PAIRING_CONSENT_DELAYED_ACCEPT = 3;
- private static final int EVENT_AGENT_CANCEL = 4;
+ private static final int EVENT_RESTART_BLUETOOTH = 1;
+ private static final int EVENT_PAIRING_CONSENT_DELAYED_ACCEPT = 2;
+ private static final int EVENT_AGENT_CANCEL = 3;
private static final int CREATE_DEVICE_ALREADY_EXISTS = 1;
private static final int CREATE_DEVICE_SUCCESS = 0;
private static final int CREATE_DEVICE_FAILED = -1;
- // The time (in millisecs) to delay the pairing attempt after the first
- // auto pairing attempt fails. We use an exponential delay with
- // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and
- // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value.
- private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000;
- private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000;
-
private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
@@ -76,13 +68,6 @@ class BluetoothEventLoop {
public void handleMessage(Message msg) {
String address = null;
switch (msg.what) {
- case EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
- address = (String)msg.obj;
- if (address != null) {
- mBluetoothService.createBond(address);
- return;
- }
- break;
case EVENT_RESTART_BLUETOOTH:
mBluetoothService.restart();
break;
@@ -95,8 +80,7 @@ class BluetoothEventLoop {
case EVENT_AGENT_CANCEL:
// Set the Bond State to BOND_NONE.
// We always have only 1 device in BONDING state.
- String[] devices =
- mBluetoothService.getBondState().listInState(BluetoothDevice.BOND_BONDING);
+ String[] devices = mBluetoothService.listInState(BluetoothDevice.BOND_BONDING);
if (devices.length == 0) {
break;
} else if (devices.length > 1) {
@@ -104,7 +88,7 @@ class BluetoothEventLoop {
break;
}
address = devices[0];
- mBluetoothService.getBondState().setBondState(address,
+ mBluetoothService.setBondState(address,
BluetoothDevice.BOND_NONE,
BluetoothDevice.UNBOND_REASON_REMOTE_AUTH_CANCELED);
break;
@@ -115,7 +99,7 @@ class BluetoothEventLoop {
static { classInitNative(); }
private static native void classInitNative();
- /* pacakge */ BluetoothEventLoop(Context context, BluetoothAdapter adapter,
+ /* package */ BluetoothEventLoop(Context context, BluetoothAdapter adapter,
BluetoothService bluetoothService) {
mBluetoothService = bluetoothService;
mContext = context;
@@ -209,55 +193,7 @@ class BluetoothEventLoop {
private void onCreatePairedDeviceResult(String address, int result) {
address = address.toUpperCase();
- if (result == BluetoothDevice.BOND_SUCCESS) {
- mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED);
- if (mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
- mBluetoothService.getBondState().clearPinAttempts(address);
- }
- } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED &&
- mBluetoothService.getBondState().getAttempt(address) == 1) {
- mBluetoothService.getBondState().addAutoPairingFailure(address);
- pairingAttempt(address, result);
- } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN &&
- mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
- pairingAttempt(address, result);
- } else {
- mBluetoothService.getBondState().setBondState(address,
- BluetoothDevice.BOND_NONE, result);
- if (mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
- mBluetoothService.getBondState().clearPinAttempts(address);
- }
- }
- }
-
- private void pairingAttempt(String address, int result) {
- // This happens when our initial guess of "0000" as the pass key
- // fails. Try to create the bond again and display the pin dialog
- // to the user. Use back-off while posting the delayed
- // message. The initial value is
- // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is
- // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is
- // reached, display an error to the user.
- int attempt = mBluetoothService.getBondState().getAttempt(address);
- if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY >
- MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) {
- mBluetoothService.getBondState().clearPinAttempts(address);
- mBluetoothService.getBondState().setBondState(address,
- BluetoothDevice.BOND_NONE, result);
- return;
- }
-
- Message message = mHandler.obtainMessage(EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
- message.obj = address;
- boolean postResult = mHandler.sendMessageDelayed(message,
- attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
- if (!postResult) {
- mBluetoothService.getBondState().clearPinAttempts(address);
- mBluetoothService.getBondState().setBondState(address,
- BluetoothDevice.BOND_NONE, result);
- return;
- }
- mBluetoothService.getBondState().attempt(address);
+ mBluetoothService.onCreatePairedDeviceResult(address, result);
}
private void onDeviceCreated(String deviceObjectPath) {
@@ -275,8 +211,8 @@ class BluetoothEventLoop {
private void onDeviceRemoved(String deviceObjectPath) {
String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
if (address != null) {
- mBluetoothService.getBondState().setBondState(address.toUpperCase(),
- BluetoothDevice.BOND_NONE, BluetoothDevice.UNBOND_REASON_REMOVED);
+ mBluetoothService.setBondState(address.toUpperCase(), BluetoothDevice.BOND_NONE,
+ BluetoothDevice.UNBOND_REASON_REMOVED);
mBluetoothService.setRemoteDeviceProperty(address, "UUIDs", null);
}
}
@@ -407,13 +343,11 @@ class BluetoothEventLoop {
// If locally initiated pairing, we will
// not go to BOND_BONDED state until we have received a
// successful return value in onCreatePairedDeviceResult
- if (null == mBluetoothService.getBondState().getPendingOutgoingBonding()) {
- mBluetoothService.getBondState().setBondState(address,
- BluetoothDevice.BOND_BONDED);
+ if (null == mBluetoothService.getPendingOutgoingBonding()) {
+ mBluetoothService.setBondState(address, BluetoothDevice.BOND_BONDED);
}
} else {
- mBluetoothService.getBondState().setBondState(address,
- BluetoothDevice.BOND_NONE);
+ mBluetoothService.setBondState(address, BluetoothDevice.BOND_NONE);
mBluetoothService.setRemoteDeviceProperty(address, "Trusted", "false");
}
} else if (name.equals("Trusted")) {
@@ -443,8 +377,8 @@ class BluetoothEventLoop {
// Also set it only when the state is not already Bonded, we can sometimes
// get an authorization request from the remote end if it doesn't have the link key
// while we still have it.
- if (mBluetoothService.getBondState().getBondState(address) != BluetoothDevice.BOND_BONDED)
- mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDING);
+ if (mBluetoothService.getBondState(address) != BluetoothDevice.BOND_BONDED)
+ mBluetoothService.setBondState(address, BluetoothDevice.BOND_BONDING);
return address;
}
@@ -458,7 +392,7 @@ class BluetoothEventLoop {
* so we may get this request many times. Also if we respond immediately,
* the other end is unable to handle it. Delay sending the message.
*/
- if (mBluetoothService.getBondState().getBondState(address) == BluetoothDevice.BOND_BONDED) {
+ if (mBluetoothService.getBondState(address) == BluetoothDevice.BOND_BONDED) {
Message message = mHandler.obtainMessage(EVENT_PAIRING_CONSENT_DELAYED_ACCEPT);
message.obj = address;
mHandler.sendMessageDelayed(message, 1500);
@@ -503,7 +437,7 @@ class BluetoothEventLoop {
if (address == null) return;
String pendingOutgoingAddress =
- mBluetoothService.getBondState().getPendingOutgoingBonding();
+ mBluetoothService.getPendingOutgoingBonding();
if (address.equals(pendingOutgoingAddress)) {
// we initiated the bonding
@@ -524,12 +458,7 @@ class BluetoothEventLoop {
case BluetoothClass.Device.AUDIO_VIDEO_PORTABLE_AUDIO:
case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
- if (!mBluetoothService.getBondState().hasAutoPairingFailed(address) &&
- !mBluetoothService.getBondState().isAutoPairingBlacklisted(address)) {
- mBluetoothService.getBondState().attempt(address);
- mBluetoothService.setPin(address, BluetoothDevice.convertPinToBytes("0000"));
- return;
- }
+ if (mBluetoothService.attemptAutoPair(address)) return;
}
}
Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
@@ -551,6 +480,17 @@ class BluetoothEventLoop {
mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
}
+ private void onRequestOobData(String objectPath , int nativeData) {
+ String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
+ if (address == null) return;
+
+ Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
+ intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
+ BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT);
+ mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+ }
+
private boolean onAgentAuthorize(String objectPath, String deviceUuid) {
String address = mBluetoothService.getAddressFromObjectPath(objectPath);
if (address == null) {
@@ -583,7 +523,21 @@ class BluetoothEventLoop {
return authorized;
}
- boolean isOtherSinkInNonDisconnectingState(String address) {
+ private boolean onAgentOutOfBandDataAvailable(String objectPath) {
+ if (!mBluetoothService.isEnabled()) return false;
+
+ String address = mBluetoothService.getAddressFromObjectPath(objectPath);
+ if (address == null) return false;
+
+ if (mBluetoothService.getDeviceOutOfBandData(
+ mAdapter.getRemoteDevice(address)) != null) {
+ return true;
+ }
+ return false;
+
+ }
+
+ private boolean isOtherSinkInNonDisconnectingState(String address) {
BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
Set<BluetoothDevice> devices = a2dp.getNonDisconnectedSinks();
if (devices.size() == 0) return false;
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index b2aa04d..dfe3a25 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -50,6 +50,7 @@ import android.os.ServiceManager;
import android.os.SystemService;
import android.provider.Settings;
import android.util.Log;
+import android.util.Pair;
import com.android.internal.app.IBatteryStats;
@@ -103,6 +104,14 @@ public class BluetoothService extends IBluetooth.Stub {
private static final int MESSAGE_FINISH_DISABLE = 2;
private static final int MESSAGE_UUID_INTENT = 3;
private static final int MESSAGE_DISCOVERABLE_TIMEOUT = 4;
+ private static final int MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 5;
+
+ // The time (in millisecs) to delay the pairing attempt after the first
+ // auto pairing attempt fails. We use an exponential delay with
+ // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and
+ // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value.
+ private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000;
+ private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000;
// The timeout used to sent the UUIDs Intent
// This timeout should be greater than the page timeout
@@ -129,6 +138,8 @@ public class BluetoothService extends IBluetooth.Stub {
private final BluetoothProfileState mHfpProfileState;
private BluetoothA2dpService mA2dpService;
+ private final HashMap<String, Pair<byte[], byte[]>> mDeviceOobData;
+
private static String mDockAddress;
private String mDockPin;
@@ -183,6 +194,7 @@ public class BluetoothService extends IBluetooth.Stub {
mDeviceProperties = new HashMap<String, Map<String,String>>();
mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>();
+ mDeviceOobData = new HashMap<String, Pair<byte[], byte[]>>();
mUuidIntentTracker = new ArrayList<String>();
mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>();
mServiceRecordToPid = new HashMap<Integer, Integer>();
@@ -498,6 +510,13 @@ public class BluetoothService extends IBluetooth.Stub {
setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE, -1);
}
break;
+ case MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
+ address = (String)msg.obj;
+ if (address != null) {
+ createBond(address);
+ return;
+ }
+ break;
}
}
};
@@ -587,8 +606,68 @@ public class BluetoothService extends IBluetooth.Stub {
Binder.restoreCallingIdentity(origCallerIdentityToken);
}
- /* package */ BondState getBondState() {
- return mBondState;
+ /*package*/ synchronized boolean attemptAutoPair(String address) {
+ if (!mBondState.hasAutoPairingFailed(address) &&
+ !mBondState.isAutoPairingBlacklisted(address)) {
+ mBondState.attempt(address);
+ setPin(address, BluetoothDevice.convertPinToBytes("0000"));
+ return true;
+ }
+ return false;
+ }
+
+ /*package*/ synchronized void onCreatePairedDeviceResult(String address, int result) {
+ if (result == BluetoothDevice.BOND_SUCCESS) {
+ setBondState(address, BluetoothDevice.BOND_BONDED);
+ if (mBondState.isAutoPairingAttemptsInProgress(address)) {
+ mBondState.clearPinAttempts(address);
+ }
+ } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED &&
+ mBondState.getAttempt(address) == 1) {
+ mBondState.addAutoPairingFailure(address);
+ pairingAttempt(address, result);
+ } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN &&
+ mBondState.isAutoPairingAttemptsInProgress(address)) {
+ pairingAttempt(address, result);
+ } else {
+ setBondState(address, BluetoothDevice.BOND_NONE, result);
+ if (mBondState.isAutoPairingAttemptsInProgress(address)) {
+ mBondState.clearPinAttempts(address);
+ }
+ }
+ }
+
+ /*package*/ synchronized String getPendingOutgoingBonding() {
+ return mBondState.getPendingOutgoingBonding();
+ }
+
+ private void pairingAttempt(String address, int result) {
+ // This happens when our initial guess of "0000" as the pass key
+ // fails. Try to create the bond again and display the pin dialog
+ // to the user. Use back-off while posting the delayed
+ // message. The initial value is
+ // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is
+ // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is
+ // reached, display an error to the user.
+ int attempt = mBondState.getAttempt(address);
+ if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY >
+ MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) {
+ mBondState.clearPinAttempts(address);
+ setBondState(address, BluetoothDevice.BOND_NONE, result);
+ return;
+ }
+
+ Message message = mHandler.obtainMessage(MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
+ message.obj = address;
+ boolean postResult = mHandler.sendMessageDelayed(message,
+ attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
+ if (!postResult) {
+ mBondState.clearPinAttempts(address);
+ setBondState(address,
+ BluetoothDevice.BOND_NONE, result);
+ return;
+ }
+ mBondState.attempt(address);
}
/** local cache of bonding state.
@@ -1119,7 +1198,7 @@ public class BluetoothService extends IBluetooth.Stub {
mIsDiscovering = isDiscovering;
}
- public synchronized boolean createBond(String address) {
+ private boolean isBondingFeasible(String address) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
if (!isEnabledInternal()) return false;
@@ -1149,8 +1228,13 @@ public class BluetoothService extends IBluetooth.Stub {
return false;
}
}
+ return true;
+ }
+
+ public synchronized boolean createBond(String address) {
+ if (!isBondingFeasible(address)) return false;
- if (!createPairedDeviceNative(address, 60000 /* 1 minute */)) {
+ if (!createPairedDeviceNative(address, 60000 /*1 minute*/ )) {
return false;
}
@@ -1160,6 +1244,51 @@ public class BluetoothService extends IBluetooth.Stub {
return true;
}
+ public synchronized boolean createBondOutOfBand(String address, byte[] hash,
+ byte[] randomizer) {
+ if (!isBondingFeasible(address)) return false;
+
+ if (!createPairedDeviceOutOfBandNative(address, 60000 /* 1 minute */)) {
+ return false;
+ }
+
+ setDeviceOutOfBandData(address, hash, randomizer);
+ mBondState.setPendingOutgoingBonding(address);
+ mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
+
+ return true;
+ }
+
+ public synchronized boolean setDeviceOutOfBandData(String address, byte[] hash,
+ byte[] randomizer) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (!isEnabledInternal()) return false;
+
+ Pair <byte[], byte[]> value = new Pair<byte[], byte[]>(hash, randomizer);
+
+ if (DBG) {
+ log("Setting out of band data for:" + address + ":" +
+ Arrays.toString(hash) + ":" + Arrays.toString(randomizer));
+ }
+
+ mDeviceOobData.put(address, value);
+ return true;
+ }
+
+ Pair<byte[], byte[]> getDeviceOutOfBandData(BluetoothDevice device) {
+ return mDeviceOobData.get(device.getAddress());
+ }
+
+
+ public synchronized byte[] readOutOfBandData() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
+ "Need BLUETOOTH permission");
+ if (!isEnabledInternal()) return null;
+
+ return readAdapterOutOfBandDataNative();
+ }
+
public synchronized boolean cancelBondProcess(String address) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
@@ -1205,6 +1334,10 @@ public class BluetoothService extends IBluetooth.Stub {
return mBondState.listInState(BluetoothDevice.BOND_BONDED);
}
+ /*package*/ synchronized String[] listInState(int state) {
+ return mBondState.listInState(state);
+ }
+
public synchronized int getBondState(String address) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
@@ -1213,6 +1346,15 @@ public class BluetoothService extends IBluetooth.Stub {
return mBondState.getBondState(address.toUpperCase());
}
+ /*package*/ synchronized boolean setBondState(String address, int state) {
+ return setBondState(address, state, 0);
+ }
+
+ /*package*/ synchronized boolean setBondState(String address, int state, int reason) {
+ mBondState.setBondState(address.toUpperCase(), state);
+ return true;
+ }
+
public synchronized boolean isBluetoothDock(String address) {
SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
mContext.MODE_PRIVATE);
@@ -1551,6 +1693,32 @@ public class BluetoothService extends IBluetooth.Stub {
return setPairingConfirmationNative(address, confirm, data.intValue());
}
+ public synchronized boolean setRemoteOutOfBandData(String address) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH_ADMIN permission");
+ if (!isEnabledInternal()) return false;
+ address = address.toUpperCase();
+ Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
+ if (data == null) {
+ Log.w(TAG, "setRemoteOobData(" + address + ") called but no native data available, " +
+ "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
+ " or by bluez.\n");
+ return false;
+ }
+
+ Pair<byte[], byte[]> val = mDeviceOobData.get(address);
+ byte[] hash, randomizer;
+ if (val == null) {
+ // TODO: check what should be passed in this case.
+ hash = new byte[16];
+ randomizer = new byte[16];
+ } else {
+ hash = val.first;
+ randomizer = val.second;
+ }
+ return setRemoteOutOfBandDataNative(address, hash, randomizer, data.intValue());
+ }
+
public synchronized boolean cancelPairingUserInput(String address) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
@@ -2084,6 +2252,9 @@ public class BluetoothService extends IBluetooth.Stub {
private native boolean stopDiscoveryNative();
private native boolean createPairedDeviceNative(String address, int timeout_ms);
+ private native boolean createPairedDeviceOutOfBandNative(String address, int timeout_ms);
+ private native byte[] readAdapterOutOfBandDataNative();
+
private native boolean cancelDeviceCreationNative(String address);
private native boolean removeDeviceNative(String objectPath);
private native int getDeviceServiceChannelNative(String objectPath, String uuid,
@@ -2094,6 +2265,9 @@ public class BluetoothService extends IBluetooth.Stub {
private native boolean setPasskeyNative(String address, int passkey, int nativeData);
private native boolean setPairingConfirmationNative(String address, boolean confirm,
int nativeData);
+ private native boolean setRemoteOutOfBandDataNative(String address, byte[] hash,
+ byte[] randomizer, int nativeData);
+
private native boolean setDevicePropertyBooleanNative(String objectPath, String key,
int value);
private native boolean createDeviceNative(String address);
diff --git a/core/java/android/util/CalendarUtils.java b/core/java/android/util/CalendarUtils.java
new file mode 100644
index 0000000..9a4a67d
--- /dev/null
+++ b/core/java/android/util/CalendarUtils.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import android.content.AsyncQueryHandler;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.provider.Calendar.CalendarCache;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.text.format.Time;
+
+import java.util.Formatter;
+import java.util.HashSet;
+import java.util.Locale;
+
+/**
+ * A class containing utility methods related to Calendar apps.
+ *
+ * @hide
+ */
+public class CalendarUtils {
+ private static final boolean DEBUG = false;
+ private static final String TAG = "CalendarUtils";
+
+ /**
+ * This class contains methods specific to reading and writing time zone
+ * values.
+ */
+ public static class TimeZoneUtils {
+ private static final String[] TIMEZONE_TYPE_ARGS = { CalendarCache.TIMEZONE_KEY_TYPE };
+ private static final String[] TIMEZONE_INSTANCES_ARGS =
+ { CalendarCache.TIMEZONE_KEY_INSTANCES };
+
+ private static StringBuilder mSB = new StringBuilder(50);
+ private static Formatter mF = new Formatter(mSB, Locale.getDefault());
+ private volatile static boolean mFirstTZRequest = true;
+ private volatile static boolean mTZQueryInProgress = false;
+
+ private volatile static boolean mUseHomeTZ = false;
+ private volatile static String mHomeTZ = Time.getCurrentTimezone();
+
+ private static HashSet<Runnable> mTZCallbacks = new HashSet<Runnable>();
+ private static int mToken = 1;
+ private static AsyncTZHandler mHandler;
+
+ // The name of the shared preferences file. This name must be maintained for historical
+ // reasons, as it's what PreferenceManager assigned the first time the file was created.
+ private final String mPrefsName;
+
+ /**
+ * This is the key used for writing whether or not a home time zone should
+ * be used in the Calendar app to the Calendar Preferences.
+ */
+ public static final String KEY_HOME_TZ_ENABLED = "preferences_home_tz_enabled";
+ /**
+ * This is the key used for writing the time zone that should be used if
+ * home time zones are enabled for the Calendar app.
+ */
+ public static final String KEY_HOME_TZ = "preferences_home_tz";
+
+ /**
+ * This is a helper class for handling the async queries and updates for the
+ * time zone settings in Calendar.
+ */
+ private class AsyncTZHandler extends AsyncQueryHandler {
+ public AsyncTZHandler(ContentResolver cr) {
+ super(cr);
+ }
+
+ @Override
+ protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
+ synchronized (mTZCallbacks) {
+ boolean writePrefs = false;
+ // Check the values in the db
+ int keyColumn = cursor.getColumnIndexOrThrow(CalendarCache.KEY);
+ int valueColumn = cursor.getColumnIndexOrThrow(CalendarCache.VALUE);
+ while(cursor.moveToNext()) {
+ String key = cursor.getString(keyColumn);
+ String value = cursor.getString(valueColumn);
+ if (TextUtils.equals(key, CalendarCache.TIMEZONE_KEY_TYPE)) {
+ boolean useHomeTZ = !TextUtils.equals(
+ value, CalendarCache.TIMEZONE_TYPE_AUTO);
+ if (useHomeTZ != mUseHomeTZ) {
+ writePrefs = true;
+ mUseHomeTZ = useHomeTZ;
+ }
+ } else if (TextUtils.equals(
+ key, CalendarCache.TIMEZONE_KEY_INSTANCES_PREVIOUS)) {
+ if (!TextUtils.isEmpty(value) && !TextUtils.equals(mHomeTZ, value)) {
+ writePrefs = true;
+ mHomeTZ = value;
+ }
+ }
+ }
+ if (writePrefs) {
+ SharedPreferences prefs = getSharedPreferences((Context)cookie, mPrefsName);
+ // Write the prefs
+ setSharedPreference(prefs, KEY_HOME_TZ_ENABLED, mUseHomeTZ);
+ setSharedPreference(prefs, KEY_HOME_TZ, mHomeTZ);
+ }
+
+ mTZQueryInProgress = false;
+ for (Runnable callback : mTZCallbacks) {
+ if (callback != null) {
+ callback.run();
+ }
+ }
+ mTZCallbacks.clear();
+ }
+ }
+ }
+
+ /**
+ * The name of the file where the shared prefs for Calendar are stored
+ * must be provided. All activities within an app should provide the
+ * same preferences name or behavior may become erratic.
+ *
+ * @param prefsName
+ */
+ public TimeZoneUtils(String prefsName) {
+ mPrefsName = prefsName;
+ }
+
+ /**
+ * Formats a date or a time range according to the local conventions.
+ *
+ * This formats a date/time range using Calendar's time zone and the
+ * local conventions for the region of the device.
+ *
+ * @param context the context is required only if the time is shown
+ * @param startMillis the start time in UTC milliseconds
+ * @param endMillis the end time in UTC milliseconds
+ * @param flags a bit mask of options See
+ * {@link DateUtils#formatDateRange(Context, Formatter, long, long, int, String) formatDateRange}
+ * @return a string containing the formatted date/time range.
+ */
+ public String formatDateRange(Context context, long startMillis,
+ long endMillis, int flags) {
+ String date;
+ synchronized (mSB) {
+ mSB.setLength(0);
+ date = DateUtils.formatDateRange(context, mF, startMillis, endMillis, flags,
+ getTimeZone(context, null)).toString();
+ }
+ return date;
+ }
+
+ /**
+ * Writes a new home time zone to the db.
+ *
+ * Updates the home time zone in the db asynchronously and updates
+ * the local cache. Sending a time zone of
+ * {@link CalendarCache#TIMEZONE_TYPE_AUTO} will cause it to be set
+ * to the device's time zone. null or empty tz will be ignored.
+ *
+ * @param context The calling activity
+ * @param timeZone The time zone to set Calendar to, or
+ * {@link CalendarCache#TIMEZONE_TYPE_AUTO}
+ */
+ public void setTimeZone(Context context, String timeZone) {
+ if (TextUtils.isEmpty(timeZone)) {
+ if (DEBUG) {
+ Log.d(TAG, "Empty time zone, nothing to be done.");
+ }
+ return;
+ }
+ boolean updatePrefs = false;
+ synchronized (mTZCallbacks) {
+ if (CalendarCache.TIMEZONE_TYPE_AUTO.equals(timeZone)) {
+ if (mUseHomeTZ) {
+ updatePrefs = true;
+ }
+ mUseHomeTZ = false;
+ } else {
+ if (!mUseHomeTZ || !TextUtils.equals(mHomeTZ, timeZone)) {
+ updatePrefs = true;
+ }
+ mUseHomeTZ = true;
+ mHomeTZ = timeZone;
+ }
+ }
+ if (updatePrefs) {
+ // Write the prefs
+ SharedPreferences prefs = getSharedPreferences(context, mPrefsName);
+ setSharedPreference(prefs, KEY_HOME_TZ_ENABLED, mUseHomeTZ);
+ setSharedPreference(prefs, KEY_HOME_TZ, mHomeTZ);
+
+ // Update the db
+ ContentValues values = new ContentValues();
+ if (mHandler == null) {
+ mHandler = new AsyncTZHandler(context.getContentResolver());
+ }
+
+ mHandler.cancelOperation(mToken);
+
+ // skip 0 so query can use it
+ if (++mToken == 0) {
+ mToken = 1;
+ }
+
+ // Write the use home tz setting
+ values.put(CalendarCache.VALUE, mUseHomeTZ ? CalendarCache.TIMEZONE_TYPE_HOME
+ : CalendarCache.TIMEZONE_TYPE_AUTO);
+ mHandler.startUpdate(mToken, null, CalendarCache.URI, values, CalendarCache.WHERE,
+ TIMEZONE_TYPE_ARGS);
+
+ // If using a home tz write it to the db
+ if (mUseHomeTZ) {
+ ContentValues values2 = new ContentValues();
+ values2.put(CalendarCache.VALUE, mHomeTZ);
+ mHandler.startUpdate(mToken, null, CalendarCache.URI, values2,
+ CalendarCache.WHERE, TIMEZONE_INSTANCES_ARGS);
+ }
+ }
+ }
+
+ /**
+ * Gets the time zone that Calendar should be displayed in
+ *
+ * This is a helper method to get the appropriate time zone for Calendar. If this
+ * is the first time this method has been called it will initiate an asynchronous
+ * query to verify that the data in preferences is correct. The callback supplied
+ * will only be called if this query returns a value other than what is stored in
+ * preferences and should cause the calling activity to refresh anything that
+ * depends on calling this method.
+ *
+ * @param context The calling activity
+ * @param callback The runnable that should execute if a query returns new values
+ * @return The string value representing the time zone Calendar should display
+ */
+ public String getTimeZone(Context context, Runnable callback) {
+ synchronized (mTZCallbacks){
+ if (mFirstTZRequest) {
+ mTZQueryInProgress = true;
+ mFirstTZRequest = false;
+
+ SharedPreferences prefs = getSharedPreferences(context, mPrefsName);
+ mUseHomeTZ = prefs.getBoolean(KEY_HOME_TZ_ENABLED, false);
+ mHomeTZ = prefs.getString(KEY_HOME_TZ, Time.getCurrentTimezone());
+
+ // When the async query returns it should synchronize on
+ // mTZCallbacks, update mUseHomeTZ, mHomeTZ, and the
+ // preferences, set mTZQueryInProgress to false, and call all
+ // the runnables in mTZCallbacks.
+ if (mHandler == null) {
+ mHandler = new AsyncTZHandler(context.getContentResolver());
+ }
+ mHandler.startQuery(0, context, CalendarCache.URI, CalendarCache.POJECTION,
+ null, null, null);
+ }
+ if (mTZQueryInProgress) {
+ mTZCallbacks.add(callback);
+ }
+ }
+ return mUseHomeTZ ? mHomeTZ : Time.getCurrentTimezone();
+ }
+
+ /**
+ * Forces a query of the database to check for changes to the time zone.
+ * This should be called if another app may have modified the db. If a
+ * query is already in progress the callback will be added to the list
+ * of callbacks to be called when it returns.
+ *
+ * @param context The calling activity
+ * @param callback The runnable that should execute if a query returns
+ * new values
+ */
+ public void forceDBRequery(Context context, Runnable callback) {
+ synchronized (mTZCallbacks){
+ if (mTZQueryInProgress) {
+ mTZCallbacks.add(callback);
+ return;
+ }
+ mFirstTZRequest = true;
+ getTimeZone(context, callback);
+ }
+ }
+ }
+
+ /**
+ * A helper method for writing a String value to the preferences
+ * asynchronously.
+ *
+ * @param context A context with access to the correct preferences
+ * @param key The preference to write to
+ * @param value The value to write
+ */
+ public static void setSharedPreference(SharedPreferences prefs, String key, String value) {
+// SharedPreferences prefs = getSharedPreferences(context);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString(key, value);
+ editor.apply();
+ }
+
+ /**
+ * A helper method for writing a boolean value to the preferences
+ * asynchronously.
+ *
+ * @param context A context with access to the correct preferences
+ * @param key The preference to write to
+ * @param value The value to write
+ */
+ public static void setSharedPreference(SharedPreferences prefs, String key, boolean value) {
+// SharedPreferences prefs = getSharedPreferences(context, prefsName);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean(key, value);
+ editor.apply();
+ }
+
+ /** Return a properly configured SharedPreferences instance */
+ public static SharedPreferences getSharedPreferences(Context context, String prefsName) {
+ return context.getSharedPreferences(prefsName, Context.MODE_PRIVATE);
+ }
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index fe003a4..b794a6a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1582,7 +1582,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* {@link #OVERSCROLL_ALWAYS}, {@link #OVERSCROLL_IF_CONTENT_SCROLLS},
* and {@link #OVERSCROLL_NEVER}.
*/
- private int mOverscrollMode = OVERSCROLL_ALWAYS;
+ private int mOverscrollMode;
/**
* The parent this view is attached to.
@@ -1876,6 +1876,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
// Used for debug only
//++sInstanceCount;
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+ setOverscrollMode(OVERSCROLL_ALWAYS);
}
/**
diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java
index e766693..1f8d53f 100644
--- a/core/java/android/webkit/JWebCoreJavaBridge.java
+++ b/core/java/android/webkit/JWebCoreJavaBridge.java
@@ -20,6 +20,8 @@ import android.os.Handler;
import android.os.Message;
import android.util.Log;
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
import java.util.Set;
final class JWebCoreJavaBridge extends Handler {
@@ -44,7 +46,8 @@ final class JWebCoreJavaBridge extends Handler {
// keep track of the main WebView attached to the current window so that we
// can get the proper Context.
- private WebView mCurrentMainWebView;
+ private static WeakReference<WebView> sCurrentMainWebView =
+ new WeakReference<WebView>(null);
/* package */
static final int REFRESH_PLUGINS = 100;
@@ -62,20 +65,20 @@ final class JWebCoreJavaBridge extends Handler {
nativeFinalize();
}
- synchronized void setActiveWebView(WebView webview) {
- if (mCurrentMainWebView != null) {
+ static synchronized void setActiveWebView(WebView webview) {
+ if (sCurrentMainWebView.get() != null) {
// it is possible if there is a sub-WebView. Do nothing.
return;
}
- mCurrentMainWebView = webview;
+ sCurrentMainWebView = new WeakReference<WebView>(webview);
}
- synchronized void removeActiveWebView(WebView webview) {
- if (mCurrentMainWebView != webview) {
+ static synchronized void removeActiveWebView(WebView webview) {
+ if (sCurrentMainWebView.get() != webview) {
// it is possible if there is a sub-WebView. Do nothing.
return;
}
- mCurrentMainWebView = null;
+ sCurrentMainWebView.clear();
}
/**
@@ -256,11 +259,12 @@ final class JWebCoreJavaBridge extends Handler {
synchronized private String getSignedPublicKey(int index, String challenge,
String url) {
- if (mCurrentMainWebView != null) {
+ WebView current = sCurrentMainWebView.get();
+ if (current != null) {
// generateKeyPair expects organizations which we don't have. Ignore
// url.
return CertTool.getSignedPublicKey(
- mCurrentMainWebView.getContext(), index, challenge);
+ current.getContext(), index, challenge);
} else {
Log.e(LOGTAG, "There is no active WebView for getSignedPublicKey");
return "";
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4bb11bb..456e0d9 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -4502,9 +4502,9 @@ public class WebView extends AbsoluteLayout
public void onWindowFocusChanged(boolean hasWindowFocus) {
setActive(hasWindowFocus);
if (hasWindowFocus) {
- BrowserFrame.sJavaBridge.setActiveWebView(this);
+ JWebCoreJavaBridge.setActiveWebView(this);
} else {
- BrowserFrame.sJavaBridge.removeActiveWebView(this);
+ JWebCoreJavaBridge.removeActiveWebView(this);
}
super.onWindowFocusChanged(hasWindowFocus);
}
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 1620778..bd87a0d 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -18,6 +18,7 @@ package com.android.internal.app;
import com.android.internal.os.BatteryStatsImpl;
+import android.os.WorkSource;
import android.telephony.SignalStrength;
interface IBatteryStats {
@@ -33,6 +34,9 @@ interface IBatteryStats {
SensorService.cpp */
void noteStopSensor(int uid, int sensor);
+ void noteStartWakelockFromSource(in WorkSource ws, int pid, String name, int type);
+ void noteStopWakelockFromSource(in WorkSource ws, int pid, String name, int type);
+
void noteStartGps(int uid);
void noteStopGps(int uid);
void noteScreenOn();
@@ -57,6 +61,12 @@ interface IBatteryStats {
void noteScanWifiLockReleased(int uid);
void noteWifiMulticastEnabled(int uid);
void noteWifiMulticastDisabled(int uid);
+ void noteFullWifiLockAcquiredFromSource(in WorkSource ws);
+ void noteFullWifiLockReleasedFromSource(in WorkSource ws);
+ void noteScanWifiLockAcquiredFromSource(in WorkSource ws);
+ void noteScanWifiLockReleasedFromSource(in WorkSource ws);
+ void noteWifiMulticastEnabledFromSource(in WorkSource ws);
+ void noteWifiMulticastDisabledFromSource(in WorkSource ws);
void setBatteryState(int status, int health, int plugType, int level, int temp, int volt);
long getAwakeTimeBattery();
long getAwakeTimePlugged();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 0ef1ea5..753dbf0 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -29,6 +29,7 @@ import android.os.ParcelFormatException;
import android.os.Parcelable;
import android.os.Process;
import android.os.SystemClock;
+import android.os.WorkSource;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
@@ -68,12 +69,12 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int VERSION = 50;
// Maximum number of items we will record in the history.
- private static final int MAX_HISTORY_ITEMS = 1000;
+ private static final int MAX_HISTORY_ITEMS = 2000;
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
// in to one common name.
- private static final int MAX_WAKELOCKS_PER_UID = 20;
+ private static final int MAX_WAKELOCKS_PER_UID = 30;
private static final String BATCHED_WAKELOCK_NAME = "*overflow*";
@@ -1171,7 +1172,7 @@ public final class BatteryStatsImpl extends BatteryStats {
// If the current time is basically the same as the last time,
// just collapse into one record.
if (mHistoryEnd != null && mHistoryEnd.cmd == HistoryItem.CMD_UPDATE
- && (mHistoryBaseTime+curTime) < (mHistoryEnd.time+100)) {
+ && (mHistoryBaseTime+curTime) < (mHistoryEnd.time+500)) {
// If the current is the same as the one before, then we no
// longer need the entry.
if (mHistoryLastEnd != null && mHistoryLastEnd.cmd == HistoryItem.CMD_UPDATE
@@ -1187,6 +1188,10 @@ public final class BatteryStatsImpl extends BatteryStats {
return;
}
+ if (mNumHistoryItems == MAX_HISTORY_ITEMS) {
+ addHistoryRecordLocked(curTime, HistoryItem.CMD_OVERFLOW);
+ }
+
if (mNumHistoryItems >= MAX_HISTORY_ITEMS) {
// Once we've reached the maximum number of items, we only
// record changes to the battery level.
@@ -1327,6 +1332,20 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
+ public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name, int type) {
+ int N = ws.size();
+ for (int i=0; i<N; i++) {
+ noteStartWakeLocked(ws.get(i), pid, name, type);
+ }
+ }
+
+ public void noteStopWakeFromSourceLocked(WorkSource ws, int pid, String name, int type) {
+ int N = ws.size();
+ for (int i=0; i<N; i++) {
+ noteStopWakeLocked(ws.get(i), pid, name, type);
+ }
+ }
+
public int startAddingCpuLocked() {
mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
@@ -1947,6 +1966,48 @@ public final class BatteryStatsImpl extends BatteryStats {
getUidStatsLocked(uid).noteWifiMulticastDisabledLocked();
}
+ public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws) {
+ int N = ws.size();
+ for (int i=0; i<N; i++) {
+ noteFullWifiLockAcquiredLocked(ws.get(i));
+ }
+ }
+
+ public void noteFullWifiLockReleasedFromSourceLocked(WorkSource ws) {
+ int N = ws.size();
+ for (int i=0; i<N; i++) {
+ noteFullWifiLockReleasedLocked(ws.get(i));
+ }
+ }
+
+ public void noteScanWifiLockAcquiredFromSourceLocked(WorkSource ws) {
+ int N = ws.size();
+ for (int i=0; i<N; i++) {
+ noteScanWifiLockAcquiredLocked(ws.get(i));
+ }
+ }
+
+ public void noteScanWifiLockReleasedFromSourceLocked(WorkSource ws) {
+ int N = ws.size();
+ for (int i=0; i<N; i++) {
+ noteScanWifiLockReleasedLocked(ws.get(i));
+ }
+ }
+
+ public void noteWifiMulticastEnabledFromSourceLocked(WorkSource ws) {
+ int N = ws.size();
+ for (int i=0; i<N; i++) {
+ noteWifiMulticastEnabledLocked(ws.get(i));
+ }
+ }
+
+ public void noteWifiMulticastDisabledFromSourceLocked(WorkSource ws) {
+ int N = ws.size();
+ for (int i=0; i<N; i++) {
+ noteWifiMulticastDisabledLocked(ws.get(i));
+ }
+ }
+
@Override public long getScreenOnTime(long batteryRealtime, int which) {
return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which);
}
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 2517a8a..6aa77f6 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -28,7 +28,7 @@
#include <surfaceflinger/Surface.h>
#include <ui/egl/android_natives.h>
#include <ui/InputTransport.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
#include "JNIHelp.h"
#include "android_os_MessageQueue.h"
@@ -128,17 +128,17 @@ AInputQueue::~AInputQueue() {
}
void AInputQueue::attachLooper(ALooper* looper, int ident,
- ALooper_callbackFunc* callback, void* data) {
- mPollLoop = static_cast<android::PollLoop*>(looper);
- mPollLoop->setLooperCallback(mConsumer.getChannel()->getReceivePipeFd(),
- ident, POLLIN, callback, data);
- mPollLoop->setLooperCallback(mDispatchKeyRead,
- ident, POLLIN, callback, data);
+ ALooper_callbackFunc callback, void* data) {
+ mLooper = static_cast<android::Looper*>(looper);
+ mLooper->addFd(mConsumer.getChannel()->getReceivePipeFd(),
+ ident, ALOOPER_EVENT_INPUT, callback, data);
+ mLooper->addFd(mDispatchKeyRead,
+ ident, ALOOPER_EVENT_INPUT, callback, data);
}
void AInputQueue::detachLooper() {
- mPollLoop->removeCallback(mConsumer.getChannel()->getReceivePipeFd());
- mPollLoop->removeCallback(mDispatchKeyRead);
+ mLooper->removeFd(mConsumer.getChannel()->getReceivePipeFd());
+ mLooper->removeFd(mDispatchKeyRead);
}
int32_t AInputQueue::hasEvents() {
@@ -440,8 +440,8 @@ struct NativeCode : public ANativeActivity {
if (env != NULL && clazz != NULL) {
env->DeleteGlobalRef(clazz);
}
- if (pollLoop != NULL && mainWorkRead >= 0) {
- pollLoop->removeCallback(mainWorkRead);
+ if (looper != NULL && mainWorkRead >= 0) {
+ looper->removeFd(mainWorkRead);
}
if (nativeInputQueue != NULL) {
nativeInputQueue->mWorkWrite = -1;
@@ -509,7 +509,7 @@ struct NativeCode : public ANativeActivity {
// These are used to wake up the main thread to process work.
int mainWorkRead;
int mainWorkWrite;
- sp<PollLoop> pollLoop;
+ sp<Looper> looper;
};
void android_NativeActivity_setWindowFormat(
@@ -541,15 +541,15 @@ void android_NativeActivity_hideSoftInput(
/*
* Callback for handling native events on the application's main thread.
*/
-static bool mainWorkCallback(int fd, int events, void* data) {
+static int mainWorkCallback(int fd, int events, void* data) {
NativeCode* code = (NativeCode*)data;
if ((events & POLLIN) == 0) {
- return true;
+ return 1;
}
ActivityWork work;
if (!read_work(code->mainWorkRead, &work)) {
- return true;
+ return 1;
}
LOG_TRACE("mainWorkCallback: cmd=%d", work.cmd);
@@ -593,7 +593,7 @@ static bool mainWorkCallback(int fd, int events, void* data) {
break;
}
- return true;
+ return 1;
}
// ------------------------------------------------------------------------
@@ -621,9 +621,9 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQ
return 0;
}
- code->pollLoop = android_os_MessageQueue_getPollLoop(env, messageQueue);
- if (code->pollLoop == NULL) {
- LOGW("Unable to retrieve MessageQueue's PollLoop");
+ code->looper = android_os_MessageQueue_getLooper(env, messageQueue);
+ if (code->looper == NULL) {
+ LOGW("Unable to retrieve MessageQueue's Looper");
delete code;
return 0;
}
@@ -642,7 +642,7 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQ
result = fcntl(code->mainWorkWrite, F_SETFL, O_NONBLOCK);
SLOGW_IF(result != 0, "Could not make main work write pipe "
"non-blocking: %s", strerror(errno));
- code->pollLoop->setCallback(code->mainWorkRead, POLLIN, mainWorkCallback, code);
+ code->looper->addFd(code->mainWorkRead, 0, ALOOPER_EVENT_INPUT, mainWorkCallback, code);
code->ANativeActivity::callbacks = &code->callbacks;
if (env->GetJavaVM(&code->vm) < 0) {
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index e29495c..10ceb7b 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -60,7 +60,7 @@ sensors_module_get_next_sensor(JNIEnv *env, jobject clazz, jobject sensor, jint
Sensor const* const* sensorList;
size_t count = mgr.getSensorList(&sensorList);
- if (next >= count)
+ if (size_t(next) >= count)
return -1;
Sensor const* const list = sensorList[next];
@@ -78,7 +78,7 @@ sensors_module_get_next_sensor(JNIEnv *env, jobject clazz, jobject sensor, jint
env->SetIntField(sensor, sensorOffsets.minDelay, list->getMinDelay());
next++;
- return next<count ? next : 0;
+ return size_t(next) < count ? next : 0;
}
//----------------------------------------------------------------------------
diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp
index 847b5a5..1b203ca 100644
--- a/core/jni/android_os_MessageQueue.cpp
+++ b/core/jni/android_os_MessageQueue.cpp
@@ -18,7 +18,7 @@
#include "JNIHelp.h"
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
#include <utils/Log.h>
#include "android_os_MessageQueue.h"
@@ -39,22 +39,22 @@ public:
NativeMessageQueue();
~NativeMessageQueue();
- inline sp<PollLoop> getPollLoop() { return mPollLoop; }
+ inline sp<Looper> getLooper() { return mLooper; }
bool pollOnce(int timeoutMillis);
void wake();
private:
- sp<PollLoop> mPollLoop;
+ sp<Looper> mLooper;
};
// ----------------------------------------------------------------------------
NativeMessageQueue::NativeMessageQueue() {
- mPollLoop = PollLoop::getForThread();
- if (mPollLoop == NULL) {
- mPollLoop = new PollLoop(false);
- PollLoop::setForThread(mPollLoop);
+ mLooper = Looper::getForThread();
+ if (mLooper == NULL) {
+ mLooper = new Looper(false);
+ Looper::setForThread(mLooper);
}
}
@@ -62,11 +62,11 @@ NativeMessageQueue::~NativeMessageQueue() {
}
bool NativeMessageQueue::pollOnce(int timeoutMillis) {
- return mPollLoop->pollOnce(timeoutMillis) != PollLoop::POLL_TIMEOUT;
+ return mLooper->pollOnce(timeoutMillis) != ALOOPER_POLL_TIMEOUT;
}
void NativeMessageQueue::wake() {
- mPollLoop->wake();
+ mLooper->wake();
}
// ----------------------------------------------------------------------------
@@ -83,10 +83,10 @@ static void android_os_MessageQueue_setNativeMessageQueue(JNIEnv* env, jobject m
reinterpret_cast<jint>(nativeMessageQueue));
}
-sp<PollLoop> android_os_MessageQueue_getPollLoop(JNIEnv* env, jobject messageQueueObj) {
+sp<Looper> android_os_MessageQueue_getLooper(JNIEnv* env, jobject messageQueueObj) {
NativeMessageQueue* nativeMessageQueue =
android_os_MessageQueue_getNativeMessageQueue(env, messageQueueObj);
- return nativeMessageQueue != NULL ? nativeMessageQueue->getPollLoop() : NULL;
+ return nativeMessageQueue != NULL ? nativeMessageQueue->getLooper() : NULL;
}
static void android_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) {
diff --git a/core/jni/android_os_MessageQueue.h b/core/jni/android_os_MessageQueue.h
index 5c742e2..f961d8f 100644
--- a/core/jni/android_os_MessageQueue.h
+++ b/core/jni/android_os_MessageQueue.h
@@ -21,9 +21,9 @@
namespace android {
-class PollLoop;
+class Looper;
-extern sp<PollLoop> android_os_MessageQueue_getPollLoop(JNIEnv* env, jobject messageQueueObj);
+extern sp<Looper> android_os_MessageQueue_getLooper(JNIEnv* env, jobject messageQueueObj);
} // namespace android
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index db45d6d..d8e049d 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -61,6 +61,8 @@ static jmethodID method_onRequestPasskey;
static jmethodID method_onRequestPasskeyConfirmation;
static jmethodID method_onRequestPairingConsent;
static jmethodID method_onDisplayPasskey;
+static jmethodID method_onRequestOobData;
+static jmethodID method_onAgentOutOfBandDataAvailable;
static jmethodID method_onAgentAuthorize;
static jmethodID method_onAgentCancel;
@@ -105,6 +107,8 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
method_onAgentAuthorize = env->GetMethodID(clazz, "onAgentAuthorize",
"(Ljava/lang/String;Ljava/lang/String;)Z");
+ method_onAgentOutOfBandDataAvailable = env->GetMethodID(clazz, "onAgentOutOfBandDataAvailable",
+ "(Ljava/lang/String;)Z");
method_onAgentCancel = env->GetMethodID(clazz, "onAgentCancel", "()V");
method_onRequestPinCode = env->GetMethodID(clazz, "onRequestPinCode",
"(Ljava/lang/String;I)V");
@@ -116,6 +120,8 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
"(Ljava/lang/String;I)V");
method_onDisplayPasskey = env->GetMethodID(clazz, "onDisplayPasskey",
"(Ljava/lang/String;II)V");
+ method_onRequestOobData = env->GetMethodID(clazz, "onRequestOobData",
+ "(Ljava/lang/String;I)V");
field_mNativeData = env->GetFieldID(clazz, "mNativeData", "I");
#endif
@@ -305,6 +311,7 @@ static int register_agent(native_data_t *nat,
{
DBusMessage *msg, *reply;
DBusError err;
+ bool oob = TRUE;
if (!dbus_connection_register_object_path(nat->conn, agent_path,
&agent_vtable, nat)) {
@@ -326,6 +333,7 @@ static int register_agent(native_data_t *nat,
}
dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
DBUS_TYPE_STRING, &capabilities,
+ DBUS_TYPE_BOOLEAN, &oob,
DBUS_TYPE_INVALID);
dbus_error_init(&err);
@@ -934,6 +942,43 @@ DBusHandlerResult agent_event_filter(DBusConnection *conn,
}
goto success;
} else if (dbus_message_is_method_call(msg,
+ "org.bluez.Agent", "OutOfBandAvailable")) {
+ char *object_path;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_OBJECT_PATH, &object_path,
+ DBUS_TYPE_INVALID)) {
+ LOGE("%s: Invalid arguments for OutOfBandData available() method", __FUNCTION__);
+ goto failure;
+ }
+
+ LOGV("... object_path = %s", object_path);
+
+ bool available =
+ env->CallBooleanMethod(nat->me, method_onAgentOutOfBandDataAvailable,
+ env->NewStringUTF(object_path));
+
+
+ // reply
+ if (available) {
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ LOGE("%s: Cannot create message reply\n", __FUNCTION__);
+ goto failure;
+ }
+ dbus_connection_send(nat->conn, reply, NULL);
+ dbus_message_unref(reply);
+ } else {
+ DBusMessage *reply = dbus_message_new_error(msg,
+ "org.bluez.Error.DoesNotExist", "OutofBand data not available");
+ if (!reply) {
+ LOGE("%s: Cannot create message reply\n", __FUNCTION__);
+ goto failure;
+ }
+ dbus_connection_send(nat->conn, reply, NULL);
+ dbus_message_unref(reply);
+ }
+ goto success;
+ } else if (dbus_message_is_method_call(msg,
"org.bluez.Agent", "RequestPinCode")) {
char *object_path;
if (!dbus_message_get_args(msg, NULL,
@@ -964,6 +1009,21 @@ DBusHandlerResult agent_event_filter(DBusConnection *conn,
int(msg));
goto success;
} else if (dbus_message_is_method_call(msg,
+ "org.bluez.Agent", "RequestOobData")) {
+ char *object_path;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_OBJECT_PATH, &object_path,
+ DBUS_TYPE_INVALID)) {
+ LOGE("%s: Invalid arguments for RequestOobData() method", __FUNCTION__);
+ goto failure;
+ }
+
+ dbus_message_ref(msg); // increment refcount because we pass to java
+ env->CallVoidMethod(nat->me, method_onRequestOobData,
+ env->NewStringUTF(object_path),
+ int(msg));
+ goto success;
+ } else if (dbus_message_is_method_call(msg,
"org.bluez.Agent", "DisplayPasskey")) {
char *object_path;
uint32_t passkey;
diff --git a/core/jni/android_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp
index 4420aca..daa59a6 100644
--- a/core/jni/android_server_BluetoothService.cpp
+++ b/core/jni/android_server_BluetoothService.cpp
@@ -288,6 +288,46 @@ done:
#endif
}
+static jbyteArray readAdapterOutOfBandDataNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ DBusError err;
+ jbyte *hash, *randomizer;
+ jbyteArray byteArray = NULL;
+ int hash_len, r_len;
+ if (nat) {
+ DBusMessage *reply = dbus_func_args(env, nat->conn,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE, "ReadLocalOutOfBandData",
+ DBUS_TYPE_INVALID);
+ if (!reply) return NULL;
+
+ dbus_error_init(&err);
+ if (dbus_message_get_args(reply, &err,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash, &hash_len,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &randomizer, &r_len,
+ DBUS_TYPE_INVALID)) {
+ if (hash_len == 16 && r_len == 16) {
+ byteArray = env->NewByteArray(32);
+ if (byteArray) {
+ env->SetByteArrayRegion(byteArray, 0, 16, hash);
+ env->SetByteArrayRegion(byteArray, 16, 16, randomizer);
+ }
+ } else {
+ LOGE("readAdapterOutOfBandDataNative: Hash len = %d, R len = %d",
+ hash_len, r_len);
+ }
+ } else {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ }
+ dbus_message_unref(reply);
+ return byteArray;
+ }
+#endif
+ return NULL;
+}
+
static jboolean createPairedDeviceNative(JNIEnv *env, jobject object,
jstring address, jint timeout_ms) {
LOGV(__FUNCTION__);
@@ -324,6 +364,41 @@ static jboolean createPairedDeviceNative(JNIEnv *env, jobject object,
return JNI_FALSE;
}
+static jboolean createPairedDeviceOutOfBandNative(JNIEnv *env, jobject object,
+ jstring address, jint timeout_ms) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
+ struct event_loop_native_data_t *eventLoopNat =
+ get_EventLoop_native_data(env, eventLoop);
+
+ if (nat && eventLoopNat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+ LOGV("... address = %s", c_address);
+ char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
+ const char *capabilities = "DisplayYesNo";
+ const char *agent_path = "/android/bluetooth/remote_device_agent";
+
+ strlcpy(context_address, c_address, BTADDR_SIZE); // for callback
+ bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms,
+ onCreatePairedDeviceResult, // callback
+ context_address,
+ eventLoopNat,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE,
+ "CreatePairedDeviceOutOfBand",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_OBJECT_PATH, &agent_path,
+ DBUS_TYPE_STRING, &capabilities,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ return ret ? JNI_TRUE : JNI_FALSE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
static jint getDeviceServiceChannelNative(JNIEnv *env, jobject object,
jstring path,
jstring pattern, jint attr_id) {
@@ -490,6 +565,40 @@ static jboolean setPasskeyNative(JNIEnv *env, jobject object, jstring address,
return JNI_FALSE;
}
+static jboolean setRemoteOutOfBandDataNative(JNIEnv *env, jobject object, jstring address,
+ jbyteArray hash, jbyteArray randomizer, int nativeData) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ DBusMessage *msg = (DBusMessage *)nativeData;
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ jbyte *h_ptr = env->GetByteArrayElements(hash, NULL);
+ jbyte *r_ptr = env->GetByteArrayElements(randomizer, NULL);
+ if (!reply) {
+ LOGE("%s: Cannot create message reply to return remote OOB data to "
+ "D-Bus\n", __FUNCTION__);
+ dbus_message_unref(msg);
+ return JNI_FALSE;
+ }
+
+ dbus_message_append_args(reply,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &h_ptr, 16,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &r_ptr, 16,
+ DBUS_TYPE_INVALID);
+
+ env->ReleaseByteArrayElements(hash, h_ptr, 0);
+ env->ReleaseByteArrayElements(randomizer, r_ptr, 0);
+
+ dbus_connection_send(nat->conn, reply, NULL);
+ dbus_message_unref(msg);
+ dbus_message_unref(reply);
+ return JNI_TRUE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
static jboolean setPinNative(JNIEnv *env, jobject object, jstring address,
jstring pin, int nativeData) {
#ifdef HAVE_BLUETOOTH
@@ -907,7 +1016,10 @@ static JNINativeMethod sMethods[] = {
{"startDiscoveryNative", "()Z", (void*)startDiscoveryNative},
{"stopDiscoveryNative", "()Z", (void *)stopDiscoveryNative},
+ {"readAdapterOutOfBandDataNative", "()[B", (void *)readAdapterOutOfBandDataNative},
{"createPairedDeviceNative", "(Ljava/lang/String;I)Z", (void *)createPairedDeviceNative},
+ {"createPairedDeviceOutOfBandNative", "(Ljava/lang/String;I)Z",
+ (void *)createPairedDeviceOutOfBandNative},
{"cancelDeviceCreationNative", "(Ljava/lang/String;)Z", (void *)cancelDeviceCreationNative},
{"removeDeviceNative", "(Ljava/lang/String;)Z", (void *)removeDeviceNative},
{"getDeviceServiceChannelNative", "(Ljava/lang/String;Ljava/lang/String;I)I",
@@ -916,6 +1028,7 @@ static JNINativeMethod sMethods[] = {
{"setPairingConfirmationNative", "(Ljava/lang/String;ZI)Z",
(void *)setPairingConfirmationNative},
{"setPasskeyNative", "(Ljava/lang/String;II)Z", (void *)setPasskeyNative},
+ {"setRemoteOutOfBandDataNative", "(Ljava/lang/String;[B[BI)Z", (void *)setRemoteOutOfBandDataNative},
{"setPinNative", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)setPinNative},
{"cancelPairingUserInputNative", "(Ljava/lang/String;I)Z",
(void *)cancelPairingUserInputNative},
diff --git a/core/jni/android_view_InputQueue.cpp b/core/jni/android_view_InputQueue.cpp
index 42f35d1..282e9ed 100644
--- a/core/jni/android_view_InputQueue.cpp
+++ b/core/jni/android_view_InputQueue.cpp
@@ -29,7 +29,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <utils/Log.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
#include <ui/InputTransport.h>
@@ -77,7 +77,7 @@ private:
};
Connection(uint16_t id,
- const sp<InputChannel>& inputChannel, const sp<PollLoop>& pollLoop);
+ const sp<InputChannel>& inputChannel, const sp<Looper>& looper);
inline const char* getInputChannelName() const { return inputChannel->getName().string(); }
@@ -88,7 +88,7 @@ private:
sp<InputChannel> inputChannel;
InputConsumer inputConsumer;
- sp<PollLoop> pollLoop;
+ sp<Looper> looper;
jobject inputHandlerObjGlobal;
PreallocatedInputEventFactory inputEventFactory;
@@ -110,7 +110,7 @@ private:
static void handleInputChannelDisposed(JNIEnv* env,
jobject inputChannelObj, const sp<InputChannel>& inputChannel, void* data);
- static bool handleReceiveCallback(int receiveFd, int events, void* data);
+ static int handleReceiveCallback(int receiveFd, int events, void* data);
static jlong generateFinishedToken(int32_t receiveFd,
uint16_t connectionId, uint16_t messageSeqNum);
@@ -141,7 +141,7 @@ status_t NativeInputQueue::registerInputChannel(JNIEnv* env, jobject inputChanne
LOGD("channel '%s' - Registered", inputChannel->getName().string());
#endif
- sp<PollLoop> pollLoop = android_os_MessageQueue_getPollLoop(env, messageQueueObj);
+ sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj);
{ // acquire lock
AutoMutex _l(mLock);
@@ -153,7 +153,7 @@ status_t NativeInputQueue::registerInputChannel(JNIEnv* env, jobject inputChanne
}
uint16_t connectionId = mNextConnectionId++;
- sp<Connection> connection = new Connection(connectionId, inputChannel, pollLoop);
+ sp<Connection> connection = new Connection(connectionId, inputChannel, looper);
status_t result = connection->inputConsumer.initialize();
if (result) {
LOGW("Failed to initialize input consumer for input channel '%s', status=%d",
@@ -166,7 +166,7 @@ status_t NativeInputQueue::registerInputChannel(JNIEnv* env, jobject inputChanne
int32_t receiveFd = inputChannel->getReceivePipeFd();
mConnectionsByReceiveFd.add(receiveFd, connection);
- pollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this);
+ looper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock
android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
@@ -201,7 +201,7 @@ status_t NativeInputQueue::unregisterInputChannel(JNIEnv* env, jobject inputChan
connection->status = Connection::STATUS_ZOMBIE;
- connection->pollLoop->removeCallback(inputChannel->getReceivePipeFd());
+ connection->looper->removeFd(inputChannel->getReceivePipeFd());
env->DeleteGlobalRef(connection->inputHandlerObjGlobal);
connection->inputHandlerObjGlobal = NULL;
@@ -293,7 +293,7 @@ void NativeInputQueue::handleInputChannelDisposed(JNIEnv* env,
q->unregisterInputChannel(env, inputChannelObj);
}
-bool NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* data) {
+int NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* data) {
NativeInputQueue* q = static_cast<NativeInputQueue*>(data);
JNIEnv* env = AndroidRuntime::getJNIEnv();
@@ -308,33 +308,33 @@ bool NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* da
if (connectionIndex < 0) {
LOGE("Received spurious receive callback for unknown input channel. "
"fd=%d, events=0x%x", receiveFd, events);
- return false; // remove the callback
+ return 0; // remove the callback
}
connection = q->mConnectionsByReceiveFd.valueAt(connectionIndex);
- if (events & (POLLERR | POLLHUP | POLLNVAL)) {
+ if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
LOGE("channel '%s' ~ Publisher closed input channel or an error occurred. "
"events=0x%x", connection->getInputChannelName(), events);
- return false; // remove the callback
+ return 0; // remove the callback
}
- if (! (events & POLLIN)) {
+ if (! (events & ALOOPER_EVENT_INPUT)) {
LOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
"events=0x%x", connection->getInputChannelName(), events);
- return true;
+ return 1;
}
status_t status = connection->inputConsumer.receiveDispatchSignal();
if (status) {
LOGE("channel '%s' ~ Failed to receive dispatch signal. status=%d",
connection->getInputChannelName(), status);
- return false; // remove the callback
+ return 0; // remove the callback
}
if (connection->messageInProgress) {
LOGW("channel '%s' ~ Publisher sent spurious dispatch signal.",
connection->getInputChannelName());
- return true;
+ return 1;
}
status = connection->inputConsumer.consume(& connection->inputEventFactory, & inputEvent);
@@ -342,7 +342,7 @@ bool NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* da
LOGW("channel '%s' ~ Failed to consume input event. status=%d",
connection->getInputChannelName(), status);
connection->inputConsumer.sendFinishedSignal();
- return true;
+ return 1;
}
connection->messageInProgress = true;
@@ -394,7 +394,7 @@ bool NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* da
connection->getInputChannelName());
env->DeleteLocalRef(inputHandlerObjLocal);
q->finished(env, finishedToken, false);
- return true;
+ return 1;
}
#if DEBUG_DISPATCH_CYCLE
@@ -417,7 +417,7 @@ bool NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* da
env->DeleteLocalRef(inputEventObj);
env->DeleteLocalRef(inputHandlerObjLocal);
- return true;
+ return 1;
}
jlong NativeInputQueue::generateFinishedToken(int32_t receiveFd, uint16_t connectionId,
@@ -435,9 +435,9 @@ void NativeInputQueue::parseFinishedToken(jlong finishedToken,
// ----------------------------------------------------------------------------
NativeInputQueue::Connection::Connection(uint16_t id,
- const sp<InputChannel>& inputChannel, const sp<PollLoop>& pollLoop) :
+ const sp<InputChannel>& inputChannel, const sp<Looper>& looper) :
id(id), status(STATUS_NORMAL), inputChannel(inputChannel), inputConsumer(inputChannel),
- pollLoop(pollLoop), inputHandlerObjGlobal(NULL),
+ looper(looper), inputHandlerObjGlobal(NULL),
messageSeqNum(0), messageInProgress(false) {
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a9e4971..9b9b4be 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -930,7 +930,7 @@
<permission android:name="android.permission.UPDATE_DEVICE_STATS"
android:label="@string/permlab_batteryStats"
android:description="@string/permdesc_batteryStats"
- android:protectionLevel="signature" />
+ android:protectionLevel="signatureOrSystem" />
<!-- Allows an application to open windows that are for use by parts
of the system user interface. Not for use by third party apps. -->
diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd
index 4594bb5..3d4b6a1 100644
--- a/docs/html/sdk/eclipse-adt.jd
+++ b/docs/html/sdk/eclipse-adt.jd
@@ -428,7 +428,7 @@ environment. </p>
<h3 id="preparing">Configuring the ADT Plugin</h3>
-<p>Once you've successfully downnloaded ADT as described above, the next step
+<p>Once you've successfully downloaded ADT as described above, the next step
is to modify your ADT preferences in Eclipse to point to the Android SDK directory:</p>
<ol>
diff --git a/include/android_runtime/android_app_NativeActivity.h b/include/android_runtime/android_app_NativeActivity.h
index fdceb84..b49e02a 100644
--- a/include/android_runtime/android_app_NativeActivity.h
+++ b/include/android_runtime/android_app_NativeActivity.h
@@ -18,6 +18,7 @@
#define _ANDROID_APP_NATIVEACTIVITY_H
#include <ui/InputTransport.h>
+#include <utils/Looper.h>
#include <android/native_activity.h>
@@ -69,7 +70,7 @@ public:
/* Destroys the consumer and releases its input channel. */
~AInputQueue();
- void attachLooper(ALooper* looper, int ident, ALooper_callbackFunc* callback, void* data);
+ void attachLooper(ALooper* looper, int ident, ALooper_callbackFunc callback, void* data);
void detachLooper();
@@ -103,7 +104,7 @@ private:
void wakeupDispatch();
android::InputConsumer mConsumer;
- android::sp<android::PollLoop> mPollLoop;
+ android::sp<android::Looper> mLooper;
int mDispatchKeyRead;
int mDispatchKeyWrite;
diff --git a/include/gui/SensorEventQueue.h b/include/gui/SensorEventQueue.h
index 6581ae3..97dd391 100644
--- a/include/gui/SensorEventQueue.h
+++ b/include/gui/SensorEventQueue.h
@@ -42,7 +42,7 @@ namespace android {
class ISensorEventConnection;
class Sensor;
-class PollLoop;
+class Looper;
// ----------------------------------------------------------------------------
@@ -69,11 +69,11 @@ public:
status_t disableSensor(int32_t handle) const;
private:
- sp<PollLoop> getPollLoop() const;
+ sp<Looper> getLooper() const;
sp<ISensorEventConnection> mSensorEventConnection;
sp<SensorChannel> mSensorChannel;
mutable Mutex mLock;
- mutable sp<PollLoop> mPollLoop;
+ mutable sp<Looper> mLooper;
};
// ----------------------------------------------------------------------------
diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h
index 0f4594f..c913355 100644
--- a/include/ui/FramebufferNativeWindow.h
+++ b/include/ui/FramebufferNativeWindow.h
@@ -56,6 +56,9 @@ public:
status_t setUpdateRectangle(const Rect& updateRect);
status_t compositionComplete();
+ // for debugging only
+ int getCurrentBufferIndex() const;
+
private:
friend class LightRefBase<FramebufferNativeWindow>;
~FramebufferNativeWindow(); // this class cannot be overloaded
@@ -77,6 +80,7 @@ private:
int32_t mNumBuffers;
int32_t mNumFreeBuffers;
int32_t mBufferHead;
+ int32_t mCurrentBufferIndex;
bool mUpdateOnDemand;
};
diff --git a/include/ui/GraphicLog.h b/include/ui/GraphicLog.h
new file mode 100644
index 0000000..f929e6a
--- /dev/null
+++ b/include/ui/GraphicLog.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef _UI_GRAPHIC_LOG_H
+#define _UI_GRAPHIC_LOG_H
+
+#include <utils/Singleton.h>
+#include <cutils/compiler.h>
+
+namespace android {
+
+class GraphicLog : public Singleton<GraphicLog>
+{
+ int32_t mEnabled;
+ static void logImpl(int32_t tag, int32_t buffer);
+ static void logImpl(int32_t tag, int32_t identity, int32_t buffer);
+
+public:
+ enum {
+ SF_APP_DEQUEUE_BEFORE = 60000,
+ SF_APP_DEQUEUE_AFTER = 60001,
+ SF_APP_LOCK_BEFORE = 60002,
+ SF_APP_LOCK_AFTER = 60003,
+ SF_APP_QUEUE = 60004,
+
+ SF_REPAINT = 60005,
+ SF_COMPOSITION_COMPLETE = 60006,
+ SF_UNLOCK_CLIENTS = 60007,
+ SF_SWAP_BUFFERS = 60008,
+ SF_REPAINT_DONE = 60009,
+
+ SF_FB_POST_BEFORE = 60010,
+ SF_FB_POST_AFTER = 60011,
+ SF_FB_DEQUEUE_BEFORE = 60012,
+ SF_FB_DEQUEUE_AFTER = 60013,
+ SF_FB_LOCK_BEFORE = 60014,
+ SF_FB_LOCK_AFTER = 60015,
+ };
+
+ inline void log(int32_t tag, int32_t buffer) {
+ if (CC_UNLIKELY(mEnabled))
+ logImpl(tag, buffer);
+ }
+ inline void log(int32_t tag, int32_t identity, int32_t buffer) {
+ if (CC_UNLIKELY(mEnabled))
+ logImpl(tag, identity, buffer);
+ }
+
+ GraphicLog();
+
+ void setEnabled(bool enable);
+};
+
+}
+
+#endif // _UI_GRAPHIC_LOG_H
+
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index a06208a..d7e6254 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -25,7 +25,7 @@
#include <utils/Timers.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
#include <utils/Pool.h>
#include <stddef.h>
@@ -826,7 +826,7 @@ private:
Mutex mLock;
Allocator mAllocator;
- sp<PollLoop> mPollLoop;
+ sp<Looper> mLooper;
EventEntry* mPendingEvent;
Queue<EventEntry> mInboundQueue;
@@ -837,7 +837,7 @@ private:
void dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, nsecs_t keyRepeatDelay,
nsecs_t* nextWakeupTime);
- // Enqueues an inbound event. Returns true if mPollLoop->wake() should be called.
+ // Enqueues an inbound event. Returns true if mLooper->wake() should be called.
bool enqueueInboundEventLocked(EventEntry* entry);
// App switch latency optimization.
@@ -1010,7 +1010,7 @@ private:
void abortDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
bool broken);
void drainOutboundQueueLocked(Connection* connection, DispatchEntry* firstDispatchEntryToDrain);
- static bool handleReceiveCallback(int receiveFd, int events, void* data);
+ static int handleReceiveCallback(int receiveFd, int events, void* data);
// Preempting input dispatch.
bool preemptInputDispatchInnerLocked();
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h
index 82831e2..dc9e27a 100644
--- a/include/ui/InputTransport.h
+++ b/include/ui/InputTransport.h
@@ -33,7 +33,6 @@
#include <semaphore.h>
#include <ui/Input.h>
#include <utils/Errors.h>
-#include <utils/PollLoop.h>
#include <utils/Timers.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
diff --git a/include/utils/Looper.h b/include/utils/Looper.h
new file mode 100644
index 0000000..92e4b0a
--- /dev/null
+++ b/include/utils/Looper.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef UTILS_LOOPER_H
+#define UTILS_LOOPER_H
+
+#include <utils/threads.h>
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+
+#include <android/looper.h>
+
+/*
+ * Declare a concrete type for the NDK's looper forward declaration.
+ */
+struct ALooper {
+};
+
+namespace android {
+
+/**
+ * A polling loop that supports monitoring file descriptor events, optionally
+ * using callbacks. The implementation uses epoll() internally.
+ *
+ * A looper can be associated with a thread although there is no requirement that it must be.
+ */
+class Looper : public ALooper, public RefBase {
+protected:
+ virtual ~Looper();
+
+public:
+ /**
+ * Creates a looper.
+ *
+ * If allowNonCallbaks is true, the looper will allow file descriptors to be
+ * registered without associated callbacks. This assumes that the caller of
+ * pollOnce() is prepared to handle callback-less events itself.
+ */
+ Looper(bool allowNonCallbacks);
+
+ /**
+ * Returns whether this looper instance allows the registration of file descriptors
+ * using identifiers instead of callbacks.
+ */
+ bool getAllowNonCallbacks() const;
+
+ /**
+ * Waits for events to be available, with optional timeout in milliseconds.
+ * Invokes callbacks for all file descriptors on which an event occurred.
+ *
+ * If the timeout is zero, returns immediately without blocking.
+ * If the timeout is negative, waits indefinitely until an event appears.
+ *
+ * Returns ALOOPER_POLL_WAKE if the poll was awoken using wake() before
+ * the timeout expired and no callbacks were invoked and no other file
+ * descriptors were ready.
+ *
+ * Returns ALOOPER_POLL_CALLBACK if one or more callbacks were invoked.
+ *
+ * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
+ * timeout expired.
+ *
+ * Returns ALOOPER_POLL_ERROR if an error occurred.
+ *
+ * Returns a value >= 0 containing an identifier if its file descriptor has data
+ * and it has no callback function (requiring the caller here to handle it).
+ * In this (and only this) case outFd, outEvents and outData will contain the poll
+ * events and data associated with the fd, otherwise they will be set to NULL.
+ *
+ * This method does not return until it has finished invoking the appropriate callbacks
+ * for all file descriptors that were signalled.
+ */
+ int pollOnce(int timeoutMillis,
+ int* outFd = NULL, int* outEvents = NULL, void** outData = NULL);
+
+ /**
+ * Like pollOnce(), but performs all pending callbacks until all
+ * data has been consumed or a file descriptor is available with no callback.
+ * This function will never return ALOOPER_POLL_CALLBACK.
+ */
+ int pollAll(int timeoutMillis,
+ int* outFd = NULL, int* outEvents = NULL, void** outData = NULL);
+
+ /**
+ * Wakes the poll asynchronously.
+ *
+ * This method can be called on any thread.
+ * This method returns immediately.
+ */
+ void wake();
+
+ /**
+ * Adds a new file descriptor to be polled by the looper.
+ * If the same file descriptor was previously added, it is replaced.
+ *
+ * "fd" is the file descriptor to be added.
+ * "ident" is an identifier for this event, which is returned from ALooper_pollOnce().
+ * The identifier must be >= 0, or ALOOPER_POLL_CALLBACK if providing a non-NULL callback.
+ * "events" are the poll events to wake up on. Typically this is ALOOPER_EVENT_INPUT.
+ * "callback" is the function to call when there is an event on the file descriptor.
+ * "data" is a private data pointer to supply to the callback.
+ *
+ * There are two main uses of this function:
+ *
+ * (1) If "callback" is non-NULL, then this function will be called when there is
+ * data on the file descriptor. It should execute any events it has pending,
+ * appropriately reading from the file descriptor. The 'ident' is ignored in this case.
+ *
+ * (2) If "callback" is NULL, the 'ident' will be returned by ALooper_pollOnce
+ * when its file descriptor has data available, requiring the caller to take
+ * care of processing it.
+ *
+ * Returns 1 if the file descriptor was added, 0 if the arguments were invalid.
+ *
+ * This method can be called on any thread.
+ * This method may block briefly if it needs to wake the poll.
+ */
+ int addFd(int fd, int ident,
+ int events, ALooper_callbackFunc callback, void* data = NULL);
+
+ /**
+ * Removes a previously added file descriptor from the looper.
+ *
+ * When this method returns, it is safe to close the file descriptor since the looper
+ * will no longer have a reference to it. However, it is possible for the callback to
+ * already be running or for it to run one last time if the file descriptor was already
+ * signalled. Calling code is responsible for ensuring that this case is safely handled.
+ * For example, if the callback takes care of removing itself during its own execution either
+ * by returning 0 or by calling this method, then it can be guaranteed to not be invoked
+ * again at any later time unless registered anew.
+ *
+ * Returns 1 if the file descriptor was removed, 0 if none was previously registered.
+ *
+ * This method can be called on any thread.
+ * This method may block briefly if it needs to wake the poll.
+ */
+ int removeFd(int fd);
+
+ /**
+ * Prepares a looper associated with the calling thread, and returns it.
+ * If the thread already has a looper, it is returned. Otherwise, a new
+ * one is created, associated with the thread, and returned.
+ *
+ * The opts may be ALOOPER_PREPARE_ALLOW_NON_CALLBACKS or 0.
+ */
+ static sp<Looper> prepare(int opts);
+
+ /**
+ * Sets the given looper to be associated with the calling thread.
+ * If another looper is already associated with the thread, it is replaced.
+ *
+ * If "looper" is NULL, removes the currently associated looper.
+ */
+ static void setForThread(const sp<Looper>& looper);
+
+ /**
+ * Returns the looper associated with the calling thread, or NULL if
+ * there is not one.
+ */
+ static sp<Looper> getForThread();
+
+private:
+ struct Request {
+ int fd;
+ int ident;
+ ALooper_callbackFunc callback;
+ void* data;
+ };
+
+ struct Response {
+ int events;
+ Request request;
+ };
+
+ const bool mAllowNonCallbacks; // immutable
+
+ int mEpollFd; // immutable
+ int mWakeReadPipeFd; // immutable
+ int mWakeWritePipeFd; // immutable
+
+ // Locked list of file descriptor monitoring requests.
+ Mutex mLock;
+ KeyedVector<int, Request> mRequests;
+
+ // This state is only used privately by pollOnce and does not require a lock since
+ // it runs on a single thread.
+ Vector<Response> mResponses;
+ size_t mResponseIndex;
+
+ int pollInner(int timeoutMillis);
+
+ static void threadDestructor(void *st);
+};
+
+} // namespace android
+
+#endif // UTILS_LOOPER_H
diff --git a/include/utils/PollLoop.h b/include/utils/PollLoop.h
deleted file mode 100644
index c2dfe5d..0000000
--- a/include/utils/PollLoop.h
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#ifndef UTILS_POLL_LOOP_H
-#define UTILS_POLL_LOOP_H
-
-#include <utils/Vector.h>
-#include <utils/threads.h>
-
-#include <sys/poll.h>
-
-#include <android/looper.h>
-
-struct ALooper : public android::RefBase {
-protected:
- virtual ~ALooper() { }
-
-public:
- ALooper() { }
-};
-
-namespace android {
-
-/**
- * A basic file descriptor polling loop based on poll() with callbacks.
- */
-class PollLoop : public ALooper {
-protected:
- virtual ~PollLoop();
-
-public:
- PollLoop(bool allowNonCallbacks);
-
- /**
- * A callback that it to be invoked when an event occurs on a file descriptor.
- * Specifies the events that were triggered and the user data provided when the
- * callback was set.
- *
- * Returns true if the callback should be kept, false if it should be removed automatically
- * after the callback returns.
- */
- typedef bool (*Callback)(int fd, int events, void* data);
-
- enum {
- POLL_CALLBACK = ALOOPER_POLL_CALLBACK,
- POLL_TIMEOUT = ALOOPER_POLL_TIMEOUT,
- POLL_ERROR = ALOOPER_POLL_ERROR,
- };
-
- /**
- * Performs a single call to poll() with optional timeout in milliseconds.
- * Invokes callbacks for all file descriptors on which an event occurred.
- *
- * If the timeout is zero, returns immediately without blocking.
- * If the timeout is negative, waits indefinitely until awoken.
- *
- * Returns ALOOPER_POLL_CALLBACK if a callback was invoked.
- *
- * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
- * timeout expired.
- *
- * Returns ALOPER_POLL_ERROR if an error occurred.
- *
- * Returns a value >= 0 containing a file descriptor if it has data
- * and it has no callback function (requiring the caller here to handle it).
- * In this (and only this) case outEvents and outData will contain the poll
- * events and data associated with the fd.
- *
- * This method must only be called on the thread owning the PollLoop.
- * This method blocks until either a file descriptor is signalled, a timeout occurs,
- * or wake() is called.
- * This method does not return until it has finished invoking the appropriate callbacks
- * for all file descriptors that were signalled.
- */
- int32_t pollOnce(int timeoutMillis, int* outEvents = NULL, void** outData = NULL);
-
- /**
- * Wakes the loop asynchronously.
- *
- * This method can be called on any thread.
- * This method returns immediately.
- */
- void wake();
-
- /**
- * Control whether this PollLoop instance allows using IDs instead
- * of callbacks.
- */
- bool getAllowNonCallbacks() const;
-
- /**
- * Sets the callback for a file descriptor, replacing the existing one, if any.
- * It is an error to call this method with events == 0 or callback == NULL.
- *
- * Note that a callback can be invoked with the POLLERR, POLLHUP or POLLNVAL events
- * even if it is not explicitly requested when registered.
- *
- * This method can be called on any thread.
- * This method may block briefly if it needs to wake the poll loop.
- */
- void setCallback(int fd, int ident, int events, Callback callback, void* data = NULL);
-
- /**
- * Convenience for above setCallback when ident is not used. In this case
- * the ident is set to POLL_CALLBACK.
- */
- void setCallback(int fd, int events, Callback callback, void* data = NULL);
-
- /**
- * Like setCallback(), but for the NDK callback function.
- */
- void setLooperCallback(int fd, int ident, int events, ALooper_callbackFunc* callback,
- void* data);
-
- /**
- * Removes the callback for a file descriptor, if one exists.
- *
- * When this method returns, it is safe to close the file descriptor since the poll loop
- * will no longer have a reference to it. However, it is possible for the callback to
- * already be running or for it to run one last time if the file descriptor was already
- * signalled. Calling code is responsible for ensuring that this case is safely handled.
- * For example, if the callback takes care of removing itself during its own execution either
- * by returning false or calling this method, then it can be guaranteed to not be invoked
- * again at any later time unless registered anew.
- *
- * This method can be called on any thread.
- * This method may block briefly if it needs to wake the poll loop.
- *
- * Returns true if a callback was actually removed, false if none was registered.
- */
- bool removeCallback(int fd);
-
- /**
- * Set the given PollLoop to be associated with the
- * calling thread. There must be a 1:1 relationship between
- * PollLoop and thread.
- */
- static void setForThread(const sp<PollLoop>& pollLoop);
-
- /**
- * Return the PollLoop associated with the calling thread.
- */
- static sp<PollLoop> getForThread();
-
-private:
- struct RequestedCallback {
- Callback callback;
- ALooper_callbackFunc* looperCallback;
- int ident;
- void* data;
- };
-
- struct PendingCallback {
- int fd;
- int ident;
- int events;
- Callback callback;
- ALooper_callbackFunc* looperCallback;
- void* data;
- };
-
- const bool mAllowNonCallbacks; // immutable
-
- int mWakeReadPipeFd; // immutable
- int mWakeWritePipeFd; // immutable
-
- // The lock guards state used to track whether there is a poll() in progress and whether
- // there are any other threads waiting in wakeAndLock(). The condition variables
- // are used to transfer control among these threads such that all waiters are
- // serviced before a new poll can begin.
- // The wakeAndLock() method increments mWaiters, wakes the poll, blocks on mAwake
- // until mPolling becomes false, then decrements mWaiters again.
- // The poll() method blocks on mResume until mWaiters becomes 0, then sets
- // mPolling to true, blocks until the poll completes, then resets mPolling to false
- // and signals mResume if there are waiters.
- Mutex mLock;
- bool mPolling; // guarded by mLock
- uint32_t mWaiters; // guarded by mLock
- Condition mAwake; // guarded by mLock
- Condition mResume; // guarded by mLock
-
- // The next two vectors are only mutated when mPolling is false since they must
- // not be changed while the poll() system call is in progress. To mutate these
- // vectors, the poll() must first be awoken then the lock acquired.
- Vector<struct pollfd> mRequestedFds;
- Vector<RequestedCallback> mRequestedCallbacks;
-
- // This state is only used privately by pollOnce and does not require a lock since
- // it runs on a single thread.
- Vector<PendingCallback> mPendingCallbacks;
- Vector<PendingCallback> mPendingFds;
- size_t mPendingFdsPos;
-
- void openWakePipe();
- void closeWakePipe();
-
- void setCallbackCommon(int fd, int ident, int events, Callback callback,
- ALooper_callbackFunc* looperCallback, void* data);
- ssize_t getRequestIndexLocked(int fd);
- void wakeAndLock();
- static void threadDestructor(void *st);
-};
-
-} // namespace android
-
-#endif // UTILS_POLL_LOOP_H
diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp
index 7eb6da5..c3a9f22 100644
--- a/libs/gui/SensorEventQueue.cpp
+++ b/libs/gui/SensorEventQueue.cpp
@@ -21,7 +21,7 @@
#include <utils/Errors.h>
#include <utils/RefBase.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
#include <gui/Sensor.h>
#include <gui/SensorChannel.h>
@@ -81,28 +81,28 @@ ssize_t SensorEventQueue::read(ASensorEvent* events, size_t numEvents)
return size;
}
-sp<PollLoop> SensorEventQueue::getPollLoop() const
+sp<Looper> SensorEventQueue::getLooper() const
{
Mutex::Autolock _l(mLock);
- if (mPollLoop == 0) {
- mPollLoop = new PollLoop(true);
- mPollLoop->setCallback(getFd(), getFd(), POLLIN, NULL, NULL);
+ if (mLooper == 0) {
+ mLooper = new Looper(true);
+ mLooper->addFd(getFd(), getFd(), ALOOPER_EVENT_INPUT, NULL, NULL);
}
- return mPollLoop;
+ return mLooper;
}
status_t SensorEventQueue::waitForEvent() const
{
const int fd = getFd();
- sp<PollLoop> pollLoop(getPollLoop());
- int32_t result = pollLoop->pollOnce(-1, NULL, NULL);
- return (result == fd) ? NO_ERROR : -1;
+ sp<Looper> looper(getLooper());
+ int32_t result = looper->pollOnce(-1);
+ return (result == fd) ? status_t(NO_ERROR) : status_t(-1);
}
status_t SensorEventQueue::wake() const
{
- sp<PollLoop> pollLoop(getPollLoop());
- pollLoop->wake();
+ sp<Looper> looper(getLooper());
+ looper->wake();
return NO_ERROR;
}
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index cb76091..560ea67 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -32,6 +32,7 @@
#include <ui/DisplayInfo.h>
#include <ui/GraphicBuffer.h>
#include <ui/GraphicBufferMapper.h>
+#include <ui/GraphicLog.h>
#include <ui/Rect.h>
#include <surfaceflinger/Surface.h>
@@ -568,7 +569,13 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer)
if (err != NO_ERROR)
return err;
+ GraphicLog& logger(GraphicLog::getInstance());
+ logger.log(GraphicLog::SF_APP_DEQUEUE_BEFORE, mIdentity, -1);
+
ssize_t bufIdx = mSharedBufferClient->dequeue();
+
+ logger.log(GraphicLog::SF_APP_DEQUEUE_AFTER, mIdentity, bufIdx);
+
if (bufIdx < 0) {
LOGE("error dequeuing a buffer (%s)", strerror(bufIdx));
return bufIdx;
@@ -617,13 +624,20 @@ int Surface::lockBuffer(android_native_buffer_t* buffer)
return err;
int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
+
+ GraphicLog& logger(GraphicLog::getInstance());
+ logger.log(GraphicLog::SF_APP_LOCK_BEFORE, mIdentity, bufIdx);
+
err = mSharedBufferClient->lock(bufIdx);
+
+ logger.log(GraphicLog::SF_APP_LOCK_AFTER, mIdentity, bufIdx);
+
LOGE_IF(err, "error locking buffer %d (%s)", bufIdx, strerror(-err));
return err;
}
int Surface::queueBuffer(android_native_buffer_t* buffer)
-{
+{
status_t err = validate();
if (err != NO_ERROR)
return err;
@@ -633,6 +647,9 @@ int Surface::queueBuffer(android_native_buffer_t* buffer)
}
int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
+
+ GraphicLog::getInstance().log(GraphicLog::SF_APP_QUEUE, mIdentity, bufIdx);
+
mSharedBufferClient->setTransform(bufIdx, mNextBufferTransform);
mSharedBufferClient->setCrop(bufIdx, mNextBufferCrop);
mSharedBufferClient->setDirtyRegion(bufIdx, mDirtyRegion);
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 9f49348..c4a09d6 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -9,6 +9,7 @@ LOCAL_SRC_FILES:= \
GraphicBuffer.cpp \
GraphicBufferAllocator.cpp \
GraphicBufferMapper.cpp \
+ GraphicLog.cpp \
KeyLayoutMap.cpp \
KeyCharacterMap.cpp \
Input.cpp \
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 6f8948d..a36d555 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -29,6 +29,7 @@
#include <ui/Rect.h>
#include <ui/FramebufferNativeWindow.h>
+#include <ui/GraphicLog.h>
#include <EGL/egl.h>
@@ -174,6 +175,14 @@ int FramebufferNativeWindow::setSwapInterval(
return fb->setSwapInterval(fb, interval);
}
+// only for debugging / logging
+int FramebufferNativeWindow::getCurrentBufferIndex() const
+{
+ Mutex::Autolock _l(mutex);
+ const int index = mCurrentBufferIndex;
+ return index;
+}
+
int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window,
android_native_buffer_t** buffer)
{
@@ -181,18 +190,24 @@ int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window,
Mutex::Autolock _l(self->mutex);
framebuffer_device_t* fb = self->fbDev;
+ int index = self->mBufferHead++;
+ if (self->mBufferHead >= self->mNumBuffers)
+ self->mBufferHead = 0;
+
+ GraphicLog& logger(GraphicLog::getInstance());
+ logger.log(GraphicLog::SF_FB_DEQUEUE_BEFORE, index);
+
// wait for a free buffer
while (!self->mNumFreeBuffers) {
self->mCondition.wait(self->mutex);
}
// get this buffer
self->mNumFreeBuffers--;
- int index = self->mBufferHead++;
- if (self->mBufferHead >= self->mNumBuffers)
- self->mBufferHead = 0;
+ self->mCurrentBufferIndex = index;
*buffer = self->buffers[index].get();
+ logger.log(GraphicLog::SF_FB_DEQUEUE_AFTER, index);
return 0;
}
@@ -202,11 +217,17 @@ int FramebufferNativeWindow::lockBuffer(ANativeWindow* window,
FramebufferNativeWindow* self = getSelf(window);
Mutex::Autolock _l(self->mutex);
+ const int index = self->mCurrentBufferIndex;
+ GraphicLog& logger(GraphicLog::getInstance());
+ logger.log(GraphicLog::SF_FB_LOCK_BEFORE, index);
+
// wait that the buffer we're locking is not front anymore
while (self->front == buffer) {
self->mCondition.wait(self->mutex);
}
+ logger.log(GraphicLog::SF_FB_LOCK_AFTER, index);
+
return NO_ERROR;
}
@@ -217,7 +238,15 @@ int FramebufferNativeWindow::queueBuffer(ANativeWindow* window,
Mutex::Autolock _l(self->mutex);
framebuffer_device_t* fb = self->fbDev;
buffer_handle_t handle = static_cast<NativeBuffer*>(buffer)->handle;
+
+ const int index = self->mCurrentBufferIndex;
+ GraphicLog& logger(GraphicLog::getInstance());
+ logger.log(GraphicLog::SF_FB_POST_BEFORE, index);
+
int res = fb->post(fb, handle);
+
+ logger.log(GraphicLog::SF_FB_POST_AFTER, index);
+
self->front = static_cast<NativeBuffer*>(buffer);
self->mNumFreeBuffers++;
self->mCondition.broadcast();
diff --git a/libs/ui/GraphicLog.cpp b/libs/ui/GraphicLog.cpp
new file mode 100644
index 0000000..b55ce23
--- /dev/null
+++ b/libs/ui/GraphicLog.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include <utils/Endian.h>
+#include <utils/Timers.h>
+
+#include <ui/GraphicLog.h>
+
+namespace android {
+
+ANDROID_SINGLETON_STATIC_INSTANCE(GraphicLog)
+
+static inline
+void writeInt32(uint8_t* base, size_t& pos, int32_t value) {
+ int32_t v = htole32(value);
+ base[pos] = EVENT_TYPE_INT;
+ memcpy(&base[pos+1], &v, sizeof(int32_t));
+ pos += 1+sizeof(int32_t);
+}
+
+static inline
+void writeInt64(uint8_t* base, size_t& pos, int64_t value) {
+ int64_t v = htole64(value);
+ base[pos] = EVENT_TYPE_LONG;
+ memcpy(&base[pos+1], &v, sizeof(int64_t));
+ pos += 1+sizeof(int64_t);
+}
+
+void GraphicLog::logImpl(int32_t tag, int32_t buffer)
+{
+ uint8_t scratch[2 + 2 + sizeof(int32_t) + sizeof(int64_t)];
+ size_t pos = 0;
+ scratch[pos++] = EVENT_TYPE_LIST;
+ scratch[pos++] = 2;
+ writeInt32(scratch, pos, buffer);
+ writeInt64(scratch, pos, ns2ms( systemTime( SYSTEM_TIME_MONOTONIC ) ));
+ android_bWriteLog(tag, scratch, sizeof(scratch));
+}
+
+void GraphicLog::logImpl(int32_t tag, int32_t identity, int32_t buffer)
+{
+ uint8_t scratch[2 + 3 + sizeof(int32_t) + sizeof(int32_t) + sizeof(int64_t)];
+ size_t pos = 0;
+ scratch[pos++] = EVENT_TYPE_LIST;
+ scratch[pos++] = 3;
+ writeInt32(scratch, pos, buffer);
+ writeInt32(scratch, pos, identity);
+ writeInt64(scratch, pos, ns2ms( systemTime( SYSTEM_TIME_MONOTONIC ) ));
+ android_bWriteLog(tag, scratch, sizeof(scratch));
+}
+
+GraphicLog::GraphicLog()
+ : mEnabled(0)
+{
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get("debug.graphic_log", property, NULL) > 0) {
+ mEnabled = atoi(property);
+ }
+}
+
+void GraphicLog::setEnabled(bool enable)
+{
+ mEnabled = enable;
+}
+
+}
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index b8a26b0..48dea57 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -95,7 +95,7 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic
mFocusedApplication(NULL),
mCurrentInputTargetsValid(false),
mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
- mPollLoop = new PollLoop(false);
+ mLooper = new Looper(false);
mInboundQueue.headSentinel.refCount = -1;
mInboundQueue.headSentinel.type = EventEntry::TYPE_SENTINEL;
@@ -156,7 +156,7 @@ void InputDispatcher::dispatchOnce() {
timeoutMillis = 0;
}
- mPollLoop->pollOnce(timeoutMillis);
+ mLooper->pollOnce(timeoutMillis);
}
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout,
@@ -1784,7 +1784,7 @@ void InputDispatcher::drainOutboundQueueLocked(Connection* connection,
}
}
-bool InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data) {
+int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data) {
InputDispatcher* d = static_cast<InputDispatcher*>(data);
{ // acquire lock
@@ -1794,24 +1794,24 @@ bool InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* dat
if (connectionIndex < 0) {
LOGE("Received spurious receive callback for unknown input channel. "
"fd=%d, events=0x%x", receiveFd, events);
- return false; // remove the callback
+ return 0; // remove the callback
}
nsecs_t currentTime = now();
sp<Connection> connection = d->mConnectionsByReceiveFd.valueAt(connectionIndex);
- if (events & (POLLERR | POLLHUP | POLLNVAL)) {
+ if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
LOGE("channel '%s' ~ Consumer closed input channel or an error occurred. "
"events=0x%x", connection->getInputChannelName(), events);
d->abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
d->runCommandsLockedInterruptible();
- return false; // remove the callback
+ return 0; // remove the callback
}
- if (! (events & POLLIN)) {
+ if (! (events & ALOOPER_EVENT_INPUT)) {
LOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
"events=0x%x", connection->getInputChannelName(), events);
- return true;
+ return 1;
}
status_t status = connection->inputPublisher.receiveFinishedSignal();
@@ -1820,12 +1820,12 @@ bool InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* dat
connection->getInputChannelName(), status);
d->abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
d->runCommandsLockedInterruptible();
- return false; // remove the callback
+ return 0; // remove the callback
}
d->finishDispatchCycleLocked(currentTime, connection);
d->runCommandsLockedInterruptible();
- return true;
+ return 1;
} // release lock
}
@@ -1843,7 +1843,7 @@ void InputDispatcher::notifyConfigurationChanged(nsecs_t eventTime) {
} // release lock
if (needWake) {
- mPollLoop->wake();
+ mLooper->wake();
}
}
@@ -1870,7 +1870,7 @@ void InputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t sou
} // release lock
if (needWake) {
- mPollLoop->wake();
+ mLooper->wake();
}
}
@@ -2007,7 +2007,7 @@ NoBatchingOrStreaming:;
} // release lock
if (needWake) {
- mPollLoop->wake();
+ mLooper->wake();
}
}
@@ -2043,7 +2043,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
} // release lock
if (needWake) {
- mPollLoop->wake();
+ mLooper->wake();
}
int32_t injectionResult;
@@ -2294,7 +2294,7 @@ void InputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows) {
} // release lock
// Wake up poll loop since it may need to make new input dispatching choices.
- mPollLoop->wake();
+ mLooper->wake();
}
void InputDispatcher::setFocusedApplication(const InputApplication* inputApplication) {
@@ -2317,7 +2317,7 @@ void InputDispatcher::setFocusedApplication(const InputApplication* inputApplica
} // release lock
// Wake up poll loop since it may need to make new input dispatching choices.
- mPollLoop->wake();
+ mLooper->wake();
}
void InputDispatcher::releaseFocusedApplicationLocked() {
@@ -2355,7 +2355,7 @@ void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) {
if (changed) {
// Wake up poll loop since it may need to make new input dispatching choices.
- mPollLoop->wake();
+ mLooper->wake();
}
}
@@ -2372,7 +2372,7 @@ void InputDispatcher::preemptInputDispatch() {
if (preemptedOne) {
// Wake up the poll loop so it can get a head start dispatching the next event.
- mPollLoop->wake();
+ mLooper->wake();
}
}
@@ -2495,7 +2495,7 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan
mMonitoringChannels.push(inputChannel);
}
- mPollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this);
+ mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
runCommandsLockedInterruptible();
} // release lock
@@ -2529,7 +2529,7 @@ status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputCh
}
}
- mPollLoop->removeCallback(inputChannel->getReceivePipeFd());
+ mLooper->removeFd(inputChannel->getReceivePipeFd());
nsecs_t currentTime = now();
abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
@@ -2539,7 +2539,7 @@ status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputCh
// Wake the poll loop because removing the connection may have changed the current
// synchronization state.
- mPollLoop->wake();
+ mLooper->wake();
return OK;
}
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 2e20268..eb75ed8 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -86,7 +86,7 @@ LOCAL_SRC_FILES:= \
$(commonSources) \
BackupData.cpp \
BackupHelpers.cpp \
- PollLoop.cpp
+ Looper.cpp
ifeq ($(TARGET_OS),linux)
LOCAL_LDLIBS += -lrt -ldl
diff --git a/libs/utils/Looper.cpp b/libs/utils/Looper.cpp
new file mode 100644
index 0000000..fd287da
--- /dev/null
+++ b/libs/utils/Looper.cpp
@@ -0,0 +1,368 @@
+//
+// Copyright 2010 The Android Open Source Project
+//
+// A looper implementation based on epoll().
+//
+#define LOG_TAG "Looper"
+
+//#define LOG_NDEBUG 0
+
+// Debugs poll and wake interactions.
+#define DEBUG_POLL_AND_WAKE 0
+
+// Debugs callback registration and invocation.
+#define DEBUG_CALLBACKS 0
+
+#include <cutils/log.h>
+#include <utils/Looper.h>
+#include <utils/Timers.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/epoll.h>
+
+
+namespace android {
+
+static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
+static bool gHaveTLS = false;
+static pthread_key_t gTLS = 0;
+
+// Hint for number of file descriptors to be associated with the epoll instance.
+static const int EPOLL_SIZE_HINT = 8;
+
+// Maximum number of file descriptors for which to retrieve poll events each iteration.
+static const int EPOLL_MAX_EVENTS = 16;
+
+Looper::Looper(bool allowNonCallbacks) :
+ mAllowNonCallbacks(allowNonCallbacks),
+ mResponseIndex(0) {
+ mEpollFd = epoll_create(EPOLL_SIZE_HINT);
+ LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
+
+ int wakeFds[2];
+ int result = pipe(wakeFds);
+ LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
+
+ mWakeReadPipeFd = wakeFds[0];
+ mWakeWritePipeFd = wakeFds[1];
+
+ result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
+ LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
+ errno);
+
+ result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
+ LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
+ errno);
+
+ struct epoll_event eventItem;
+ eventItem.events = EPOLLIN;
+ eventItem.data.fd = mWakeReadPipeFd;
+ result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
+ LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
+ errno);
+}
+
+Looper::~Looper() {
+ close(mWakeReadPipeFd);
+ close(mWakeWritePipeFd);
+ close(mEpollFd);
+}
+
+void Looper::threadDestructor(void *st) {
+ Looper* const self = static_cast<Looper*>(st);
+ if (self != NULL) {
+ self->decStrong((void*)threadDestructor);
+ }
+}
+
+void Looper::setForThread(const sp<Looper>& looper) {
+ sp<Looper> old = getForThread(); // also has side-effect of initializing TLS
+
+ if (looper != NULL) {
+ looper->incStrong((void*)threadDestructor);
+ }
+
+ pthread_setspecific(gTLS, looper.get());
+
+ if (old != NULL) {
+ old->decStrong((void*)threadDestructor);
+ }
+}
+
+sp<Looper> Looper::getForThread() {
+ if (!gHaveTLS) {
+ pthread_mutex_lock(&gTLSMutex);
+ if (pthread_key_create(&gTLS, threadDestructor) != 0) {
+ pthread_mutex_unlock(&gTLSMutex);
+ return NULL;
+ }
+ gHaveTLS = true;
+ pthread_mutex_unlock(&gTLSMutex);
+ }
+
+ return (Looper*)pthread_getspecific(gTLS);
+}
+
+sp<Looper> Looper::prepare(int opts) {
+ bool allowNonCallbacks = opts & ALOOPER_PREPARE_ALLOW_NON_CALLBACKS;
+ sp<Looper> looper = Looper::getForThread();
+ if (looper == NULL) {
+ looper = new Looper(allowNonCallbacks);
+ Looper::setForThread(looper);
+ }
+ if (looper->getAllowNonCallbacks() != allowNonCallbacks) {
+ LOGW("Looper already prepared for this thread with a different value for the "
+ "ALOOPER_PREPARE_ALLOW_NON_CALLBACKS option.");
+ }
+ return looper;
+}
+
+bool Looper::getAllowNonCallbacks() const {
+ return mAllowNonCallbacks;
+}
+
+int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
+ int result = 0;
+ for (;;) {
+ while (mResponseIndex < mResponses.size()) {
+ const Response& response = mResponses.itemAt(mResponseIndex++);
+ if (! response.request.callback) {
+#if DEBUG_POLL_AND_WAKE
+ LOGD("%p ~ pollOnce - returning signalled identifier %d: "
+ "fd=%d, events=0x%x, data=%p", this,
+ response.request.ident, response.request.fd,
+ response.events, response.request.data);
+#endif
+ if (outFd != NULL) *outFd = response.request.fd;
+ if (outEvents != NULL) *outEvents = response.events;
+ if (outData != NULL) *outData = response.request.data;
+ return response.request.ident;
+ }
+ }
+
+ if (result != 0) {
+#if DEBUG_POLL_AND_WAKE
+ LOGD("%p ~ pollOnce - returning result %d", this, result);
+#endif
+ if (outFd != NULL) *outFd = 0;
+ if (outEvents != NULL) *outEvents = NULL;
+ if (outData != NULL) *outData = NULL;
+ return result;
+ }
+
+ result = pollInner(timeoutMillis);
+ }
+}
+
+int Looper::pollInner(int timeoutMillis) {
+#if DEBUG_POLL_AND_WAKE
+ LOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
+#endif
+ struct epoll_event eventItems[EPOLL_MAX_EVENTS];
+ int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
+ if (eventCount < 0) {
+ if (errno != EINTR) {
+ LOGW("Poll failed with an unexpected error, errno=%d", errno);
+ }
+ return ALOOPER_POLL_ERROR;
+ }
+
+ if (eventCount == 0) {
+#if DEBUG_POLL_AND_WAKE
+ LOGD("%p ~ pollOnce - timeout", this);
+#endif
+ return ALOOPER_POLL_TIMEOUT;
+ }
+
+ int result = ALOOPER_POLL_WAKE;
+ mResponses.clear();
+ mResponseIndex = 0;
+
+#if DEBUG_POLL_AND_WAKE
+ LOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);
+#endif
+ { // acquire lock
+ AutoMutex _l(mLock);
+ for (int i = 0; i < eventCount; i++) {
+ int fd = eventItems[i].data.fd;
+ uint32_t epollEvents = eventItems[i].events;
+ if (fd == mWakeReadPipeFd) {
+ if (epollEvents & EPOLLIN) {
+#if DEBUG_POLL_AND_WAKE
+ LOGD("%p ~ pollOnce - awoken", this);
+#endif
+ char buffer[16];
+ ssize_t nRead;
+ do {
+ nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
+ } while (nRead == sizeof(buffer));
+ } else {
+ LOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);
+ }
+ } else {
+ ssize_t requestIndex = mRequests.indexOfKey(fd);
+ if (requestIndex >= 0) {
+ int events = 0;
+ if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT;
+ if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;
+ if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR;
+ if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;
+
+ Response response;
+ response.events = events;
+ response.request = mRequests.valueAt(requestIndex);
+ mResponses.push(response);
+ } else {
+ LOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
+ "no longer registered.", epollEvents, fd);
+ }
+ }
+ }
+ }
+
+ for (size_t i = 0; i < mResponses.size(); i++) {
+ const Response& response = mResponses.itemAt(i);
+ if (response.request.callback) {
+#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
+ LOGD("%p ~ pollOnce - invoking callback: fd=%d, events=0x%x, data=%p", this,
+ response.request.fd, response.events, response.request.data);
+#endif
+ int callbackResult = response.request.callback(
+ response.request.fd, response.events, response.request.data);
+ if (callbackResult == 0) {
+ removeFd(response.request.fd);
+ }
+
+ result = ALOOPER_POLL_CALLBACK;
+ }
+ }
+ return result;
+}
+
+int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
+ if (timeoutMillis <= 0) {
+ int result;
+ do {
+ result = pollOnce(timeoutMillis, outFd, outEvents, outData);
+ } while (result == ALOOPER_POLL_CALLBACK);
+ return result;
+ } else {
+ nsecs_t endTime = systemTime(SYSTEM_TIME_MONOTONIC)
+ + milliseconds_to_nanoseconds(timeoutMillis);
+
+ for (;;) {
+ int result = pollOnce(timeoutMillis, outFd, outEvents, outData);
+ if (result != ALOOPER_POLL_CALLBACK) {
+ return result;
+ }
+
+ nsecs_t timeoutNanos = endTime - systemTime(SYSTEM_TIME_MONOTONIC);
+ if (timeoutNanos <= 0) {
+ return ALOOPER_POLL_TIMEOUT;
+ }
+
+ timeoutMillis = int(nanoseconds_to_milliseconds(timeoutNanos + 999999LL));
+ }
+ }
+}
+
+void Looper::wake() {
+#if DEBUG_POLL_AND_WAKE
+ LOGD("%p ~ wake", this);
+#endif
+
+ ssize_t nWrite = write(mWakeWritePipeFd, "W", 1);
+ if (nWrite != 1) {
+ if (errno != EAGAIN) {
+ LOGW("Could not write wake signal, errno=%d", errno);
+ }
+ }
+}
+
+int Looper::addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data) {
+#if DEBUG_CALLBACKS
+ LOGD("%p ~ addFd - fd=%d, ident=%d, events=0x%x, callback=%p, data=%p", this, fd, ident,
+ events, callback, data);
+#endif
+
+ int epollEvents = 0;
+ if (events & ALOOPER_EVENT_INPUT) epollEvents |= EPOLLIN;
+ if (events & ALOOPER_EVENT_OUTPUT) epollEvents |= EPOLLOUT;
+ if (events & ALOOPER_EVENT_ERROR) epollEvents |= EPOLLERR;
+ if (events & ALOOPER_EVENT_HANGUP) epollEvents |= EPOLLHUP;
+
+ if (epollEvents == 0) {
+ LOGE("Invalid attempt to set a callback with no selected poll events.");
+ return -1;
+ }
+
+ if (! callback) {
+ if (! mAllowNonCallbacks) {
+ LOGE("Invalid attempt to set NULL callback but not allowed for this looper.");
+ return -1;
+ }
+
+ if (ident < 0) {
+ LOGE("Invalid attempt to set NULL callback with ident <= 0.");
+ return -1;
+ }
+ }
+
+ { // acquire lock
+ AutoMutex _l(mLock);
+
+ Request request;
+ request.fd = fd;
+ request.ident = ident;
+ request.callback = callback;
+ request.data = data;
+
+ struct epoll_event eventItem;
+ eventItem.events = epollEvents;
+ eventItem.data.fd = fd;
+
+ ssize_t requestIndex = mRequests.indexOfKey(fd);
+ if (requestIndex < 0) {
+ int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
+ if (epollResult < 0) {
+ LOGE("Error adding epoll events for fd %d, errno=%d", fd, errno);
+ return -1;
+ }
+ mRequests.add(fd, request);
+ } else {
+ int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
+ if (epollResult < 0) {
+ LOGE("Error modifying epoll events for fd %d, errno=%d", fd, errno);
+ return -1;
+ }
+ mRequests.replaceValueAt(requestIndex, request);
+ }
+ } // release lock
+ return 1;
+}
+
+int Looper::removeFd(int fd) {
+#if DEBUG_CALLBACKS
+ LOGD("%p ~ removeFd - fd=%d", this, fd);
+#endif
+
+ { // acquire lock
+ AutoMutex _l(mLock);
+ ssize_t requestIndex = mRequests.indexOfKey(fd);
+ if (requestIndex < 0) {
+ return 0;
+ }
+
+ int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL);
+ if (epollResult < 0) {
+ LOGE("Error removing epoll events for fd %d, errno=%d", fd, errno);
+ return -1;
+ }
+
+ mRequests.removeItemsAt(requestIndex);
+ } // request lock
+ return 1;
+}
+
+} // namespace android
diff --git a/libs/utils/PollLoop.cpp b/libs/utils/PollLoop.cpp
deleted file mode 100644
index fe76cd0..0000000
--- a/libs/utils/PollLoop.cpp
+++ /dev/null
@@ -1,377 +0,0 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
-// A select loop implementation.
-//
-#define LOG_TAG "PollLoop"
-
-//#define LOG_NDEBUG 0
-
-// Debugs poll and wake interactions.
-#define DEBUG_POLL_AND_WAKE 0
-
-// Debugs callback registration and invocation.
-#define DEBUG_CALLBACKS 0
-
-#include <cutils/log.h>
-#include <utils/PollLoop.h>
-
-#include <unistd.h>
-#include <fcntl.h>
-
-namespace android {
-
-static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
-static bool gHaveTLS = false;
-static pthread_key_t gTLS = 0;
-
-PollLoop::PollLoop(bool allowNonCallbacks) :
- mAllowNonCallbacks(allowNonCallbacks), mPolling(false),
- mWaiters(0), mPendingFdsPos(0) {
- openWakePipe();
-}
-
-PollLoop::~PollLoop() {
- closeWakePipe();
-}
-
-void PollLoop::threadDestructor(void *st) {
- PollLoop* const self = static_cast<PollLoop*>(st);
- if (self != NULL) {
- self->decStrong((void*)threadDestructor);
- }
-}
-
-void PollLoop::setForThread(const sp<PollLoop>& pollLoop) {
- sp<PollLoop> old = getForThread();
-
- if (pollLoop != NULL) {
- pollLoop->incStrong((void*)threadDestructor);
- }
-
- pthread_setspecific(gTLS, pollLoop.get());
-
- if (old != NULL) {
- old->decStrong((void*)threadDestructor);
- }
-}
-
-sp<PollLoop> PollLoop::getForThread() {
- if (!gHaveTLS) {
- pthread_mutex_lock(&gTLSMutex);
- if (pthread_key_create(&gTLS, threadDestructor) != 0) {
- pthread_mutex_unlock(&gTLSMutex);
- return NULL;
- }
- gHaveTLS = true;
- pthread_mutex_unlock(&gTLSMutex);
- }
-
- return (PollLoop*)pthread_getspecific(gTLS);
-}
-
-void PollLoop::openWakePipe() {
- int wakeFds[2];
- int result = pipe(wakeFds);
- LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
-
- mWakeReadPipeFd = wakeFds[0];
- mWakeWritePipeFd = wakeFds[1];
-
- result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
- LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
- errno);
-
- result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
- LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
- errno);
-
- // Add the wake pipe to the head of the request list with a null callback.
- struct pollfd requestedFd;
- requestedFd.fd = mWakeReadPipeFd;
- requestedFd.events = POLLIN;
- mRequestedFds.insertAt(requestedFd, 0);
-
- RequestedCallback requestedCallback;
- requestedCallback.callback = NULL;
- requestedCallback.looperCallback = NULL;
- requestedCallback.ident = 0;
- requestedCallback.data = NULL;
- mRequestedCallbacks.insertAt(requestedCallback, 0);
-}
-
-void PollLoop::closeWakePipe() {
- close(mWakeReadPipeFd);
- close(mWakeWritePipeFd);
-
- // Note: We don't need to remove the poll structure or callback entry because this
- // method is currently only called by the destructor.
-}
-
-int32_t PollLoop::pollOnce(int timeoutMillis, int* outEvents, void** outData) {
- // If there are still pending fds from the last call, dispatch those
- // first, to avoid an earlier fd from starving later ones.
- const size_t pendingFdsCount = mPendingFds.size();
- if (mPendingFdsPos < pendingFdsCount) {
- const PendingCallback& pending = mPendingFds.itemAt(mPendingFdsPos);
- mPendingFdsPos++;
- if (outEvents != NULL) *outEvents = pending.events;
- if (outData != NULL) *outData = pending.data;
- return pending.ident;
- }
-
- // Wait for wakeAndLock() waiters to run then set mPolling to true.
- mLock.lock();
- while (mWaiters != 0) {
- mResume.wait(mLock);
- }
- mPolling = true;
- mLock.unlock();
-
- // Poll.
- int32_t result;
- size_t requestedCount = mRequestedFds.size();
-
-#if DEBUG_POLL_AND_WAKE
- LOGD("%p ~ pollOnce - waiting on %d fds", this, requestedCount);
- for (size_t i = 0; i < requestedCount; i++) {
- LOGD(" fd %d - events %d", mRequestedFds[i].fd, mRequestedFds[i].events);
- }
-#endif
-
- int respondedCount = poll(mRequestedFds.editArray(), requestedCount, timeoutMillis);
-
- if (respondedCount == 0) {
- // Timeout
-#if DEBUG_POLL_AND_WAKE
- LOGD("%p ~ pollOnce - timeout", this);
-#endif
- result = POLL_TIMEOUT;
- goto Done;
- }
-
- if (respondedCount < 0) {
- // Error
-#if DEBUG_POLL_AND_WAKE
- LOGD("%p ~ pollOnce - error, errno=%d", this, errno);
-#endif
- if (errno != EINTR) {
- LOGW("Poll failed with an unexpected error, errno=%d", errno);
- }
- result = POLL_ERROR;
- goto Done;
- }
-
-#if DEBUG_POLL_AND_WAKE
- LOGD("%p ~ pollOnce - handling responses from %d fds", this, respondedCount);
- for (size_t i = 0; i < requestedCount; i++) {
- LOGD(" fd %d - events %d, revents %d", mRequestedFds[i].fd, mRequestedFds[i].events,
- mRequestedFds[i].revents);
- }
-#endif
-
- // Process the poll results.
- mPendingCallbacks.clear();
- mPendingFds.clear();
- mPendingFdsPos = 0;
- if (outEvents != NULL) *outEvents = 0;
- if (outData != NULL) *outData = NULL;
-
- result = POLL_CALLBACK;
- for (size_t i = 0; i < requestedCount; i++) {
- const struct pollfd& requestedFd = mRequestedFds.itemAt(i);
-
- short revents = requestedFd.revents;
- if (revents) {
- const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
- PendingCallback pending;
- pending.fd = requestedFd.fd;
- pending.ident = requestedCallback.ident;
- pending.events = revents;
- pending.callback = requestedCallback.callback;
- pending.looperCallback = requestedCallback.looperCallback;
- pending.data = requestedCallback.data;
-
- if (pending.callback || pending.looperCallback) {
- mPendingCallbacks.push(pending);
- } else if (pending.fd != mWakeReadPipeFd) {
- if (result == POLL_CALLBACK) {
- result = pending.ident;
- if (outEvents != NULL) *outEvents = pending.events;
- if (outData != NULL) *outData = pending.data;
- } else {
- mPendingFds.push(pending);
- }
- } else {
-#if DEBUG_POLL_AND_WAKE
- LOGD("%p ~ pollOnce - awoken", this);
-#endif
- char buffer[16];
- ssize_t nRead;
- do {
- nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
- } while (nRead == sizeof(buffer));
- }
-
- respondedCount -= 1;
- if (respondedCount == 0) {
- break;
- }
- }
- }
-
-Done:
- // Set mPolling to false and wake up the wakeAndLock() waiters.
- mLock.lock();
- mPolling = false;
- if (mWaiters != 0) {
- mAwake.broadcast();
- }
- mLock.unlock();
-
- if (result == POLL_CALLBACK || result >= 0) {
- size_t pendingCount = mPendingCallbacks.size();
- for (size_t i = 0; i < pendingCount; i++) {
- const PendingCallback& pendingCallback = mPendingCallbacks.itemAt(i);
-#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
- LOGD("%p ~ pollOnce - invoking callback for fd %d", this, pendingCallback.fd);
-#endif
-
- bool keep = true;
- if (pendingCallback.callback != NULL) {
- keep = pendingCallback.callback(pendingCallback.fd, pendingCallback.events,
- pendingCallback.data);
- } else {
- keep = pendingCallback.looperCallback(pendingCallback.fd, pendingCallback.events,
- pendingCallback.data) != 0;
- }
- if (! keep) {
- removeCallback(pendingCallback.fd);
- }
- }
- }
-
-#if DEBUG_POLL_AND_WAKE
- LOGD("%p ~ pollOnce - done", this);
-#endif
- return result;
-}
-
-void PollLoop::wake() {
-#if DEBUG_POLL_AND_WAKE
- LOGD("%p ~ wake", this);
-#endif
-
- ssize_t nWrite = write(mWakeWritePipeFd, "W", 1);
- if (nWrite != 1) {
- if (errno != EAGAIN) {
- LOGW("Could not write wake signal, errno=%d", errno);
- }
- }
-}
-
-bool PollLoop::getAllowNonCallbacks() const {
- return mAllowNonCallbacks;
-}
-
-void PollLoop::setCallback(int fd, int ident, int events, Callback callback, void* data) {
- setCallbackCommon(fd, ident, events, callback, NULL, data);
-}
-
-void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {
- setCallbackCommon(fd, POLL_CALLBACK, events, callback, NULL, data);
-}
-
-void PollLoop::setLooperCallback(int fd, int ident, int events, ALooper_callbackFunc* callback,
- void* data) {
- setCallbackCommon(fd, ident, events, NULL, callback, data);
-}
-
-void PollLoop::setCallbackCommon(int fd, int ident, int events, Callback callback,
- ALooper_callbackFunc* looperCallback, void* data) {
-
-#if DEBUG_CALLBACKS
- LOGD("%p ~ setCallback - fd=%d, events=%d", this, fd, events);
-#endif
-
- if (! events) {
- LOGE("Invalid attempt to set a callback with no selected poll events.");
- removeCallback(fd);
- return;
- }
-
- if (! callback && ! looperCallback && ! mAllowNonCallbacks) {
- LOGE("Invalid attempt to set NULL callback but not allowed.");
- removeCallback(fd);
- return;
- }
-
- wakeAndLock();
-
- struct pollfd requestedFd;
- requestedFd.fd = fd;
- requestedFd.events = events;
-
- RequestedCallback requestedCallback;
- requestedCallback.callback = callback;
- requestedCallback.looperCallback = looperCallback;
- requestedCallback.ident = ident;
- requestedCallback.data = data;
-
- ssize_t index = getRequestIndexLocked(fd);
- if (index < 0) {
- mRequestedFds.push(requestedFd);
- mRequestedCallbacks.push(requestedCallback);
- } else {
- mRequestedFds.replaceAt(requestedFd, size_t(index));
- mRequestedCallbacks.replaceAt(requestedCallback, size_t(index));
- }
-
- mLock.unlock();
-}
-
-bool PollLoop::removeCallback(int fd) {
-#if DEBUG_CALLBACKS
- LOGD("%p ~ removeCallback - fd=%d", this, fd);
-#endif
-
- wakeAndLock();
-
- ssize_t index = getRequestIndexLocked(fd);
- if (index >= 0) {
- mRequestedFds.removeAt(size_t(index));
- mRequestedCallbacks.removeAt(size_t(index));
- }
-
- mLock.unlock();
- return index >= 0;
-}
-
-ssize_t PollLoop::getRequestIndexLocked(int fd) {
- size_t requestCount = mRequestedFds.size();
-
- for (size_t i = 0; i < requestCount; i++) {
- if (mRequestedFds.itemAt(i).fd == fd) {
- return i;
- }
- }
-
- return -1;
-}
-
-void PollLoop::wakeAndLock() {
- mLock.lock();
-
- mWaiters += 1;
- while (mPolling) {
- wake();
- mAwake.wait(mLock);
- }
-
- mWaiters -= 1;
- if (mWaiters == 0) {
- mResume.signal();
- }
-}
-
-} // namespace android
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index 725de9c..00077ee 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -7,7 +7,7 @@ ifneq ($(TARGET_SIMULATOR),true)
# Build the unit tests.
test_src_files := \
ObbFile_test.cpp \
- PollLoop_test.cpp \
+ Looper_test.cpp \
String8_test.cpp
shared_libraries := \
diff --git a/libs/utils/tests/Looper_test.cpp b/libs/utils/tests/Looper_test.cpp
new file mode 100644
index 0000000..afc92f8
--- /dev/null
+++ b/libs/utils/tests/Looper_test.cpp
@@ -0,0 +1,433 @@
+//
+// Copyright 2010 The Android Open Source Project
+//
+
+#include <utils/Looper.h>
+#include <utils/Timers.h>
+#include <utils/StopWatch.h>
+#include <gtest/gtest.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "TestHelpers.h"
+
+// # of milliseconds to fudge stopwatch measurements
+#define TIMING_TOLERANCE_MS 25
+
+namespace android {
+
+class DelayedWake : public DelayedTask {
+ sp<Looper> mLooper;
+
+public:
+ DelayedWake(int delayMillis, const sp<Looper> looper) :
+ DelayedTask(delayMillis), mLooper(looper) {
+ }
+
+protected:
+ virtual void doTask() {
+ mLooper->wake();
+ }
+};
+
+class DelayedWriteSignal : public DelayedTask {
+ Pipe* mPipe;
+
+public:
+ DelayedWriteSignal(int delayMillis, Pipe* pipe) :
+ DelayedTask(delayMillis), mPipe(pipe) {
+ }
+
+protected:
+ virtual void doTask() {
+ mPipe->writeSignal();
+ }
+};
+
+class CallbackHandler {
+public:
+ void setCallback(const sp<Looper>& looper, int fd, int events) {
+ looper->addFd(fd, 0, events, staticHandler, this);
+ }
+
+protected:
+ virtual ~CallbackHandler() { }
+
+ virtual int handler(int fd, int events) = 0;
+
+private:
+ static int staticHandler(int fd, int events, void* data) {
+ return static_cast<CallbackHandler*>(data)->handler(fd, events);
+ }
+};
+
+class StubCallbackHandler : public CallbackHandler {
+public:
+ int nextResult;
+ int callbackCount;
+
+ int fd;
+ int events;
+
+ StubCallbackHandler(int nextResult) : nextResult(nextResult),
+ callbackCount(0), fd(-1), events(-1) {
+ }
+
+protected:
+ virtual int handler(int fd, int events) {
+ callbackCount += 1;
+ this->fd = fd;
+ this->events = events;
+ return nextResult;
+ }
+};
+
+class LooperTest : public testing::Test {
+protected:
+ sp<Looper> mLooper;
+
+ virtual void SetUp() {
+ mLooper = new Looper(true);
+ }
+
+ virtual void TearDown() {
+ mLooper.clear();
+ }
+};
+
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndNotAwoken_WaitsForTimeout) {
+ StopWatch stopWatch("pollOnce");
+ int result = mLooper->pollOnce(100);
+ int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+ EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+ << "elapsed time should approx. equal timeout";
+ EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+ << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndAwokenBeforeWaiting_ImmediatelyReturns) {
+ mLooper->wake();
+
+ StopWatch stopWatch("pollOnce");
+ int result = mLooper->pollOnce(1000);
+ int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+ EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+ << "elapsed time should approx. zero because wake() was called before waiting";
+ EXPECT_EQ(ALOOPER_POLL_WAKE, result)
+ << "pollOnce result should be ALOOPER_POLL_CALLBACK because loop was awoken";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndAwokenWhileWaiting_PromptlyReturns) {
+ sp<DelayedWake> delayedWake = new DelayedWake(100, mLooper);
+ delayedWake->run();
+
+ StopWatch stopWatch("pollOnce");
+ int result = mLooper->pollOnce(1000);
+ int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+ EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+ << "elapsed time should approx. equal wake delay";
+ EXPECT_EQ(ALOOPER_POLL_WAKE, result)
+ << "pollOnce result should be ALOOPER_POLL_CALLBACK because loop was awoken";
+}
+
+TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndNoRegisteredFDs_ImmediatelyReturns) {
+ StopWatch stopWatch("pollOnce");
+ int result = mLooper->pollOnce(0);
+ int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+ EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+ << "elapsed time should be approx. zero";
+ EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+ << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+}
+
+TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndNoSignalledFDs_ImmediatelyReturns) {
+ Pipe pipe;
+ StubCallbackHandler handler(true);
+
+ handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+ StopWatch stopWatch("pollOnce");
+ int result = mLooper->pollOnce(0);
+ int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+ EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+ << "elapsed time should be approx. zero";
+ EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+ << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+ EXPECT_EQ(0, handler.callbackCount)
+ << "callback should not have been invoked because FD was not signalled";
+}
+
+TEST_F(LooperTest, PollOnce_WhenZeroTimeoutAndSignalledFD_ImmediatelyInvokesCallbackAndReturns) {
+ Pipe pipe;
+ StubCallbackHandler handler(true);
+
+ ASSERT_EQ(OK, pipe.writeSignal());
+ handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+ StopWatch stopWatch("pollOnce");
+ int result = mLooper->pollOnce(0);
+ int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+ EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+ << "elapsed time should be approx. zero";
+ EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+ << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
+ EXPECT_EQ(1, handler.callbackCount)
+ << "callback should be invoked exactly once";
+ EXPECT_EQ(pipe.receiveFd, handler.fd)
+ << "callback should have received pipe fd as parameter";
+ EXPECT_EQ(ALOOPER_EVENT_INPUT, handler.events)
+ << "callback should have received ALOOPER_EVENT_INPUT as events";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndNoSignalledFDs_WaitsForTimeoutAndReturns) {
+ Pipe pipe;
+ StubCallbackHandler handler(true);
+
+ handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+ StopWatch stopWatch("pollOnce");
+ int result = mLooper->pollOnce(100);
+ int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+ EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+ << "elapsed time should approx. equal timeout";
+ EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+ << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+ EXPECT_EQ(0, handler.callbackCount)
+ << "callback should not have been invoked because FD was not signalled";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDBeforeWaiting_ImmediatelyInvokesCallbackAndReturns) {
+ Pipe pipe;
+ StubCallbackHandler handler(true);
+
+ pipe.writeSignal();
+ handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+ StopWatch stopWatch("pollOnce");
+ int result = mLooper->pollOnce(100);
+ int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+ ASSERT_EQ(OK, pipe.readSignal())
+ << "signal should actually have been written";
+ EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+ << "elapsed time should be approx. zero";
+ EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+ << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
+ EXPECT_EQ(1, handler.callbackCount)
+ << "callback should be invoked exactly once";
+ EXPECT_EQ(pipe.receiveFd, handler.fd)
+ << "callback should have received pipe fd as parameter";
+ EXPECT_EQ(ALOOPER_EVENT_INPUT, handler.events)
+ << "callback should have received ALOOPER_EVENT_INPUT as events";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDWhileWaiting_PromptlyInvokesCallbackAndReturns) {
+ Pipe pipe;
+ StubCallbackHandler handler(true);
+ sp<DelayedWriteSignal> delayedWriteSignal = new DelayedWriteSignal(100, & pipe);
+
+ handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+ delayedWriteSignal->run();
+
+ StopWatch stopWatch("pollOnce");
+ int result = mLooper->pollOnce(1000);
+ int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+ ASSERT_EQ(OK, pipe.readSignal())
+ << "signal should actually have been written";
+ EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+ << "elapsed time should approx. equal signal delay";
+ EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+ << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
+ EXPECT_EQ(1, handler.callbackCount)
+ << "callback should be invoked exactly once";
+ EXPECT_EQ(pipe.receiveFd, handler.fd)
+ << "callback should have received pipe fd as parameter";
+ EXPECT_EQ(ALOOPER_EVENT_INPUT, handler.events)
+ << "callback should have received ALOOPER_EVENT_INPUT as events";
+}
+
+TEST_F(LooperTest, PollOnce_WhenCallbackAddedThenRemoved_CallbackShouldNotBeInvoked) {
+ Pipe pipe;
+ StubCallbackHandler handler(true);
+
+ handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+ pipe.writeSignal(); // would cause FD to be considered signalled
+ mLooper->removeFd(pipe.receiveFd);
+
+ StopWatch stopWatch("pollOnce");
+ int result = mLooper->pollOnce(100);
+ int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+ ASSERT_EQ(OK, pipe.readSignal())
+ << "signal should actually have been written";
+ EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+ << "elapsed time should approx. equal timeout because FD was no longer registered";
+ EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+ << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+ EXPECT_EQ(0, handler.callbackCount)
+ << "callback should not be invoked";
+}
+
+TEST_F(LooperTest, PollOnce_WhenCallbackReturnsFalse_CallbackShouldNotBeInvokedAgainLater) {
+ Pipe pipe;
+ StubCallbackHandler handler(false);
+
+ handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+ // First loop: Callback is registered and FD is signalled.
+ pipe.writeSignal();
+
+ StopWatch stopWatch("pollOnce");
+ int result = mLooper->pollOnce(0);
+ int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+ ASSERT_EQ(OK, pipe.readSignal())
+ << "signal should actually have been written";
+ EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+ << "elapsed time should approx. equal zero because FD was already signalled";
+ EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+ << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
+ EXPECT_EQ(1, handler.callbackCount)
+ << "callback should be invoked";
+
+ // Second loop: Callback is no longer registered and FD is signalled.
+ pipe.writeSignal();
+
+ stopWatch.reset();
+ result = mLooper->pollOnce(0);
+ elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+ ASSERT_EQ(OK, pipe.readSignal())
+ << "signal should actually have been written";
+ EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+ << "elapsed time should approx. equal zero because timeout was zero";
+ EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+ << "pollOnce result should be ALOOPER_POLL_TIMEOUT";
+ EXPECT_EQ(1, handler.callbackCount)
+ << "callback should not be invoked this time";
+}
+
+TEST_F(LooperTest, PollOnce_WhenNonCallbackFdIsSignalled_ReturnsIdent) {
+ const int expectedIdent = 5;
+ void* expectedData = this;
+
+ Pipe pipe;
+
+ pipe.writeSignal();
+ mLooper->addFd(pipe.receiveFd, expectedIdent, ALOOPER_EVENT_INPUT, NULL, expectedData);
+
+ StopWatch stopWatch("pollOnce");
+ int fd;
+ int events;
+ void* data;
+ int result = mLooper->pollOnce(100, &fd, &events, &data);
+ int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+ ASSERT_EQ(OK, pipe.readSignal())
+ << "signal should actually have been written";
+ EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+ << "elapsed time should be approx. zero";
+ EXPECT_EQ(expectedIdent, result)
+ << "pollOnce result should be the ident of the FD that was signalled";
+ EXPECT_EQ(pipe.receiveFd, fd)
+ << "pollOnce should have returned the received pipe fd";
+ EXPECT_EQ(ALOOPER_EVENT_INPUT, events)
+ << "pollOnce should have returned ALOOPER_EVENT_INPUT as events";
+ EXPECT_EQ(expectedData, data)
+ << "pollOnce should have returned the data";
+}
+
+TEST_F(LooperTest, AddFd_WhenCallbackAdded_ReturnsOne) {
+ Pipe pipe;
+ int result = mLooper->addFd(pipe.receiveFd, 0, ALOOPER_EVENT_INPUT, NULL, NULL);
+
+ EXPECT_EQ(1, result)
+ << "addFd should return 1 because FD was added";
+}
+
+TEST_F(LooperTest, AddFd_WhenEventsIsZero_ReturnsError) {
+ Pipe pipe;
+ int result = mLooper->addFd(pipe.receiveFd, 0, 0, NULL, NULL);
+
+ EXPECT_EQ(-1, result)
+ << "addFd should return -1 because arguments were invalid";
+}
+
+TEST_F(LooperTest, AddFd_WhenIdentIsNegativeAndCallbackIsNull_ReturnsError) {
+ Pipe pipe;
+ int result = mLooper->addFd(pipe.receiveFd, -1, ALOOPER_EVENT_INPUT, NULL, NULL);
+
+ EXPECT_EQ(-1, result)
+ << "addFd should return -1 because arguments were invalid";
+}
+
+TEST_F(LooperTest, AddFd_WhenNoCallbackAndAllowNonCallbacksIsFalse_ReturnsError) {
+ Pipe pipe;
+ sp<Looper> looper = new Looper(false /*allowNonCallbacks*/);
+ int result = looper->addFd(pipe.receiveFd, 0, 0, NULL, NULL);
+
+ EXPECT_EQ(-1, result)
+ << "addFd should return -1 because arguments were invalid";
+}
+
+TEST_F(LooperTest, RemoveFd_WhenCallbackNotAdded_ReturnsZero) {
+ int result = mLooper->removeFd(1);
+
+ EXPECT_EQ(0, result)
+ << "removeFd should return 0 because FD not registered";
+}
+
+TEST_F(LooperTest, RemoveFd_WhenCallbackAddedThenRemovedTwice_ReturnsOnceFirstTimeAndReturnsZeroSecondTime) {
+ Pipe pipe;
+ StubCallbackHandler handler(false);
+ handler.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+
+ // First time.
+ int result = mLooper->removeFd(pipe.receiveFd);
+
+ EXPECT_EQ(1, result)
+ << "removeFd should return 1 first time because FD was registered";
+
+ // Second time.
+ result = mLooper->removeFd(pipe.receiveFd);
+
+ EXPECT_EQ(0, result)
+ << "removeFd should return 0 second time because FD was no longer registered";
+}
+
+TEST_F(LooperTest, PollOnce_WhenCallbackAddedTwice_OnlySecondCallbackShouldBeInvoked) {
+ Pipe pipe;
+ StubCallbackHandler handler1(true);
+ StubCallbackHandler handler2(true);
+
+ handler1.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT);
+ handler2.setCallback(mLooper, pipe.receiveFd, ALOOPER_EVENT_INPUT); // replace it
+ pipe.writeSignal(); // would cause FD to be considered signalled
+
+ StopWatch stopWatch("pollOnce");
+ int result = mLooper->pollOnce(100);
+ int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+ ASSERT_EQ(OK, pipe.readSignal())
+ << "signal should actually have been written";
+ EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+ << "elapsed time should approx. zero because FD was already signalled";
+ EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+ << "pollOnce result should be ALOOPER_POLL_CALLBACK because FD was signalled";
+ EXPECT_EQ(0, handler1.callbackCount)
+ << "original handler callback should not be invoked because it was replaced";
+ EXPECT_EQ(1, handler2.callbackCount)
+ << "replacement handler callback should be invoked";
+}
+
+
+} // namespace android
diff --git a/libs/utils/tests/PollLoop_test.cpp b/libs/utils/tests/PollLoop_test.cpp
deleted file mode 100644
index 02f1808..0000000
--- a/libs/utils/tests/PollLoop_test.cpp
+++ /dev/null
@@ -1,370 +0,0 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
-
-#include <utils/PollLoop.h>
-#include <utils/Timers.h>
-#include <utils/StopWatch.h>
-#include <gtest/gtest.h>
-#include <unistd.h>
-#include <time.h>
-
-#include "TestHelpers.h"
-
-// # of milliseconds to fudge stopwatch measurements
-#define TIMING_TOLERANCE_MS 25
-
-namespace android {
-
-class DelayedWake : public DelayedTask {
- sp<PollLoop> mPollLoop;
-
-public:
- DelayedWake(int delayMillis, const sp<PollLoop> pollLoop) :
- DelayedTask(delayMillis), mPollLoop(pollLoop) {
- }
-
-protected:
- virtual void doTask() {
- mPollLoop->wake();
- }
-};
-
-class DelayedWriteSignal : public DelayedTask {
- Pipe* mPipe;
-
-public:
- DelayedWriteSignal(int delayMillis, Pipe* pipe) :
- DelayedTask(delayMillis), mPipe(pipe) {
- }
-
-protected:
- virtual void doTask() {
- mPipe->writeSignal();
- }
-};
-
-class CallbackHandler {
-public:
- void setCallback(const sp<PollLoop>& pollLoop, int fd, int events) {
- pollLoop->setCallback(fd, events, staticHandler, this);
- }
-
-protected:
- virtual ~CallbackHandler() { }
-
- virtual bool handler(int fd, int events) = 0;
-
-private:
- static bool staticHandler(int fd, int events, void* data) {
- return static_cast<CallbackHandler*>(data)->handler(fd, events);
- }
-};
-
-class StubCallbackHandler : public CallbackHandler {
-public:
- bool nextResult;
- int callbackCount;
-
- int fd;
- int events;
-
- StubCallbackHandler(bool nextResult) : nextResult(nextResult),
- callbackCount(0), fd(-1), events(-1) {
- }
-
-protected:
- virtual bool handler(int fd, int events) {
- callbackCount += 1;
- this->fd = fd;
- this->events = events;
- return nextResult;
- }
-};
-
-class PollLoopTest : public testing::Test {
-protected:
- sp<PollLoop> mPollLoop;
-
- virtual void SetUp() {
- mPollLoop = new PollLoop(false);
- }
-
- virtual void TearDown() {
- mPollLoop.clear();
- }
-};
-
-
-TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndNotAwoken_WaitsForTimeoutAndReturnsFalse) {
- StopWatch stopWatch("pollOnce");
- int32_t result = mPollLoop->pollOnce(100);
- int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
- EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
- << "elapsed time should approx. equal timeout";
- EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
- << "pollOnce result should be POLL_TIMEOUT";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndAwokenBeforeWaiting_ImmediatelyReturnsTrue) {
- mPollLoop->wake();
-
- StopWatch stopWatch("pollOnce");
- int32_t result = mPollLoop->pollOnce(1000);
- int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
- EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
- << "elapsed time should approx. zero because wake() was called before waiting";
- EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
- << "pollOnce result should be POLL_CALLBACK because loop was awoken";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndAwokenWhileWaiting_PromptlyReturnsTrue) {
- sp<DelayedWake> delayedWake = new DelayedWake(100, mPollLoop);
- delayedWake->run();
-
- StopWatch stopWatch("pollOnce");
- int32_t result = mPollLoop->pollOnce(1000);
- int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
- EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
- << "elapsed time should approx. equal wake delay";
- EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
- << "pollOnce result should be POLL_CALLBACK because loop was awoken";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndNoRegisteredFDs_ImmediatelyReturnsFalse) {
- StopWatch stopWatch("pollOnce");
- int32_t result = mPollLoop->pollOnce(0);
- int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
- EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
- << "elapsed time should be approx. zero";
- EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
- << "pollOnce result should be POLL_TIMEOUT";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndNoSignalledFDs_ImmediatelyReturnsFalse) {
- Pipe pipe;
- StubCallbackHandler handler(true);
-
- handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-
- StopWatch stopWatch("pollOnce");
- int32_t result = mPollLoop->pollOnce(0);
- int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
- EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
- << "elapsed time should be approx. zero";
- EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
- << "pollOnce result should be POLL_TIMEOUT";
- EXPECT_EQ(0, handler.callbackCount)
- << "callback should not have been invoked because FD was not signalled";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndSignalledFD_ImmediatelyInvokesCallbackAndReturnsTrue) {
- Pipe pipe;
- StubCallbackHandler handler(true);
-
- ASSERT_EQ(OK, pipe.writeSignal());
- handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-
- StopWatch stopWatch("pollOnce");
- int32_t result = mPollLoop->pollOnce(0);
- int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
- EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
- << "elapsed time should be approx. zero";
- EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
- << "pollOnce result should be POLL_CALLBACK because FD was signalled";
- EXPECT_EQ(1, handler.callbackCount)
- << "callback should be invoked exactly once";
- EXPECT_EQ(pipe.receiveFd, handler.fd)
- << "callback should have received pipe fd as parameter";
- EXPECT_EQ(POLL_IN, handler.events)
- << "callback should have received POLL_IN as events";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndNoSignalledFDs_WaitsForTimeoutAndReturnsFalse) {
- Pipe pipe;
- StubCallbackHandler handler(true);
-
- handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-
- StopWatch stopWatch("pollOnce");
- int32_t result = mPollLoop->pollOnce(100);
- int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
- EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
- << "elapsed time should approx. equal timeout";
- EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
- << "pollOnce result should be POLL_TIMEOUT";
- EXPECT_EQ(0, handler.callbackCount)
- << "callback should not have been invoked because FD was not signalled";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDBeforeWaiting_ImmediatelyInvokesCallbackAndReturnsTrue) {
- Pipe pipe;
- StubCallbackHandler handler(true);
-
- pipe.writeSignal();
- handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-
- StopWatch stopWatch("pollOnce");
- int32_t result = mPollLoop->pollOnce(100);
- int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
- ASSERT_EQ(OK, pipe.readSignal())
- << "signal should actually have been written";
- EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
- << "elapsed time should be approx. zero";
- EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
- << "pollOnce result should be POLL_CALLBACK because FD was signalled";
- EXPECT_EQ(1, handler.callbackCount)
- << "callback should be invoked exactly once";
- EXPECT_EQ(pipe.receiveFd, handler.fd)
- << "callback should have received pipe fd as parameter";
- EXPECT_EQ(POLL_IN, handler.events)
- << "callback should have received POLL_IN as events";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndSignalledFDWhileWaiting_PromptlyInvokesCallbackAndReturnsTrue) {
- Pipe pipe;
- StubCallbackHandler handler(true);
- sp<DelayedWriteSignal> delayedWriteSignal = new DelayedWriteSignal(100, & pipe);
-
- handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
- delayedWriteSignal->run();
-
- StopWatch stopWatch("pollOnce");
- int32_t result = mPollLoop->pollOnce(1000);
- int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
- ASSERT_EQ(OK, pipe.readSignal())
- << "signal should actually have been written";
- EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
- << "elapsed time should approx. equal signal delay";
- EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
- << "pollOnce result should be POLL_CALLBACK because FD was signalled";
- EXPECT_EQ(1, handler.callbackCount)
- << "callback should be invoked exactly once";
- EXPECT_EQ(pipe.receiveFd, handler.fd)
- << "callback should have received pipe fd as parameter";
- EXPECT_EQ(POLL_IN, handler.events)
- << "callback should have received POLL_IN as events";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenCallbackAddedThenRemoved_CallbackShouldNotBeInvoked) {
- Pipe pipe;
- StubCallbackHandler handler(true);
-
- handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
- pipe.writeSignal(); // would cause FD to be considered signalled
- mPollLoop->removeCallback(pipe.receiveFd);
-
- StopWatch stopWatch("pollOnce");
- int32_t result = mPollLoop->pollOnce(100);
- int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
- ASSERT_EQ(OK, pipe.readSignal())
- << "signal should actually have been written";
- EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
- << "elapsed time should approx. equal timeout because FD was no longer registered";
- EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
- << "pollOnce result should be POLL_TIMEOUT";
- EXPECT_EQ(0, handler.callbackCount)
- << "callback should not be invoked";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenCallbackReturnsFalse_CallbackShouldNotBeInvokedAgainLater) {
- Pipe pipe;
- StubCallbackHandler handler(false);
-
- handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-
- // First loop: Callback is registered and FD is signalled.
- pipe.writeSignal();
-
- StopWatch stopWatch("pollOnce");
- int32_t result = mPollLoop->pollOnce(0);
- int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
- ASSERT_EQ(OK, pipe.readSignal())
- << "signal should actually have been written";
- EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
- << "elapsed time should approx. equal zero because FD was already signalled";
- EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
- << "pollOnce result should be POLL_CALLBACK because FD was signalled";
- EXPECT_EQ(1, handler.callbackCount)
- << "callback should be invoked";
-
- // Second loop: Callback is no longer registered and FD is signalled.
- pipe.writeSignal();
-
- stopWatch.reset();
- result = mPollLoop->pollOnce(0);
- elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
- ASSERT_EQ(OK, pipe.readSignal())
- << "signal should actually have been written";
- EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
- << "elapsed time should approx. equal zero because timeout was zero";
- EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
- << "pollOnce result should be POLL_TIMEOUT";
- EXPECT_EQ(1, handler.callbackCount)
- << "callback should not be invoked this time";
-}
-
-TEST_F(PollLoopTest, RemoveCallback_WhenCallbackNotAdded_ReturnsFalse) {
- bool result = mPollLoop->removeCallback(1);
-
- EXPECT_FALSE(result)
- << "removeCallback should return false because FD not registered";
-}
-
-TEST_F(PollLoopTest, RemoveCallback_WhenCallbackAddedThenRemovedTwice_ReturnsTrueFirstTimeAndReturnsFalseSecondTime) {
- Pipe pipe;
- StubCallbackHandler handler(false);
- handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
-
- // First time.
- bool result = mPollLoop->removeCallback(pipe.receiveFd);
-
- EXPECT_TRUE(result)
- << "removeCallback should return true first time because FD was registered";
-
- // Second time.
- result = mPollLoop->removeCallback(pipe.receiveFd);
-
- EXPECT_FALSE(result)
- << "removeCallback should return false second time because FD was no longer registered";
-}
-
-TEST_F(PollLoopTest, PollOnce_WhenCallbackAddedTwice_OnlySecondCallbackShouldBeInvoked) {
- Pipe pipe;
- StubCallbackHandler handler1(true);
- StubCallbackHandler handler2(true);
-
- handler1.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
- handler2.setCallback(mPollLoop, pipe.receiveFd, POLL_IN); // replace it
- pipe.writeSignal(); // would cause FD to be considered signalled
-
- StopWatch stopWatch("pollOnce");
- int32_t result = mPollLoop->pollOnce(100);
- int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
-
- ASSERT_EQ(OK, pipe.readSignal())
- << "signal should actually have been written";
- EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
- << "elapsed time should approx. zero because FD was already signalled";
- EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
- << "pollOnce result should be POLL_CALLBACK because FD was signalled";
- EXPECT_EQ(0, handler1.callbackCount)
- << "original handler callback should not be invoked because it was replaced";
- EXPECT_EQ(1, handler2.callbackCount)
- << "replacement handler callback should be invoked";
-}
-
-
-} // namespace android
diff --git a/location/java/android/location/ILocationProvider.aidl b/location/java/android/location/ILocationProvider.aidl
index 2b9782a..ecf6789 100644
--- a/location/java/android/location/ILocationProvider.aidl
+++ b/location/java/android/location/ILocationProvider.aidl
@@ -20,6 +20,7 @@ import android.location.Criteria;
import android.location.Location;
import android.net.NetworkInfo;
import android.os.Bundle;
+import android.os.WorkSource;
/**
* Binder interface for services that implement location providers.
@@ -43,7 +44,7 @@ interface ILocationProvider {
long getStatusUpdateTime();
String getInternalState();
void enableLocationTracking(boolean enable);
- void setMinTime(long minTime);
+ void setMinTime(long minTime, in WorkSource ws);
void updateNetworkState(int state, in NetworkInfo info);
void updateLocation(in Location location);
boolean sendExtraCommand(String command, inout Bundle extras);
diff --git a/location/java/android/location/provider/LocationProvider.java b/location/java/android/location/provider/LocationProvider.java
index cf939de..95b4425 100644
--- a/location/java/android/location/provider/LocationProvider.java
+++ b/location/java/android/location/provider/LocationProvider.java
@@ -26,6 +26,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.WorkSource;
import android.util.Log;
/**
@@ -106,8 +107,8 @@ public abstract class LocationProvider {
LocationProvider.this.onEnableLocationTracking(enable);
}
- public void setMinTime(long minTime) {
- LocationProvider.this.onSetMinTime(minTime);
+ public void setMinTime(long minTime, WorkSource ws) {
+ LocationProvider.this.onSetMinTime(minTime, ws);
}
public void updateNetworkState(int state, NetworkInfo info) {
@@ -123,11 +124,11 @@ public abstract class LocationProvider {
}
public void addListener(int uid) {
- LocationProvider.this.onAddListener(uid);
+ LocationProvider.this.onAddListener(uid, new WorkSource(uid));
}
public void removeListener(int uid) {
- LocationProvider.this.onRemoveListener(uid);
+ LocationProvider.this.onRemoveListener(uid, new WorkSource(uid));
}
};
@@ -303,8 +304,9 @@ public abstract class LocationProvider {
* the frequency of updates to match the requested frequency.
*
* @param minTime the smallest minTime value over all listeners for this provider.
+ * @param ws the source this work is coming from.
*/
- public abstract void onSetMinTime(long minTime);
+ public abstract void onSetMinTime(long minTime, WorkSource ws);
/**
* Updates the network state for the given provider. This function must
@@ -340,14 +342,16 @@ public abstract class LocationProvider {
* Notifies the location provider when a new client is listening for locations.
*
* @param uid user ID of the new client.
+ * @param ws a WorkSource representation of the client.
*/
- public abstract void onAddListener(int uid);
+ public abstract void onAddListener(int uid, WorkSource ws);
/**
* Notifies the location provider when a client is no longer listening for locations.
*
* @param uid user ID of the client no longer listening.
+ * @param ws a WorkSource representation of the client.
*/
- public abstract void onRemoveListener(int uid);
+ public abstract void onRemoveListener(int uid, WorkSource ws);
}
diff --git a/media/java/android/media/AudioEffect.java b/media/java/android/media/AudioEffect.java
index 35038fa..ae67114 100644
--- a/media/java/android/media/AudioEffect.java
+++ b/media/java/android/media/AudioEffect.java
@@ -16,12 +16,14 @@
package android.media;
-import android.util.Log;
-import java.lang.ref.WeakReference;
-import java.io.IOException;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.util.Log;
+import java.io.IOException;
+import java.lang.ref.WeakReference;
import java.nio.ByteOrder;
import java.nio.ByteBuffer;
import java.util.UUID;
@@ -839,6 +841,128 @@ public class AudioEffect {
byte[] value);
}
+
+ // -------------------------------------------------------------------------
+ // Audio Effect Control panel intents
+ // -------------------------------------------------------------------------
+
+ /**
+ * This intent launches an audio effect control panel UI. The goal of this intent is to enable
+ * separate implementations of music/media player applications and audio effect control
+ * application or services. This will allow platform vendors to offer more advanced control
+ * options for standard effects or control for platform specific effects.
+ * <p>The intent carries a number of extras used by the player application to communicate
+ * necessary pieces of information to the control panel application.
+ * <p>The calling application must use the
+ * {@link android.app.Activity#startActivityForResult(Intent, int)} method to launch the
+ * control panel so that its package name is indicated and used by the control panel
+ * application to keep track of changes for this particular application.
+ * <p>The android.media.EXTRA_AUDIO_SESSION extra will indicate an audio session to which the
+ * audio effects should be applied. If no audio session is specified, either one of the
+ * follownig will happen:
+ * - If an audio session was previously opened by the calling application with
+ * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} intent, the effect changes will
+ * be applied to that session.
+ * - If no audio session is opened, the changes will be stored in the package specific storage
+ * area and applied whenever a new audio session is opened by this application.
+ * <p>The android.media.EXTRA_CONTENT_TYPE extra will help the control panel application
+ * customize both the UI layout and the default audio effect settings if none are already
+ * stored for the calling application.
+ * {@hide} pending API council approval
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL =
+ "android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL";
+
+ /**
+ * This intent indicates to the effect control application or service that a new audio session
+ * is opened and requires audio effects to be applied. This is different from
+ * {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL} in that no UI should be displayed in
+ * this case. Music player applications can broadcast this intent before starting playback
+ * to make sure that any audio effect settings previously selected by the user are applied.
+ * <p>The effect control application receiving this intent will look for previously stored
+ * settings for the calling application, create all required audio effects and apply the
+ * effect settings to the specified audio session.
+ * <p>The calling package name is indicated by the {@link #EXTRA_PACKAGE_NAME} extra and the
+ * audio session ID by the {@link #EXTRA_AUDIO_SESSION} extra. Both extras are mandatory.
+ * <p>If no stored settings are found for the calling application, default settings for the
+ * content type indicated by {@link #EXTRA_CONTENT_TYPE} will be applied. The default settings
+ * for a given content type are platform specific.
+ * {@hide} pending API council approval
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION =
+ "android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION";
+
+ /**
+ * This intent indicates to the effect control application or service that an audio session
+ * is closed and that effects should not be applied anymore.
+ * <p>The effect control application receiving this intent will delete all effects on this
+ * session and store current settings in package specific storage.
+ * <p>The calling package name is indicated by the {@link #EXTRA_PACKAGE_NAME} extra and the
+ * audio session ID by the {@link #EXTRA_AUDIO_SESSION} extra. Both extras are mandatory.
+ * <p>It is good practice for applications to broadcast this intent when music playback stops
+ * and/or when exiting to free system resources consumed by audio effect engines.
+ * {@hide} pending API council approval
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION =
+ "android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION";
+
+ /**
+ * This extra indicates the ID of the audio session the effects should be applied to.
+ * <p>The extra value is of type int and is the audio session ID.
+ * @see android.media.MediaPlayer#setAudioSessionId(int) for details on audio sessions.
+ * {@hide} pending API council approval
+ */
+ public static final String EXTRA_AUDIO_SESSION = "android.media.extra.AUDIO_SESSION";
+
+ /**
+ * This extra indicates the package name of the calling application for
+ * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and
+ * {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION} intents.
+ * <p>The extra value is a string containing the full package name.
+ * {@hide} pending API council approval
+ */
+ public static final String EXTRA_PACKAGE_NAME = "android.media.extra.PACKAGE_NAME";
+
+ /**
+ * This extra indicates which type of content is played by the application. This information is
+ * used by the effect control application to customize UI and default effect settings.
+ * The content type is one of the following:
+ * <ul>
+ * <li>{@link #CONTENT_TYPE_MUSIC}</li>
+ * <li>{@link #CONTENT_TYPE_MOVIE}</li>
+ * <li>{@link #CONTENT_TYPE_GAME}</li>
+ * <li>{@link #CONTENT_TYPE_VOICE}</li>
+ * </ul>
+ * If omitted, the content type defaults to {@link #CONTENT_TYPE_MUSIC}.
+ * {@hide} pending API council approval
+ */
+ public static final String EXTRA_CONTENT_TYPE = "android.media.extra.CONTENT_TYPE";
+
+ /**
+ * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is music
+ * {@hide} pending API council approval
+ */
+ public static final int CONTENT_TYPE_MUSIC = 0;
+ /**
+ * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is video of movie
+ * {@hide} pending API council approval
+ */
+ public static final int CONTENT_TYPE_MOVIE = 1;
+ /**
+ * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is game audio
+ * {@hide} pending API council approval
+ */
+ public static final int CONTENT_TYPE_GAME = 2;
+ /**
+ * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is voice audio
+ * {@hide} pending API council approval
+ */
+ public static final int CONTENT_TYPE_VOICE = 3;
+
+
// ---------------------------------------------------------
// Inner classes
// --------------------
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index b8403e1..280def9 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1210,7 +1210,6 @@ public class MediaPlayer
* effect which can be applied on any sound source that directs a certain amount of its
* energy to this effect. This amount is defined by setAuxEffectSendLevel().
* {@see #setAuxEffectSendLevel(float)}.
- // TODO when AudioEffect is unhidden
* <p>After creating an auxiliary effect (e.g. {@link android.media.EnvironmentalReverb}),
* retrieve its ID with {@link android.media.AudioEffect#getId()} and use it when calling
* this method to attach the player to the effect.
diff --git a/native/android/input.cpp b/native/android/input.cpp
index 57f0072..c753aa5 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -20,7 +20,7 @@
#include <android/input.h>
#include <ui/Input.h>
#include <ui/InputTransport.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
@@ -250,7 +250,7 @@ float AMotionEvent_getHistoricalOrientation(AInputEvent* motion_event, size_t po
void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
- int ident, ALooper_callbackFunc* callback, void* data) {
+ int ident, ALooper_callbackFunc callback, void* data) {
queue->attachLooper(looper, ident, callback, data);
}
diff --git a/native/android/looper.cpp b/native/android/looper.cpp
index 0aeed77..9f5cda9 100644
--- a/native/android/looper.cpp
+++ b/native/android/looper.cpp
@@ -18,65 +18,56 @@
#include <utils/Log.h>
#include <android/looper.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
-using android::PollLoop;
+using android::Looper;
using android::sp;
ALooper* ALooper_forThread() {
- return PollLoop::getForThread().get();
+ return Looper::getForThread().get();
}
-ALooper* ALooper_prepare(int32_t opts) {
- bool allowFds = (opts&ALOOPER_PREPARE_ALLOW_NON_CALLBACKS) != 0;
- sp<PollLoop> loop = PollLoop::getForThread();
- if (loop == NULL) {
- loop = new PollLoop(allowFds);
- PollLoop::setForThread(loop);
- }
- if (loop->getAllowNonCallbacks() != allowFds) {
- LOGW("ALooper_prepare again with different ALOOPER_PREPARE_ALLOW_NON_CALLBACKS");
- }
- return loop.get();
+ALooper* ALooper_prepare(int opts) {
+ return Looper::prepare(opts).get();
}
-int32_t ALooper_pollOnce(int timeoutMillis, int* outEvents, void** outData) {
- sp<PollLoop> loop = PollLoop::getForThread();
- if (loop == NULL) {
- LOGW("ALooper_pollOnce: No looper for this thread!");
- return -1;
- }
- return loop->pollOnce(timeoutMillis, outEvents, outData);
+void ALooper_acquire(ALooper* looper) {
+ static_cast<Looper*>(looper)->incStrong((void*)ALooper_acquire);
}
-int32_t ALooper_pollAll(int timeoutMillis, int* outEvents, void** outData) {
- sp<PollLoop> loop = PollLoop::getForThread();
- if (loop == NULL) {
- LOGW("ALooper_pollOnce: No looper for this thread!");
- return -1;
- }
-
- int32_t result;
- while ((result = loop->pollOnce(timeoutMillis, outEvents, outData)) == ALOOPER_POLL_CALLBACK) {
- ;
+void ALooper_release(ALooper* looper) {
+ static_cast<Looper*>(looper)->decStrong((void*)ALooper_acquire);
+}
+
+int ALooper_pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
+ sp<Looper> looper = Looper::getForThread();
+ if (looper == NULL) {
+ LOGE("ALooper_pollOnce: No looper for this thread!");
+ return ALOOPER_POLL_ERROR;
}
-
- return result;
+
+ return looper->pollOnce(timeoutMillis, outFd, outEvents, outData);
}
-void ALooper_acquire(ALooper* looper) {
- static_cast<PollLoop*>(looper)->incStrong((void*)ALooper_acquire);
+int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
+ sp<Looper> looper = Looper::getForThread();
+ if (looper == NULL) {
+ LOGE("ALooper_pollAll: No looper for this thread!");
+ return ALOOPER_POLL_ERROR;
+ }
+
+ return looper->pollAll(timeoutMillis, outFd, outEvents, outData);
}
-void ALooper_release(ALooper* looper) {
- static_cast<PollLoop*>(looper)->decStrong((void*)ALooper_acquire);
+void ALooper_wake(ALooper* looper) {
+ static_cast<Looper*>(looper)->wake();
}
-void ALooper_addFd(ALooper* looper, int fd, int ident, int events,
- ALooper_callbackFunc* callback, void* data) {
- static_cast<PollLoop*>(looper)->setLooperCallback(fd, ident, events, callback, data);
+int ALooper_addFd(ALooper* looper, int fd, int ident, int events,
+ ALooper_callbackFunc callback, void* data) {
+ return static_cast<Looper*>(looper)->addFd(fd, ident, events, callback, data);
}
-int32_t ALooper_removeFd(ALooper* looper, int fd) {
- return static_cast<PollLoop*>(looper)->removeCallback(fd) ? 1 : 0;
+int ALooper_removeFd(ALooper* looper, int fd) {
+ return static_cast<Looper*>(looper)->removeFd(fd);
}
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index cf7635d..76c6eda 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -21,7 +21,7 @@
#include <android/sensor.h>
#include <utils/RefBase.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
#include <utils/Timers.h>
#include <gui/Sensor.h>
@@ -60,12 +60,12 @@ ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type
}
ASensorEventQueue* ASensorManager_createEventQueue(ASensorManager* manager,
- ALooper* looper, int ident, ALooper_callbackFunc* callback, void* data)
+ ALooper* looper, int ident, ALooper_callbackFunc callback, void* data)
{
sp<SensorEventQueue> queue =
static_cast<SensorManager*>(manager)->createEventQueue();
if (queue != 0) {
- ALooper_addFd(looper, queue->getFd(), ident, POLLIN, callback, data);
+ ALooper_addFd(looper, queue->getFd(), ident, ALOOPER_EVENT_INPUT, callback, data);
queue->looper = looper;
queue->incStrong(manager);
}
diff --git a/native/include/android/input.h b/native/include/android/input.h
index 9da122b..c1134bf 100644
--- a/native/include/android/input.h
+++ b/native/include/android/input.h
@@ -645,7 +645,7 @@ typedef struct AInputQueue AInputQueue;
* ALooper_addFd() for information on the ident, callback, and data params.
*/
void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
- int ident, ALooper_callbackFunc* callback, void* data);
+ int ident, ALooper_callbackFunc callback, void* data);
/*
* Remove the input queue from the looper it is currently attached to.
diff --git a/native/include/android/looper.h b/native/include/android/looper.h
index 287bcd5..a63b744 100644
--- a/native/include/android/looper.h
+++ b/native/include/android/looper.h
@@ -18,8 +18,6 @@
#ifndef ANDROID_LOOPER_H
#define ANDROID_LOOPER_H
-#include <poll.h>
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -41,25 +39,14 @@ struct ALooper;
typedef struct ALooper ALooper;
/**
- * For callback-based event loops, this is the prototype of the function
- * that is called. It is given the file descriptor it is associated with,
- * a bitmask of the poll events that were triggered (typically POLLIN), and
- * the data pointer that was originally supplied.
- *
- * Implementations should return 1 to continue receiving callbacks, or 0
- * to have this file descriptor and callback unregistered from the looper.
- */
-typedef int ALooper_callbackFunc(int fd, int events, void* data);
-
-/**
- * Return the ALooper associated with the calling thread, or NULL if
+ * Returns the looper associated with the calling thread, or NULL if
* there is not one.
*/
ALooper* ALooper_forThread();
enum {
/**
- * Option for ALooper_prepare: this ALooper will accept calls to
+ * Option for ALooper_prepare: this looper will accept calls to
* ALooper_addFd() that do not have a callback (that is provide NULL
* for the callback). In this case the caller of ALooper_pollOnce()
* or ALooper_pollAll() MUST check the return from these functions to
@@ -69,108 +56,188 @@ enum {
};
/**
- * Prepare an ALooper associated with the calling thread, and return it.
- * If the thread already has an ALooper, it is returned. Otherwise, a new
+ * Prepares a looper associated with the calling thread, and returns it.
+ * If the thread already has a looper, it is returned. Otherwise, a new
* one is created, associated with the thread, and returned.
*
* The opts may be ALOOPER_PREPARE_ALLOW_NON_CALLBACKS or 0.
*/
-ALooper* ALooper_prepare(int32_t opts);
+ALooper* ALooper_prepare(int opts);
enum {
/**
- * Result from ALooper_pollOnce() and ALooper_pollAll(): one or
- * more callbacks were executed.
+ * Result from ALooper_pollOnce() and ALooper_pollAll():
+ * The poll was awoken using wake() before the timeout expired
+ * and no callbacks were executed and no other file descriptors were ready.
*/
- ALOOPER_POLL_CALLBACK = -1,
-
+ ALOOPER_POLL_WAKE = -1,
+
+ /**
+ * Result from ALooper_pollOnce() and ALooper_pollAll():
+ * One or more callbacks were executed.
+ */
+ ALOOPER_POLL_CALLBACK = -2,
+
/**
- * Result from ALooper_pollOnce() and ALooper_pollAll(): the
- * timeout expired.
+ * Result from ALooper_pollOnce() and ALooper_pollAll():
+ * The timeout expired.
*/
- ALOOPER_POLL_TIMEOUT = -2,
-
+ ALOOPER_POLL_TIMEOUT = -3,
+
/**
- * Result from ALooper_pollOnce() and ALooper_pollAll(): an error
- * occurred.
+ * Result from ALooper_pollOnce() and ALooper_pollAll():
+ * An error occurred.
*/
- ALOOPER_POLL_ERROR = -3,
+ ALOOPER_POLL_ERROR = -4,
};
/**
- * Wait for events to be available, with optional timeout in milliseconds.
+ * Acquire a reference on the given ALooper object. This prevents the object
+ * from being deleted until the reference is removed. This is only needed
+ * to safely hand an ALooper from one thread to another.
+ */
+void ALooper_acquire(ALooper* looper);
+
+/**
+ * Remove a reference that was previously acquired with ALooper_acquire().
+ */
+void ALooper_release(ALooper* looper);
+
+/**
+ * Flags for file descriptor events that a looper can monitor.
+ *
+ * These flag bits can be combined to monitor multiple events at once.
+ */
+enum {
+ /**
+ * The file descriptor is available for read operations.
+ */
+ ALOOPER_EVENT_INPUT = 1 << 0,
+
+ /**
+ * The file descriptor is available for write operations.
+ */
+ ALOOPER_EVENT_OUTPUT = 1 << 1,
+
+ /**
+ * The file descriptor has encountered an error condition.
+ *
+ * The looper always sends notifications about errors; it is not necessary
+ * to specify this event flag in the requested event set.
+ */
+ ALOOPER_EVENT_ERROR = 1 << 2,
+
+ /**
+ * The file descriptor was hung up.
+ * For example, indicates that the remote end of a pipe or socket was closed.
+ *
+ * The looper always sends notifications about hangups; it is not necessary
+ * to specify this event flag in the requested event set.
+ */
+ ALOOPER_EVENT_HANGUP = 1 << 3,
+};
+
+/**
+ * For callback-based event loops, this is the prototype of the function
+ * that is called. It is given the file descriptor it is associated with,
+ * a bitmask of the poll events that were triggered (typically ALOOPER_EVENT_INPUT),
+ * and the data pointer that was originally supplied.
+ *
+ * Implementations should return 1 to continue receiving callbacks, or 0
+ * to have this file descriptor and callback unregistered from the looper.
+ */
+typedef int (*ALooper_callbackFunc)(int fd, int events, void* data);
+
+/**
+ * Waits for events to be available, with optional timeout in milliseconds.
* Invokes callbacks for all file descriptors on which an event occurred.
*
* If the timeout is zero, returns immediately without blocking.
* If the timeout is negative, waits indefinitely until an event appears.
*
- * Returns ALOOPER_POLL_CALLBACK if a callback was invoked.
+ * Returns ALOOPER_POLL_WAKE if the poll was awoken using wake() before
+ * the timeout expired and no callbacks were invoked and no other file
+ * descriptors were ready.
+ *
+ * Returns ALOOPER_POLL_CALLBACK if one or more callbacks were invoked.
*
* Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
* timeout expired.
*
- * Returns ALOPER_POLL_ERROR if an error occurred.
+ * Returns ALOOPER_POLL_ERROR if an error occurred.
*
* Returns a value >= 0 containing an identifier if its file descriptor has data
* and it has no callback function (requiring the caller here to handle it).
- * In this (and only this) case outEvents and outData will contain the poll
- * events and data associated with the fd.
+ * In this (and only this) case outFd, outEvents and outData will contain the poll
+ * events and data associated with the fd, otherwise they will be set to NULL.
*
* This method does not return until it has finished invoking the appropriate callbacks
* for all file descriptors that were signalled.
*/
-int32_t ALooper_pollOnce(int timeoutMillis, int* outEvents, void** outData);
+int ALooper_pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);
/**
* Like ALooper_pollOnce(), but performs all pending callbacks until all
* data has been consumed or a file descriptor is available with no callback.
* This function will never return ALOOPER_POLL_CALLBACK.
*/
-int32_t ALooper_pollAll(int timeoutMillis, int* outEvents, void** outData);
-
-/**
- * Acquire a reference on the given ALooper object. This prevents the object
- * from being deleted until the reference is removed. This is only needed
- * to safely hand an ALooper from one thread to another.
- */
-void ALooper_acquire(ALooper* looper);
+int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData);
/**
- * Remove a reference that was previously acquired with ALooper_acquire().
+ * Wakes the poll asynchronously.
+ *
+ * This method can be called on any thread.
+ * This method returns immediately.
*/
-void ALooper_release(ALooper* looper);
+void ALooper_wake(ALooper* looper);
/**
- * Add a new file descriptor to be polled by the looper. If the same file
- * descriptor was previously added, it is replaced.
+ * Adds a new file descriptor to be polled by the looper.
+ * If the same file descriptor was previously added, it is replaced.
*
* "fd" is the file descriptor to be added.
- * "ident" is an identifier for this event, which is returned from
- * ALooper_pollOnce(). Must be >= 0, or ALOOPER_POLL_CALLBACK if
- * providing a non-NULL callback.
- * "events" are the poll events to wake up on. Typically this is POLLIN.
- * "callback" is the function to call when there is an event on the file
- * descriptor.
+ * "ident" is an identifier for this event, which is returned from ALooper_pollOnce().
+ * The identifier must be >= 0, or ALOOPER_POLL_CALLBACK if providing a non-NULL callback.
+ * "events" are the poll events to wake up on. Typically this is ALOOPER_EVENT_INPUT.
+ * "callback" is the function to call when there is an event on the file descriptor.
* "data" is a private data pointer to supply to the callback.
*
* There are two main uses of this function:
*
- * (1) If "callback" is non-NULL, then
- * this function will be called when there is data on the file descriptor. It
- * should execute any events it has pending, appropriately reading from the
- * file descriptor. The 'ident' is ignored in this case.
+ * (1) If "callback" is non-NULL, then this function will be called when there is
+ * data on the file descriptor. It should execute any events it has pending,
+ * appropriately reading from the file descriptor. The 'ident' is ignored in this case.
*
* (2) If "callback" is NULL, the 'ident' will be returned by ALooper_pollOnce
* when its file descriptor has data available, requiring the caller to take
* care of processing it.
+ *
+ * Returns 1 if the file descriptor was added or -1 if an error occurred.
+ *
+ * This method can be called on any thread.
+ * This method may block briefly if it needs to wake the poll.
*/
-void ALooper_addFd(ALooper* looper, int fd, int ident, int events,
- ALooper_callbackFunc* callback, void* data);
+int ALooper_addFd(ALooper* looper, int fd, int ident, int events,
+ ALooper_callbackFunc callback, void* data);
/**
- * Remove a previously added file descriptor from the looper.
+ * Removes a previously added file descriptor from the looper.
+ *
+ * When this method returns, it is safe to close the file descriptor since the looper
+ * will no longer have a reference to it. However, it is possible for the callback to
+ * already be running or for it to run one last time if the file descriptor was already
+ * signalled. Calling code is responsible for ensuring that this case is safely handled.
+ * For example, if the callback takes care of removing itself during its own execution either
+ * by returning 0 or by calling this method, then it can be guaranteed to not be invoked
+ * again at any later time unless registered anew.
+ *
+ * Returns 1 if the file descriptor was removed, 0 if none was previously registered
+ * or -1 if an error occurred.
+ *
+ * This method can be called on any thread.
+ * This method may block briefly if it needs to wake the poll.
*/
-int32_t ALooper_removeFd(ALooper* looper, int fd);
+int ALooper_removeFd(ALooper* looper, int fd);
#ifdef __cplusplus
};
diff --git a/native/include/android/sensor.h b/native/include/android/sensor.h
index a102d43..f163f18 100644
--- a/native/include/android/sensor.h
+++ b/native/include/android/sensor.h
@@ -166,7 +166,7 @@ ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type
* Creates a new sensor event queue and associate it with a looper.
*/
ASensorEventQueue* ASensorManager_createEventQueue(ASensorManager* manager,
- ALooper* looper, int ident, ALooper_callbackFunc* callback, void* data);
+ ALooper* looper, int ident, ALooper_callbackFunc callback, void* data);
/*
* Destroys the event queue and free all resources associated to it.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
index b4e0d3a..5dedcc9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
@@ -718,7 +718,6 @@ public class StatusBarPolicy {
iconId = sWifiSignalImages[mLastWifiInetConnectivityState]
[mLastWifiSignalLevel];
}
-
mService.setIcon("wifi", iconId, 0);
// Show the icon since wi-fi is connected
mService.setIconVisibility("wifi", true);
@@ -1101,7 +1100,7 @@ public class StatusBarPolicy {
int iconId;
final int newRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
int newSignalLevel = WifiManager.calculateSignalLevel(newRssi,
- sWifiSignalImages.length);
+ sWifiSignalImages[0].length);
if (newSignalLevel != mLastWifiSignalLevel) {
mLastWifiSignalLevel = newSignalLevel;
if (mIsWifiConnected) {
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index e454c08..aa87f29 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -54,6 +54,7 @@ import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.WorkSource;
import android.provider.Settings;
import android.util.EventLog;
import android.util.Slog;
@@ -504,7 +505,7 @@ class BackupManagerService extends IBackupManager.Stub {
parseLeftoverJournals();
// Power management
- mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "backup");
+ mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
// Start the backup passes going
setBackupEnabled(areEnabled);
@@ -1363,6 +1364,7 @@ class BackupManagerService extends IBackupManager.Stub {
? IApplicationThread.BACKUP_MODE_FULL
: IApplicationThread.BACKUP_MODE_INCREMENTAL;
try {
+ mWakelock.setWorkSource(new WorkSource(request.appInfo.uid));
agent = bindToAgentSynchronous(request.appInfo, mode);
if (agent != null) {
int result = processOneBackup(request, agent, transport);
@@ -1378,6 +1380,8 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
+ mWakelock.setWorkSource(null);
+
return BackupConstants.TRANSPORT_OK;
}
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index a38970f..f3ce8ba 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -52,6 +52,7 @@ import android.os.Message;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
+import android.os.WorkSource;
import android.provider.Settings;
import android.util.Log;
import android.util.Slog;
@@ -157,6 +158,12 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
private final HashMap<String,ArrayList<UpdateRecord>> mRecordsByProvider =
new HashMap<String,ArrayList<UpdateRecord>>();
+ /**
+ * Temporary filled in when computing min time for a provider. Access is
+ * protected by global lock mLock.
+ */
+ private final WorkSource mTmpWorkSource = new WorkSource();
+
// Proximity listeners
private Receiver mProximityReceiver = null;
private ILocationListener mProximityListener = null;
@@ -912,7 +919,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
if (enabled) {
p.enable();
if (listeners > 0) {
- p.setMinTime(getMinTimeLocked(provider));
+ p.setMinTime(getMinTimeLocked(provider), mTmpWorkSource);
p.enableLocationTracking(true);
}
} else {
@@ -924,9 +931,21 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
private long getMinTimeLocked(String provider) {
long minTime = Long.MAX_VALUE;
ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
+ mTmpWorkSource.clear();
if (records != null) {
for (int i=records.size()-1; i>=0; i--) {
- minTime = Math.min(minTime, records.get(i).mMinTime);
+ UpdateRecord ur = records.get(i);
+ long curTime = ur.mMinTime;
+ if (curTime < minTime) {
+ minTime = curTime;
+ }
+ }
+ long inclTime = (minTime*3)/2;
+ for (int i=records.size()-1; i>=0; i--) {
+ UpdateRecord ur = records.get(i);
+ if (ur.mMinTime <= inclTime) {
+ mTmpWorkSource.add(ur.mUid);
+ }
}
}
return minTime;
@@ -1124,7 +1143,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
boolean isProviderEnabled = isAllowedBySettingsLocked(provider);
if (isProviderEnabled) {
long minTimeForProvider = getMinTimeLocked(provider);
- p.setMinTime(minTimeForProvider);
+ p.setMinTime(minTimeForProvider, mTmpWorkSource);
// try requesting single shot if singleShot is true, and fall back to
// regular location tracking if requestSingleShotFix() is not supported
if (!singleShot || !p.requestSingleShotFix()) {
@@ -1222,7 +1241,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
LocationProviderInterface p = mProvidersByName.get(provider);
if (p != null) {
if (hasOtherListener) {
- p.setMinTime(getMinTimeLocked(provider));
+ p.setMinTime(getMinTimeLocked(provider), mTmpWorkSource);
} else {
p.enableLocationTracking(false);
}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 685bee4..72784d5 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -2546,7 +2546,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (GET_CERTIFICATES) {
if (ps != null
&& ps.codePath.equals(srcFile)
- && ps.getTimeStamp() == srcFile.lastModified()) {
+ && ps.timeStamp == srcFile.lastModified()) {
if (ps.signatures.mSignatures != null
&& ps.signatures.mSignatures.length != 0) {
// Optimization: reuse the existing cached certificates
@@ -3139,7 +3139,7 @@ class PackageManagerService extends IPackageManager.Stub {
long scanFileTime = scanFile.lastModified();
final boolean forceDex = (scanMode&SCAN_FORCE_DEX) != 0;
- final boolean scanFileNewer = forceDex || scanFileTime != pkgSetting.getTimeStamp();
+ final boolean scanFileNewer = forceDex || scanFileTime != pkgSetting.timeStamp;
pkg.applicationInfo.processName = fixProcessName(
pkg.applicationInfo.packageName,
pkg.applicationInfo.processName,
@@ -7007,7 +7007,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
pw.println("]");
- pw.print(" timeStamp="); pw.println(ps.getTimeStampStr());
+ pw.print(" timeStamp="); pw.println(String.valueOf(ps.timeStamp));
pw.print(" signatures="); pw.println(ps.signatures);
pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed);
pw.print(" haveGids="); pw.println(ps.haveGids);
@@ -7532,8 +7532,7 @@ class PackageManagerService extends IPackageManager.Stub {
String resourcePathString;
String nativeLibraryPathString;
String obbPathString;
- private long timeStamp;
- private String timeStampString = "0";
+ long timeStamp;
int versionCode;
boolean uidError;
@@ -7590,23 +7589,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
public void setTimeStamp(long newStamp) {
- if (newStamp != timeStamp) {
- timeStamp = newStamp;
- timeStampString = Long.toString(newStamp);
- }
- }
-
- public void setTimeStamp(long newStamp, String newStampStr) {
timeStamp = newStamp;
- timeStampString = newStampStr;
- }
-
- public long getTimeStamp() {
- return timeStamp;
- }
-
- public String getTimeStampStr() {
- return timeStampString;
}
public void copyFrom(PackageSettingBase base) {
@@ -7614,7 +7597,6 @@ class PackageManagerService extends IPackageManager.Stub {
gids = base.gids;
timeStamp = base.timeStamp;
- timeStampString = base.timeStampString;
signatures = base.signatures;
permissionsFixed = base.permissionsFixed;
haveGids = base.haveGids;
@@ -8476,7 +8458,7 @@ class PackageManagerService extends IPackageManager.Stub {
serializer.attribute(null, "realName", pkg.realName);
}
serializer.attribute(null, "codePath", pkg.codePathString);
- serializer.attribute(null, "ts", pkg.getTimeStampStr());
+ serializer.attribute(null, "ts", String.valueOf(pkg.timeStamp));
serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
if (!pkg.resourcePathString.equals(pkg.codePathString)) {
serializer.attribute(null, "resourcePath", pkg.resourcePathString);
@@ -8528,7 +8510,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
serializer.attribute(null, "flags",
Integer.toString(pkg.pkgFlags));
- serializer.attribute(null, "ts", pkg.getTimeStampStr());
+ serializer.attribute(null, "ts", String.valueOf(pkg.timeStamp));
serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
if (pkg.sharedUser == null) {
serializer.attribute(null, "userId",
@@ -8888,7 +8870,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (timeStampStr != null) {
try {
long timeStamp = Long.parseLong(timeStampStr);
- ps.setTimeStamp(timeStamp, timeStampStr);
+ ps.setTimeStamp(timeStamp);
} catch (NumberFormatException e) {
}
}
@@ -8936,7 +8918,6 @@ class PackageManagerService extends IPackageManager.Stub {
String installerPackageName = null;
String uidError = null;
int pkgFlags = 0;
- String timeStampStr;
long timeStamp = 0;
PackageSettingBase packageSetting = null;
String version = null;
@@ -8977,7 +8958,7 @@ class PackageManagerService extends IPackageManager.Stub {
pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
}
}
- timeStampStr = parser.getAttributeValue(null, "ts");
+ final String timeStampStr = parser.getAttributeValue(null, "ts");
if (timeStampStr != null) {
try {
timeStamp = Long.parseLong(timeStampStr);
@@ -9013,7 +8994,7 @@ class PackageManagerService extends IPackageManager.Stub {
+ " while parsing settings at "
+ parser.getPositionDescription());
} else {
- packageSetting.setTimeStamp(timeStamp, timeStampStr);
+ packageSetting.setTimeStamp(timeStamp);
}
} else if (sharedIdStr != null) {
userId = sharedIdStr != null
@@ -9022,7 +9003,7 @@ class PackageManagerService extends IPackageManager.Stub {
packageSetting = new PendingPackage(name.intern(), realName,
new File(codePathStr), new File(resourcePathStr),
nativeLibraryPathStr, userId, versionCode, pkgFlags);
- packageSetting.setTimeStamp(timeStamp, timeStampStr);
+ packageSetting.setTimeStamp(timeStamp);
mPendingPackages.add((PendingPackage) packageSetting);
if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
+ ": sharedUserId=" + userId + " pkg="
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 16f3f10..8ab1bb8 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -50,6 +50,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.WorkSource;
import android.provider.Settings.SettingNotFoundException;
import android.provider.Settings;
import android.util.EventLog;
@@ -310,7 +311,7 @@ class PowerManagerService extends IPowerManager.Stub
long ident = Binder.clearCallingIdentity();
try {
PowerManagerService.this.acquireWakeLockLocked(mFlags, mToken,
- MY_UID, MY_PID, mTag);
+ MY_UID, MY_PID, mTag, null);
mHeld = true;
} finally {
Binder.restoreCallingIdentity(ident);
@@ -607,6 +608,7 @@ class PowerManagerService extends IPowerManager.Stub
final int uid;
final int pid;
final int monitorType;
+ WorkSource ws;
boolean activated = true;
int minState;
}
@@ -630,35 +632,84 @@ class PowerManagerService extends IPowerManager.Stub
|| n == PowerManager.SCREEN_DIM_WAKE_LOCK;
}
- public void acquireWakeLock(int flags, IBinder lock, String tag) {
+ void enforceWakeSourcePermission(int uid, int pid) {
+ if (uid == Process.myUid()) {
+ return;
+ }
+ mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
+ pid, uid, null);
+ }
+
+ public void acquireWakeLock(int flags, IBinder lock, String tag, WorkSource ws) {
int uid = Binder.getCallingUid();
int pid = Binder.getCallingPid();
if (uid != Process.myUid()) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
}
+ if (ws != null) {
+ enforceWakeSourcePermission(uid, pid);
+ }
long ident = Binder.clearCallingIdentity();
try {
synchronized (mLocks) {
- acquireWakeLockLocked(flags, lock, uid, pid, tag);
+ acquireWakeLockLocked(flags, lock, uid, pid, tag, ws);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
- public void acquireWakeLockLocked(int flags, IBinder lock, int uid, int pid, String tag) {
- int acquireUid = -1;
- int acquirePid = -1;
- String acquireName = null;
- int acquireType = -1;
+ void noteStartWakeLocked(WakeLock wl, WorkSource ws) {
+ if (wl.monitorType >= 0) {
+ long origId = Binder.clearCallingIdentity();
+ try {
+ if (ws != null) {
+ mBatteryStats.noteStartWakelockFromSource(ws, wl.pid, wl.tag,
+ wl.monitorType);
+ } else {
+ mBatteryStats.noteStartWakelock(wl.uid, wl.pid, wl.tag, wl.monitorType);
+ }
+ } catch (RemoteException e) {
+ // Ignore
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+ }
+
+ void noteStopWakeLocked(WakeLock wl, WorkSource ws) {
+ if (wl.monitorType >= 0) {
+ long origId = Binder.clearCallingIdentity();
+ try {
+ if (ws != null) {
+ mBatteryStats.noteStopWakelockFromSource(ws, wl.pid, wl.tag,
+ wl.monitorType);
+ } else {
+ mBatteryStats.noteStopWakelock(wl.uid, wl.pid, wl.tag, wl.monitorType);
+ }
+ } catch (RemoteException e) {
+ // Ignore
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+ }
+ public void acquireWakeLockLocked(int flags, IBinder lock, int uid, int pid, String tag,
+ WorkSource ws) {
if (mSpew) {
Slog.d(TAG, "acquireWakeLock flags=0x" + Integer.toHexString(flags) + " tag=" + tag);
}
+ if (ws != null && ws.size() == 0) {
+ ws = null;
+ }
+
int index = mLocks.getIndex(lock);
WakeLock wl;
boolean newlock;
+ boolean diffsource;
+ WorkSource oldsource;
if (index < 0) {
wl = new WakeLock(flags, lock, tag, uid, pid);
switch (wl.flags & LOCK_MASK)
@@ -687,10 +738,31 @@ class PowerManagerService extends IPowerManager.Stub
return;
}
mLocks.addLock(wl);
+ if (ws != null) {
+ wl.ws = new WorkSource(ws);
+ }
newlock = true;
+ diffsource = false;
+ oldsource = null;
} else {
wl = mLocks.get(index);
newlock = false;
+ oldsource = wl.ws;
+ if (oldsource != null) {
+ if (ws == null) {
+ wl.ws = null;
+ diffsource = true;
+ } else {
+ diffsource = oldsource.diff(ws);
+ }
+ } else if (ws != null) {
+ diffsource = true;
+ } else {
+ diffsource = false;
+ }
+ if (diffsource) {
+ wl.ws = new WorkSource(ws);
+ }
}
if (isScreenLock(flags)) {
// if this causes a wakeup, we reactivate all of the locks and
@@ -731,19 +803,36 @@ class PowerManagerService extends IPowerManager.Stub
enableProximityLockLocked();
}
}
- if (newlock) {
- acquireUid = wl.uid;
- acquirePid = wl.pid;
- acquireName = wl.tag;
- acquireType = wl.monitorType;
+
+ if (diffsource) {
+ // If the lock sources have changed, need to first release the
+ // old ones.
+ noteStopWakeLocked(wl, oldsource);
+ }
+ if (newlock || diffsource) {
+ noteStartWakeLocked(wl, ws);
}
+ }
- if (acquireType >= 0) {
- try {
- mBatteryStats.noteStartWakelock(acquireUid, acquirePid, acquireName, acquireType);
- } catch (RemoteException e) {
- // Ignore
+ public void updateWakeLockWorkSource(IBinder lock, WorkSource ws) {
+ int uid = Binder.getCallingUid();
+ int pid = Binder.getCallingPid();
+ if (ws != null && ws.size() == 0) {
+ ws = null;
+ }
+ if (ws != null) {
+ enforceWakeSourcePermission(uid, pid);
+ }
+ synchronized (mLocks) {
+ int index = mLocks.getIndex(lock);
+ if (index < 0) {
+ throw new IllegalArgumentException("Wake lock not active");
}
+ WakeLock wl = mLocks.get(index);
+ WorkSource oldsource = wl.ws;
+ wl.ws = ws != null ? new WorkSource(ws) : null;
+ noteStopWakeLocked(wl, oldsource);
+ noteStartWakeLocked(wl, ws);
}
}
@@ -759,11 +848,6 @@ class PowerManagerService extends IPowerManager.Stub
}
private void releaseWakeLockLocked(IBinder lock, int flags, boolean death) {
- int releaseUid;
- int releasePid;
- String releaseName;
- int releaseType;
-
WakeLock wl = mLocks.removeLock(lock);
if (wl == null) {
return;
@@ -804,21 +888,8 @@ class PowerManagerService extends IPowerManager.Stub
}
// Unlink the lock from the binder.
wl.binder.unlinkToDeath(wl, 0);
- releaseUid = wl.uid;
- releasePid = wl.pid;
- releaseName = wl.tag;
- releaseType = wl.monitorType;
- if (releaseType >= 0) {
- long origId = Binder.clearCallingIdentity();
- try {
- mBatteryStats.noteStopWakelock(releaseUid, releasePid, releaseName, releaseType);
- } catch (RemoteException e) {
- // Ignore
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- }
+ noteStopWakeLocked(wl, wl.ws);
}
private class PokeLock implements IBinder.DeathRecipient
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 4a9c9e9..859de46 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -518,14 +518,8 @@ class ServerThread extends Thread {
});
// For debug builds, log event loop stalls to dropbox for analysis.
- // Similar logic also appears in ActivityThread.java for system apps.
- if (!"user".equals(Build.TYPE)) {
- Slog.i(TAG, "Enabling StrictMode for system server.");
- StrictMode.setThreadPolicy(
- StrictMode.DISALLOW_DISK_WRITE |
- StrictMode.DISALLOW_DISK_READ |
- StrictMode.DISALLOW_NETWORK |
- StrictMode.PENALTY_DROPBOX);
+ if (StrictMode.conditionallyEnableDebugLogging()) {
+ Slog.i(TAG, "Enabled StrictMode for system server main thread.");
}
Looper.loop();
diff --git a/services/java/com/android/server/VibratorService.java b/services/java/com/android/server/VibratorService.java
index 2e7e3e1..f0b5955 100755
--- a/services/java/com/android/server/VibratorService.java
+++ b/services/java/com/android/server/VibratorService.java
@@ -29,6 +29,7 @@ import android.os.RemoteException;
import android.os.IBinder;
import android.os.Binder;
import android.os.SystemClock;
+import android.os.WorkSource;
import android.util.Slog;
import java.util.LinkedList;
@@ -39,6 +40,7 @@ public class VibratorService extends IVibratorService.Stub {
private final LinkedList<Vibration> mVibrations;
private Vibration mCurrentVibration;
+ private final WorkSource mTmpWorkSource = new WorkSource();
private class Vibration implements IBinder.DeathRecipient {
private final IBinder mToken;
@@ -46,22 +48,24 @@ public class VibratorService extends IVibratorService.Stub {
private final long mStartTime;
private final long[] mPattern;
private final int mRepeat;
+ private final int mUid;
- Vibration(IBinder token, long millis) {
- this(token, millis, null, 0);
+ Vibration(IBinder token, long millis, int uid) {
+ this(token, millis, null, 0, uid);
}
- Vibration(IBinder token, long[] pattern, int repeat) {
- this(token, 0, pattern, repeat);
+ Vibration(IBinder token, long[] pattern, int repeat, int uid) {
+ this(token, 0, pattern, repeat, uid);
}
private Vibration(IBinder token, long millis, long[] pattern,
- int repeat) {
+ int repeat, int uid) {
mToken = token;
mTimeout = millis;
mStartTime = SystemClock.uptimeMillis();
mPattern = pattern;
mRepeat = repeat;
+ mUid = uid;
}
public void binderDied() {
@@ -98,7 +102,7 @@ public class VibratorService extends IVibratorService.Stub {
mContext = context;
PowerManager pm = (PowerManager)context.getSystemService(
Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
mWakeLock.setReferenceCounted(true);
mVibrations = new LinkedList<Vibration>();
@@ -113,6 +117,7 @@ public class VibratorService extends IVibratorService.Stub {
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires VIBRATE permission");
}
+ int uid = Binder.getCallingUid();
// We're running in the system server so we cannot crash. Check for a
// timeout of 0 or negative. This will ensure that a vibration has
// either a timeout of > 0 or a non-null pattern.
@@ -122,7 +127,7 @@ public class VibratorService extends IVibratorService.Stub {
// longer than milliseconds.
return;
}
- Vibration vib = new Vibration(token, milliseconds);
+ Vibration vib = new Vibration(token, milliseconds, uid);
synchronized (mVibrations) {
removeVibrationLocked(token);
doCancelVibrateLocked();
@@ -146,6 +151,7 @@ public class VibratorService extends IVibratorService.Stub {
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires VIBRATE permission");
}
+ int uid = Binder.getCallingUid();
// so wakelock calls will succeed
long identity = Binder.clearCallingIdentity();
try {
@@ -165,7 +171,7 @@ public class VibratorService extends IVibratorService.Stub {
return;
}
- Vibration vib = new Vibration(token, pattern, repeat);
+ Vibration vib = new Vibration(token, pattern, repeat, uid);
try {
token.linkToDeath(vib, 0);
} catch (RemoteException e) {
@@ -280,6 +286,8 @@ public class VibratorService extends IVibratorService.Stub {
VibrateThread(Vibration vib) {
mVibration = vib;
+ mTmpWorkSource.set(vib.mUid);
+ mWakeLock.setWorkSource(mTmpWorkSource);
mWakeLock.acquire();
}
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 124da4e..c837a3a 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -727,9 +727,10 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
+ // Called by SystemBackupAgent after files are restored to disk.
void settingsRestored() {
if (DEBUG) Slog.v(TAG, "settingsRestored");
-
+
boolean success = false;
synchronized (mLock) {
loadSettingsLocked();
@@ -766,7 +767,10 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
mName = "";
WALLPAPER_FILE.delete();
}
- saveSettingsLocked();
+
+ synchronized (mLock) {
+ saveSettingsLocked();
+ }
}
boolean restoreNamedResourceLocked() {
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 0eca082..f11c0f7 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -63,6 +63,7 @@ import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.WorkSource;
import android.provider.Settings;
import android.util.Slog;
import android.text.TextUtils;
@@ -2036,8 +2037,8 @@ public class WifiService extends IWifiManager.Stub {
}
private class WifiLock extends DeathRecipient {
- WifiLock(int lockMode, String tag, IBinder binder) {
- super(lockMode, tag, binder);
+ WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
+ super(lockMode, tag, binder, ws);
}
public void binderDied() {
@@ -2111,7 +2112,15 @@ public class WifiService extends IWifiManager.Stub {
}
}
- public boolean acquireWifiLock(IBinder binder, int lockMode, String tag) {
+ void enforceWakeSourcePermission(int uid, int pid) {
+ if (uid == Process.myUid()) {
+ return;
+ }
+ mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
+ pid, uid, null);
+ }
+
+ public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
if (lockMode != WifiManager.WIFI_MODE_FULL &&
lockMode != WifiManager.WIFI_MODE_SCAN_ONLY &&
@@ -2120,34 +2129,68 @@ public class WifiService extends IWifiManager.Stub {
if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode);
return false;
}
- WifiLock wifiLock = new WifiLock(lockMode, tag, binder);
+ if (ws != null) {
+ enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid());
+ }
+ if (ws != null && ws.size() == 0) {
+ ws = null;
+ }
+ if (ws == null) {
+ ws = new WorkSource(Binder.getCallingUid());
+ }
+ WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws);
synchronized (mLocks) {
return acquireWifiLockLocked(wifiLock);
}
}
+ private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException {
+ switch(wifiLock.mMode) {
+ case WifiManager.WIFI_MODE_FULL:
+ mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource);
+ break;
+ case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
+ /* Treat high power as a full lock for battery stats */
+ mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource);
+ break;
+ case WifiManager.WIFI_MODE_SCAN_ONLY:
+ mBatteryStats.noteScanWifiLockAcquiredFromSource(wifiLock.mWorkSource);
+ break;
+ }
+ }
+
+ private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException {
+ switch(wifiLock.mMode) {
+ case WifiManager.WIFI_MODE_FULL:
+ mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
+ break;
+ case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
+ /* Treat high power as a full lock for battery stats */
+ mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
+ break;
+ case WifiManager.WIFI_MODE_SCAN_ONLY:
+ mBatteryStats.noteScanWifiLockReleasedFromSource(wifiLock.mWorkSource);
+ break;
+ }
+ }
+
private boolean acquireWifiLockLocked(WifiLock wifiLock) {
Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock);
mLocks.addLock(wifiLock);
- int uid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
try {
+ noteAcquireWifiLock(wifiLock);
switch(wifiLock.mMode) {
case WifiManager.WIFI_MODE_FULL:
++mFullLocksAcquired;
- mBatteryStats.noteFullWifiLockAcquired(uid);
break;
case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
++mFullHighPerfLocksAcquired;
- /* Treat high power as a full lock for battery stats */
- mBatteryStats.noteFullWifiLockAcquired(uid);
break;
-
case WifiManager.WIFI_MODE_SCAN_ONLY:
++mScanLocksAcquired;
- mBatteryStats.noteScanWifiLockAcquired(uid);
break;
}
} catch (RemoteException e) {
@@ -2159,6 +2202,33 @@ public class WifiService extends IWifiManager.Stub {
return true;
}
+ public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
+ int uid = Binder.getCallingUid();
+ int pid = Binder.getCallingPid();
+ if (ws != null && ws.size() == 0) {
+ ws = null;
+ }
+ if (ws != null) {
+ enforceWakeSourcePermission(uid, pid);
+ }
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLocks) {
+ int index = mLocks.findLockByBinder(lock);
+ if (index < 0) {
+ throw new IllegalArgumentException("Wifi lock not active");
+ }
+ WifiLock wl = mLocks.mList.get(index);
+ noteReleaseWifiLock(wl);
+ wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid);
+ noteAcquireWifiLock(wl);
+ }
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
public boolean releaseWifiLock(IBinder lock) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
synchronized (mLocks) {
@@ -2176,21 +2246,18 @@ public class WifiService extends IWifiManager.Stub {
hadLock = (wifiLock != null);
if (hadLock) {
- int uid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
try {
+ noteAcquireWifiLock(wifiLock);
switch(wifiLock.mMode) {
case WifiManager.WIFI_MODE_FULL:
++mFullLocksReleased;
- mBatteryStats.noteFullWifiLockReleased(uid);
break;
case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
++mFullHighPerfLocksReleased;
- mBatteryStats.noteFullWifiLockReleased(uid);
break;
case WifiManager.WIFI_MODE_SCAN_ONLY:
++mScanLocksReleased;
- mBatteryStats.noteScanWifiLockReleased(uid);
break;
}
} catch (RemoteException e) {
@@ -2208,12 +2275,14 @@ public class WifiService extends IWifiManager.Stub {
String mTag;
int mMode;
IBinder mBinder;
+ WorkSource mWorkSource;
- DeathRecipient(int mode, String tag, IBinder binder) {
+ DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws) {
super();
mTag = tag;
mMode = mode;
mBinder = binder;
+ mWorkSource = ws;
try {
mBinder.linkToDeath(this, 0);
} catch (RemoteException e) {
@@ -2228,7 +2297,7 @@ public class WifiService extends IWifiManager.Stub {
private class Multicaster extends DeathRecipient {
Multicaster(String tag, IBinder binder) {
- super(Binder.getCallingUid(), tag, binder);
+ super(Binder.getCallingUid(), tag, binder, null);
}
public void binderDied() {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 2cdf31e..cf767ca 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -5985,12 +5985,18 @@ public final class ActivityManagerService extends ActivityManagerNative
finisher = new IIntentReceiver.Stub() {
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered,
- boolean sticky)
- throws RemoteException {
- synchronized (ActivityManagerService.this) {
- mDidUpdate = true;
- }
- systemReady(goingCallback);
+ boolean sticky) {
+ // The raw IIntentReceiver interface is called
+ // with the AM lock held, so redispatch to
+ // execute our code without the lock.
+ mHandler.post(new Runnable() {
+ public void run() {
+ synchronized (ActivityManagerService.this) {
+ mDidUpdate = true;
+ }
+ systemReady(goingCallback);
+ }
+ });
}
};
}
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index a0c21dd..4fc8020 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1104,7 +1104,7 @@ public class ActivityStack {
// Okay we are now going to start a switch, to 'next'. We may first
// have to pause the current activity, but this is an important point
// where we have decided to go to 'next' so keep track of that.
- if (mLastStartedActivity != null) {
+ if (mLastStartedActivity != null && !mLastStartedActivity.finishing) {
long now = SystemClock.uptimeMillis();
final boolean inTime = mLastStartedActivity.startTime != 0
&& (mLastStartedActivity.startTime + START_WARN_TIME) >= now;
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index 7314e04..bb40967 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -23,6 +23,7 @@ import android.os.IBinder;
import android.os.Parcel;
import android.os.Process;
import android.os.ServiceManager;
+import android.os.WorkSource;
import android.telephony.SignalStrength;
import android.util.Slog;
@@ -107,6 +108,20 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
}
}
+ public void noteStartWakelockFromSource(WorkSource ws, int pid, String name, int type) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteStartWakeFromSourceLocked(ws, pid, name, type);
+ }
+ }
+
+ public void noteStopWakelockFromSource(WorkSource ws, int pid, String name, int type) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteStopWakeFromSourceLocked(ws, pid, name, type);
+ }
+ }
+
public void noteStartSensor(int uid, int sensor) {
enforceCallingPermission();
synchronized (mStats) {
@@ -317,6 +332,48 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
}
}
+ public void noteFullWifiLockAcquiredFromSource(WorkSource ws) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteFullWifiLockAcquiredFromSourceLocked(ws);
+ }
+ }
+
+ public void noteFullWifiLockReleasedFromSource(WorkSource ws) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteFullWifiLockReleasedFromSourceLocked(ws);
+ }
+ }
+
+ public void noteScanWifiLockAcquiredFromSource(WorkSource ws) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteScanWifiLockAcquiredFromSourceLocked(ws);
+ }
+ }
+
+ public void noteScanWifiLockReleasedFromSource(WorkSource ws) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteScanWifiLockReleasedFromSourceLocked(ws);
+ }
+ }
+
+ public void noteWifiMulticastEnabledFromSource(WorkSource ws) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteWifiMulticastEnabledFromSourceLocked(ws);
+ }
+ }
+
+ public void noteWifiMulticastDisabledFromSource(WorkSource ws) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteWifiMulticastDisabledFromSourceLocked(ws);
+ }
+ }
+
public boolean isOnBattery() {
return mStats.isOnBattery();
}
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index c1165c7..3bf6ee4 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -44,6 +44,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.WorkSource;
import android.provider.Settings;
import android.util.Log;
import android.util.SparseIntArray;
@@ -736,7 +737,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
startNavigating(true);
}
- public void setMinTime(long minTime) {
+ public void setMinTime(long minTime, WorkSource ws) {
if (DEBUG) Log.d(TAG, "setMinTime " + minTime);
if (minTime >= 0) {
@@ -779,7 +780,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
public void addListener(int uid) {
synchronized (mWakeLock) {
mPendingListenerMessages++;
- mWakeLock.acquire();
+ mWakeLock.acquire();
Message m = Message.obtain(mHandler, ADD_LISTENER);
m.arg1 = uid;
mHandler.sendMessage(m);
diff --git a/services/java/com/android/server/location/LocationProviderInterface.java b/services/java/com/android/server/location/LocationProviderInterface.java
index 084ab81..858a582 100644
--- a/services/java/com/android/server/location/LocationProviderInterface.java
+++ b/services/java/com/android/server/location/LocationProviderInterface.java
@@ -20,6 +20,7 @@ import android.location.Criteria;
import android.location.Location;
import android.net.NetworkInfo;
import android.os.Bundle;
+import android.os.WorkSource;
/**
* Location Manager's interface for location providers.
@@ -47,7 +48,7 @@ public interface LocationProviderInterface {
/* returns false if single shot is not supported */
boolean requestSingleShotFix();
String getInternalState();
- void setMinTime(long minTime);
+ void setMinTime(long minTime, WorkSource ws);
void updateNetworkState(int state, NetworkInfo info);
void updateLocation(Location location);
boolean sendExtraCommand(String command, Bundle extras);
diff --git a/services/java/com/android/server/location/LocationProviderProxy.java b/services/java/com/android/server/location/LocationProviderProxy.java
index 24d7737..7dc9920 100644
--- a/services/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/java/com/android/server/location/LocationProviderProxy.java
@@ -29,6 +29,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.WorkSource;
import android.util.Log;
import com.android.internal.location.DummyLocationProvider;
@@ -52,6 +53,7 @@ public class LocationProviderProxy implements LocationProviderInterface {
private boolean mLocationTracking = false;
private boolean mEnabled = false;
private long mMinTime = -1;
+ private WorkSource mMinTimeSource = new WorkSource();
private int mNetworkState;
private NetworkInfo mNetworkInfo;
@@ -122,7 +124,7 @@ public class LocationProviderProxy implements LocationProviderInterface {
provider.enableLocationTracking(true);
}
if (mMinTime >= 0) {
- provider.setMinTime(mMinTime);
+ provider.setMinTime(mMinTime, mMinTimeSource);
}
if (mNetworkInfo != null) {
provider.updateNetworkState(mNetworkState, mNetworkInfo);
@@ -318,6 +320,7 @@ public class LocationProviderProxy implements LocationProviderInterface {
mLocationTracking = enable;
if (!enable) {
mMinTime = -1;
+ mMinTimeSource.clear();
}
ILocationProvider provider;
synchronized (mServiceConnection) {
@@ -339,15 +342,16 @@ public class LocationProviderProxy implements LocationProviderInterface {
return mMinTime;
}
- public void setMinTime(long minTime) {
- mMinTime = minTime;
+ public void setMinTime(long minTime, WorkSource ws) {
+ mMinTime = minTime;
+ mMinTimeSource.set(ws);
ILocationProvider provider;
synchronized (mServiceConnection) {
provider = mProvider;
}
if (provider != null) {
try {
- provider.setMinTime(minTime);
+ provider.setMinTime(minTime, ws);
} catch (RemoteException e) {
}
}
diff --git a/services/java/com/android/server/location/MockProvider.java b/services/java/com/android/server/location/MockProvider.java
index 01b34b7..09d799f 100644
--- a/services/java/com/android/server/location/MockProvider.java
+++ b/services/java/com/android/server/location/MockProvider.java
@@ -23,6 +23,7 @@ import android.location.LocationProvider;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.RemoteException;
+import android.os.WorkSource;
import android.util.Log;
import android.util.PrintWriterPrinter;
@@ -201,7 +202,7 @@ public class MockProvider implements LocationProviderInterface {
return false;
}
- public void setMinTime(long minTime) {
+ public void setMinTime(long minTime, WorkSource ws) {
}
public void updateNetworkState(int state, NetworkInfo info) {
diff --git a/services/java/com/android/server/location/PassiveProvider.java b/services/java/com/android/server/location/PassiveProvider.java
index 7fc93f8..ea0d1b0 100644
--- a/services/java/com/android/server/location/PassiveProvider.java
+++ b/services/java/com/android/server/location/PassiveProvider.java
@@ -24,6 +24,7 @@ import android.location.LocationProvider;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.RemoteException;
+import android.os.WorkSource;
import android.util.Log;
/**
@@ -123,7 +124,7 @@ public class PassiveProvider implements LocationProviderInterface {
return false;
}
- public void setMinTime(long minTime) {
+ public void setMinTime(long minTime, WorkSource ws) {
}
public void updateNetworkState(int state, NetworkInfo info) {
diff --git a/services/java/com/android/server/sip/SipService.java b/services/java/com/android/server/sip/SipService.java
index c3786f5..c1841f6 100644
--- a/services/java/com/android/server/sip/SipService.java
+++ b/services/java/com/android/server/sip/SipService.java
@@ -404,6 +404,7 @@ public final class SipService extends ISipService.Stub {
public void onConnectivityChanged(boolean connected)
throws SipException {
+ mSipGroup.onConnectivityChanged();
if (connected) {
resetGroup(mLocalIp);
if (mOpened) openToReceiveCalls();
@@ -770,6 +771,23 @@ public final class SipService extends ISipService.Stub {
b.get(ConnectivityManager.EXTRA_NETWORK_INFO);
String type = netInfo.getTypeName();
NetworkInfo.State state = netInfo.getState();
+
+ NetworkInfo activeNetInfo = getActiveNetworkInfo();
+ if (activeNetInfo != null) {
+ Log.v(TAG, "active network: " + activeNetInfo.getTypeName()
+ + ((activeNetInfo.getState() == NetworkInfo.State.CONNECTED)
+ ? " CONNECTED" : " DISCONNECTED"));
+ } else {
+ Log.v(TAG, "active network: null");
+ }
+ if ((state == NetworkInfo.State.CONNECTED)
+ && (activeNetInfo != null)
+ && (activeNetInfo.getType() != netInfo.getType())) {
+ Log.d(TAG, "ignore connect event: " + type
+ + ", active: " + activeNetInfo.getTypeName());
+ return;
+ }
+
if (state == NetworkInfo.State.CONNECTED) {
Log.v(TAG, "Connectivity alert: CONNECTED " + type);
onChanged(type, true);
@@ -784,6 +802,12 @@ public final class SipService extends ISipService.Stub {
}
}
+ private NetworkInfo getActiveNetworkInfo() {
+ ConnectivityManager cm = (ConnectivityManager)
+ mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ return cm.getActiveNetworkInfo();
+ }
+
private void onChanged(String type, boolean connected) {
synchronized (SipService.this) {
// When turning on WIFI, it needs some time for network
diff --git a/services/java/com/android/server/sip/SipSessionGroup.java b/services/java/com/android/server/sip/SipSessionGroup.java
index da8e9b8..06b6ec9 100644
--- a/services/java/com/android/server/sip/SipSessionGroup.java
+++ b/services/java/com/android/server/sip/SipSessionGroup.java
@@ -19,6 +19,7 @@ package com.android.server.sip;
import gov.nist.javax.sip.clientauthutils.AccountManager;
import gov.nist.javax.sip.clientauthutils.UserCredentials;
import gov.nist.javax.sip.header.SIPHeaderNames;
+import gov.nist.javax.sip.header.ProxyAuthenticate;
import gov.nist.javax.sip.header.WWWAuthenticate;
import gov.nist.javax.sip.message.SIPMessage;
@@ -153,6 +154,13 @@ class SipSessionGroup implements SipListener {
mSessionMap.clear();
}
+ synchronized void onConnectivityChanged() {
+ for (SipSessionImpl s : mSessionMap.values()) {
+ s.onError(SipErrorCode.DATA_CONNECTION_LOST,
+ "data connection lost");
+ }
+ }
+
public SipProfile getLocalProfile() {
return mLocalProfile;
}
@@ -210,10 +218,10 @@ class SipSessionGroup implements SipListener {
private synchronized SipSessionImpl getSipSession(EventObject event) {
String key = SipHelper.getCallId(event);
- Log.d(TAG, " sesssion key from event: " + key);
- Log.d(TAG, " active sessions:");
+ Log.d(TAG, "sesssion key from event: " + key);
+ Log.d(TAG, "active sessions:");
for (String k : mSessionMap.keySet()) {
- Log.d(TAG, " ..... '" + k + "': " + mSessionMap.get(k));
+ Log.d(TAG, " ..." + k + ": " + mSessionMap.get(k));
}
SipSessionImpl session = mSessionMap.get(key);
return ((session != null) ? session : mCallReceiverSession);
@@ -222,7 +230,7 @@ class SipSessionGroup implements SipListener {
private synchronized void addSipSession(SipSessionImpl newSession) {
removeSipSession(newSession);
String key = newSession.getCallId();
- Log.d(TAG, " +++++ add a session with key: '" + key + "'");
+ Log.d(TAG, "+++ add a session with key: '" + key + "'");
mSessionMap.put(key, newSession);
for (String k : mSessionMap.keySet()) {
Log.d(TAG, " ..... " + k + ": " + mSessionMap.get(k));
@@ -724,7 +732,8 @@ class SipSessionGroup implements SipListener {
Response response = event.getResponse();
String nonce = getNonceFromResponse(response);
if (((nonce != null) && nonce.equals(mLastNonce)) ||
- (nonce == mLastNonce)) {
+ (nonce == null)) {
+ mLastNonce = nonce;
return false;
} else {
mClientTransaction = mSipHelper.handleChallenge(
@@ -757,9 +766,12 @@ class SipSessionGroup implements SipListener {
}
private String getNonceFromResponse(Response response) {
- WWWAuthenticate authHeader = (WWWAuthenticate)(response.getHeader(
- SIPHeaderNames.WWW_AUTHENTICATE));
- return (authHeader == null) ? null : authHeader.getNonce();
+ WWWAuthenticate wwwAuth = (WWWAuthenticate)response.getHeader(
+ SIPHeaderNames.WWW_AUTHENTICATE);
+ if (wwwAuth != null) return wwwAuth.getNonce();
+ ProxyAuthenticate proxyAuth = (ProxyAuthenticate)response.getHeader(
+ SIPHeaderNames.PROXY_AUTHENTICATE);
+ return (proxyAuth == null) ? null : proxyAuth.getNonce();
}
private boolean readyForCall(EventObject evt) throws SipException {
@@ -998,7 +1010,8 @@ class SipSessionGroup implements SipListener {
onRegistrationFailed(errorCode, message);
break;
default:
- if (mInCall) {
+ if ((errorCode != SipErrorCode.DATA_CONNECTION_LOST)
+ && mInCall) {
fallbackToPreviousInCall(errorCode, message);
} else {
endCallOnError(errorCode, message);
@@ -1148,7 +1161,7 @@ class SipSessionGroup implements SipListener {
.setPort(uri.getPort())
.setDisplayName(address.getDisplayName())
.build();
- } catch (InvalidArgumentException e) {
+ } catch (IllegalArgumentException e) {
throw new SipException("createPeerProfile()", e);
} catch (ParseException e) {
throw new SipException("createPeerProfile()", e);
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 3025f77..e204e04 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -529,7 +529,7 @@ status_t SensorService::SensorEventConnection::sendEvents(
LOGE_IF(size<0, "dropping %d events on the floor (%s)",
count, strerror(-size));
- return size < 0 ? size : NO_ERROR;
+ return size < 0 ? status_t(size) : status_t(NO_ERROR);
}
sp<SensorChannel> SensorService::SensorEventConnection::getSensorChannel() const
diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp
index e464713..42bf983 100644
--- a/services/sensorservice/tests/sensorservicetest.cpp
+++ b/services/sensorservice/tests/sensorservicetest.cpp
@@ -18,11 +18,11 @@
#include <gui/Sensor.h>
#include <gui/SensorManager.h>
#include <gui/SensorEventQueue.h>
-#include <utils/PollLoop.h>
+#include <utils/Looper.h>
using namespace android;
-bool receiver(int fd, int events, void* data)
+int receiver(int fd, int events, void* data)
{
sp<SensorEventQueue> q((SensorEventQueue*)data);
ssize_t n;
@@ -41,7 +41,7 @@ bool receiver(int fd, int events, void* data)
if (n<0 && n != -EAGAIN) {
printf("error reading events (%s)\n", strerror(-n));
}
- return true;
+ return 1;
}
@@ -51,7 +51,7 @@ int main(int argc, char** argv)
Sensor const* const* list;
ssize_t count = mgr.getSensorList(&list);
- printf("numSensors=%d\n", count);
+ printf("numSensors=%d\n", int(count));
sp<SensorEventQueue> q = mgr.createEventQueue();
printf("queue=%p\n", q.get());
@@ -63,13 +63,16 @@ int main(int argc, char** argv)
q->setEventRate(accelerometer, ms2ns(10));
- sp<PollLoop> loop = new PollLoop(false);
- loop->setCallback(q->getFd(), POLLIN, receiver, q.get());
+ sp<Looper> loop = new Looper(false);
+ loop->addFd(q->getFd(), 0, ALOOPER_EVENT_INPUT, receiver, q.get());
do {
//printf("about to poll...\n");
- int32_t ret = loop->pollOnce(-1, 0, 0);
+ int32_t ret = loop->pollOnce(-1);
switch (ret) {
+ case ALOOPER_POLL_WAKE:
+ //("ALOOPER_POLL_WAKE\n");
+ break;
case ALOOPER_POLL_CALLBACK:
//("ALOOPER_POLL_CALLBACK\n");
break;
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 2eac0a8..0515110 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -296,6 +296,10 @@ status_t DisplayHardware::compositionComplete() const {
return mNativeWindow->compositionComplete();
}
+int DisplayHardware::getCurrentBufferIndex() const {
+ return mNativeWindow->getCurrentBufferIndex();
+}
+
void DisplayHardware::flip(const Region& dirty) const
{
checkGLErrors();
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index 66bf521..2d7900c 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -87,6 +87,9 @@ public:
return Rect(mWidth, mHeight);
}
+ // only for debugging
+ int getCurrentBufferIndex() const;
+
private:
void init(uint32_t displayIndex) __attribute__((noinline));
void fini() __attribute__((noinline));
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 637ae48..f199ca9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -38,6 +38,7 @@
#include <utils/StopWatch.h>
#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicLog.h>
#include <ui/PixelFormat.h>
#include <pixelflinger/pixelflinger.h>
@@ -371,15 +372,25 @@ bool SurfaceFlinger::threadLoop()
const DisplayHardware& hw(graphicPlane(0).displayHardware());
if (LIKELY(hw.canDraw() && !isFrozen())) {
// repaint the framebuffer (if needed)
+
+ const int index = hw.getCurrentBufferIndex();
+ GraphicLog& logger(GraphicLog::getInstance());
+
+ logger.log(GraphicLog::SF_REPAINT, index);
handleRepaint();
// inform the h/w that we're done compositing
+ logger.log(GraphicLog::SF_COMPOSITION_COMPLETE, index);
hw.compositionComplete();
// release the clients before we flip ('cause flip might block)
+ logger.log(GraphicLog::SF_UNLOCK_CLIENTS, index);
unlockClients();
+ logger.log(GraphicLog::SF_SWAP_BUFFERS, index);
postFramebuffer();
+
+ logger.log(GraphicLog::SF_REPAINT_DONE, index);
} else {
// pretend we did the post
unlockClients();
@@ -1470,8 +1481,7 @@ status_t SurfaceFlinger::onTransact(
int n;
switch (code) {
case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE
- return NO_ERROR;
- case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE
+ case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE
return NO_ERROR;
case 1002: // SHOW_UPDATES
n = data.readInt32();
@@ -1492,6 +1502,11 @@ status_t SurfaceFlinger::onTransact(
setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
return NO_ERROR;
}
+ case 1006:{ // enable/disable GraphicLog
+ int enabled = data.readInt32();
+ GraphicLog::getInstance().setEnabled(enabled);
+ return NO_ERROR;
+ }
case 1007: // set mFreezeCount
mFreezeCount = data.readInt32();
mFreezeDisplayTime = 0;
diff --git a/telephony/java/android/telephony/gsm/GsmCellLocation.java b/telephony/java/android/telephony/gsm/GsmCellLocation.java
index c4204fa..313bc82 100644
--- a/telephony/java/android/telephony/gsm/GsmCellLocation.java
+++ b/telephony/java/android/telephony/gsm/GsmCellLocation.java
@@ -60,8 +60,10 @@ public class GsmCellLocation extends CellLocation {
}
/**
+ * On a UMTS network, returns the primary scrambling code of the serving
+ * cell.
+ *
* @return primary scrambling code for UMTS, -1 if unknown or GSM
- * @hide
*/
public int getPsc() {
return mPsc;
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 4bf3282..8bd789c 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -24,6 +24,7 @@ import android.os.AsyncResult;
import android.os.Handler;
import android.os.Message;
import android.os.RegistrantList;
+import android.os.Registrant;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.util.Log;
@@ -75,6 +76,7 @@ public final class CallManager {
private static final int EVENT_SUBSCRIPTION_INFO_READY = 116;
private static final int EVENT_SUPP_SERVICE_FAILED = 117;
private static final int EVENT_SERVICE_STATE_CHANGED = 118;
+ private static final int EVENT_POST_DIAL_CHARACTER = 119;
// Singleton instance
private static final CallManager INSTANCE = new CallManager();
@@ -158,6 +160,9 @@ public final class CallManager {
protected final RegistrantList mServiceStateChangedRegistrants
= new RegistrantList();
+ protected final RegistrantList mPostDialCharacterRegistrants
+ = new RegistrantList();
+
private CallManager() {
mPhones = new ArrayList<Phone>();
mRingingCalls = new ArrayList<Call>();
@@ -334,6 +339,7 @@ public final class CallManager {
}
private void registerForPhoneStates(Phone phone) {
+ // for common events supported by all phones
phone.registerForPreciseCallStateChanged(mHandler, EVENT_PRECISE_CALL_STATE_CHANGED, null);
phone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null);
phone.registerForNewRingingConnection(mHandler, EVENT_NEW_RINGING_CONNECTION, null);
@@ -342,20 +348,31 @@ public final class CallManager {
phone.registerForRingbackTone(mHandler, EVENT_RINGBACK_TONE, null);
phone.registerForInCallVoicePrivacyOn(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_ON, null);
phone.registerForInCallVoicePrivacyOff(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_OFF, null);
- phone.registerForCallWaiting(mHandler, EVENT_CALL_WAITING, null);
phone.registerForDisplayInfo(mHandler, EVENT_DISPLAY_INFO, null);
phone.registerForSignalInfo(mHandler, EVENT_SIGNAL_INFO, null);
- phone.registerForCdmaOtaStatusChange(mHandler, EVENT_CDMA_OTA_STATUS_CHANGE, null);
phone.registerForResendIncallMute(mHandler, EVENT_RESEND_INCALL_MUTE, null);
phone.registerForMmiInitiate(mHandler, EVENT_MMI_INITIATE, null);
phone.registerForMmiComplete(mHandler, EVENT_MMI_COMPLETE, null);
- phone.registerForEcmTimerReset(mHandler, EVENT_ECM_TIMER_RESET, null);
- phone.registerForSubscriptionInfoReady(mHandler, EVENT_SUBSCRIPTION_INFO_READY, null);
phone.registerForSuppServiceFailed(mHandler, EVENT_SUPP_SERVICE_FAILED, null);
phone.registerForServiceStateChanged(mHandler, EVENT_SERVICE_STATE_CHANGED, null);
+
+ // for events supported only by GSM and CDMA phone
+ if (phone.getPhoneType() == Phone.PHONE_TYPE_GSM ||
+ phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) {
+ phone.setOnPostDialCharacter(mHandler, EVENT_POST_DIAL_CHARACTER, null);
+ }
+
+ // for events supported only by CDMA phone
+ if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA ){
+ phone.registerForCdmaOtaStatusChange(mHandler, EVENT_CDMA_OTA_STATUS_CHANGE, null);
+ phone.registerForSubscriptionInfoReady(mHandler, EVENT_SUBSCRIPTION_INFO_READY, null);
+ phone.registerForCallWaiting(mHandler, EVENT_CALL_WAITING, null);
+ phone.registerForEcmTimerReset(mHandler, EVENT_ECM_TIMER_RESET, null);
+ }
}
private void unregisterForPhoneStates(Phone phone) {
+ // for common events supported by all phones
phone.unregisterForPreciseCallStateChanged(mHandler);
phone.unregisterForDisconnect(mHandler);
phone.unregisterForNewRingingConnection(mHandler);
@@ -364,17 +381,27 @@ public final class CallManager {
phone.unregisterForRingbackTone(mHandler);
phone.unregisterForInCallVoicePrivacyOn(mHandler);
phone.unregisterForInCallVoicePrivacyOff(mHandler);
- phone.unregisterForCallWaiting(mHandler);
phone.unregisterForDisplayInfo(mHandler);
phone.unregisterForSignalInfo(mHandler);
- phone.unregisterForCdmaOtaStatusChange(mHandler);
phone.unregisterForResendIncallMute(mHandler);
phone.unregisterForMmiInitiate(mHandler);
phone.unregisterForMmiComplete(mHandler);
- phone.unregisterForEcmTimerReset(mHandler);
- phone.unregisterForSubscriptionInfoReady(mHandler);
phone.unregisterForSuppServiceFailed(mHandler);
phone.unregisterForServiceStateChanged(mHandler);
+
+ // for events supported only by GSM and CDMA phone
+ if (phone.getPhoneType() == Phone.PHONE_TYPE_GSM ||
+ phone.getPhoneType() == Phone.PHONE_TYPE_CDMA) {
+ phone.setOnPostDialCharacter(null, EVENT_POST_DIAL_CHARACTER, null);
+ }
+
+ // for events supported only by CDMA phone
+ if (phone.getPhoneType() == Phone.PHONE_TYPE_CDMA ){
+ phone.unregisterForCdmaOtaStatusChange(mHandler);
+ phone.unregisterForSubscriptionInfoReady(mHandler);
+ phone.unregisterForCallWaiting(mHandler);
+ phone.unregisterForEcmTimerReset(mHandler);
+ }
}
/**
@@ -1132,6 +1159,46 @@ public final class CallManager {
mSubscriptionInfoReadyRegistrants.remove(h);
}
+ /**
+ * Sets an event to be fired when the telephony system processes
+ * a post-dial character on an outgoing call.<p>
+ *
+ * Messages of type <code>what</code> will be sent to <code>h</code>.
+ * The <code>obj</code> field of these Message's will be instances of
+ * <code>AsyncResult</code>. <code>Message.obj.result</code> will be
+ * a Connection object.<p>
+ *
+ * Message.arg1 will be the post dial character being processed,
+ * or 0 ('\0') if end of string.<p>
+ *
+ * If Connection.getPostDialState() == WAIT,
+ * the application must call
+ * {@link com.android.internal.telephony.Connection#proceedAfterWaitChar()
+ * Connection.proceedAfterWaitChar()} or
+ * {@link com.android.internal.telephony.Connection#cancelPostDial()
+ * Connection.cancelPostDial()}
+ * for the telephony system to continue playing the post-dial
+ * DTMF sequence.<p>
+ *
+ * If Connection.getPostDialState() == WILD,
+ * the application must call
+ * {@link com.android.internal.telephony.Connection#proceedAfterWildChar
+ * Connection.proceedAfterWildChar()}
+ * or
+ * {@link com.android.internal.telephony.Connection#cancelPostDial()
+ * Connection.cancelPostDial()}
+ * for the telephony system to continue playing the
+ * post-dial DTMF sequence.<p>
+ *
+ */
+ public void registerForPostDialCharacter(Handler h, int what, Object obj){
+ mPostDialCharacterRegistrants.addUnique(h, what, obj);
+ }
+
+ public void unregisterForPostDialCharacter(Handler h){
+ mPostDialCharacterRegistrants.remove(h);
+ }
+
/* APIs to access foregroudCalls, backgroudCalls, and ringingCalls
* 1. APIs to access list of calls
* 2. APIs to check if any active call, which has connection other than
@@ -1144,22 +1211,22 @@ public final class CallManager {
/**
* @return list of all ringing calls
*/
- public ArrayList<Call> getRingingCalls() {
- return mRingingCalls;
+ public List<Call> getRingingCalls() {
+ return Collections.unmodifiableList(mRingingCalls);
}
/**
* @return list of all foreground calls
*/
- public ArrayList<Call> getForegroundCalls() {
- return mForegroundCalls;
+ public List<Call> getForegroundCalls() {
+ return Collections.unmodifiableList(mForegroundCalls);
}
/**
* @return list of all background calls
*/
- public ArrayList<Call> getBackgroundCalls() {
- return mBackgroundCalls;
+ public List<Call> getBackgroundCalls() {
+ return Collections.unmodifiableList(mBackgroundCalls);
}
/**
@@ -1269,7 +1336,7 @@ public final class CallManager {
/**
* @return the connections of active foreground call
- * return null if there is no active foreground call
+ * return empty list if there is no active foreground call
*/
public List<Connection> getFgCallConnections() {
Call fgCall = getActiveFgCall();
@@ -1408,6 +1475,18 @@ public final class CallManager {
break;
case EVENT_SERVICE_STATE_CHANGED:
mServiceStateChangedRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+ break;
+ case EVENT_POST_DIAL_CHARACTER:
+ // we need send the character that is being processed in msg.arg1
+ // so can't use notifyRegistrants()
+ for(int i=0; i < mPostDialCharacterRegistrants.size(); i++) {
+ Message notifyMsg;
+ notifyMsg = ((Registrant)mPostDialCharacterRegistrants.get(i)).messageForRegistrant();
+ notifyMsg.obj = msg.obj;
+ notifyMsg.arg1 = msg.arg1;
+ notifyMsg.sendToTarget();
+ }
+ break;
}
}
};
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index 2c99145..943f21c 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -635,9 +635,9 @@ public class SipPhone extends SipPhoneBase {
@Override
protected void onError(DisconnectCause cause) {
Log.w(LOG_TAG, "SIP error: " + cause);
- if (mSipAudioCall.isInCall()) {
- // Don't end the call when in call.
- // TODO: how to deliver the error to PhoneApp
+ if (mSipAudioCall.isInCall()
+ && (cause != DisconnectCause.LOST_SIGNAL)) {
+ // Don't end the call when in a call.
return;
}
@@ -819,9 +819,9 @@ public class SipPhone extends SipPhoneBase {
}
@Override
- public void onError(SipAudioCall call, String errorCode,
+ public void onError(SipAudioCall call, SipErrorCode errorCode,
String errorMessage) {
- switch (Enum.valueOf(SipErrorCode.class, errorCode)) {
+ switch (errorCode) {
case INVALID_REMOTE_URI:
onError(Connection.DisconnectCause.INVALID_NUMBER);
break;
@@ -829,6 +829,9 @@ public class SipPhone extends SipPhoneBase {
case TRANSACTION_TERMINTED:
onError(Connection.DisconnectCause.TIMED_OUT);
break;
+ case DATA_CONNECTION_LOST:
+ onError(Connection.DisconnectCause.LOST_SIGNAL);
+ break;
case INVALID_CREDENTIALS:
onError(Connection.DisconnectCause.INVALID_CREDENTIALS);
break;
diff --git a/tests/CoreTests/android/core/SSLPerformanceTest.java b/tests/CoreTests/android/core/SSLPerformanceTest.java
index fd87e89..5b5be0a 100644
--- a/tests/CoreTests/android/core/SSLPerformanceTest.java
+++ b/tests/CoreTests/android/core/SSLPerformanceTest.java
@@ -211,17 +211,17 @@ public class SSLPerformanceTest extends AndroidTestCase {
deleteDirectory();
OpenSSLContextImpl sslContext = new OpenSSLContextImpl();
- sslContext.engineInit(null, null, null,
- FileClientSessionCache.usingDirectory(getCacheDirectory()),
- null);
+ sslContext.engineInit(null, null, null);
+ sslContext.engineGetClientSessionContext().setPersistentCache(
+ FileClientSessionCache.usingDirectory(getCacheDirectory()));
// Make sure www.google.com is in the cache.
getVerisignDotCom(sslContext);
// Re-initialize so we hit the file cache.
- sslContext.engineInit(null, null, null,
- FileClientSessionCache.usingDirectory(getCacheDirectory()),
- null);
+ sslContext.engineInit(null, null, null);
+ sslContext.engineGetClientSessionContext().setPersistentCache(
+ FileClientSessionCache.usingDirectory(getCacheDirectory()));
Stopwatch stopwatch = new Stopwatch();
diff --git a/tests/CoreTests/android/core/SSLSocketTest.java b/tests/CoreTests/android/core/SSLSocketTest.java
index 021df80..03905e1 100644
--- a/tests/CoreTests/android/core/SSLSocketTest.java
+++ b/tests/CoreTests/android/core/SSLSocketTest.java
@@ -911,7 +911,8 @@ public class SSLSocketTest extends TestCase {
// Cache size = 2.
FakeClientSessionCache fakeCache = new FakeClientSessionCache();
- context.engineInit(null, null, null, fakeCache, null);
+ context.engineInit(null, null, null);
+ context.engineGetClientSessionContext().setPersistentCache(fakeCache);
SSLSocketFactory socketFactory = context.engineGetSocketFactory();
context.engineGetClientSessionContext().setSessionCacheSize(2);
makeRequests(socketFactory);
@@ -933,7 +934,8 @@ public class SSLSocketTest extends TestCase {
// Cache size = 3.
fakeCache = new FakeClientSessionCache();
- context.engineInit(null, null, null, fakeCache, null);
+ context.engineInit(null, null, null);
+ context.engineGetClientSessionContext().setPersistentCache(fakeCache);
socketFactory = context.engineGetSocketFactory();
context.engineGetClientSessionContext().setSessionCacheSize(3);
makeRequests(socketFactory);
@@ -952,7 +954,8 @@ public class SSLSocketTest extends TestCase {
// Cache size = 4.
fakeCache = new FakeClientSessionCache();
- context.engineInit(null, null, null, fakeCache, null);
+ context.engineInit(null, null, null);
+ context.engineGetClientSessionContext().setPersistentCache(fakeCache);
socketFactory = context.engineGetSocketFactory();
context.engineGetClientSessionContext().setSessionCacheSize(4);
makeRequests(socketFactory);
@@ -1010,7 +1013,8 @@ public class SSLSocketTest extends TestCase {
try {
ClientSessionCacheProxy cacheProxy
= new ClientSessionCacheProxy(fileCache);
- context.engineInit(null, null, null, cacheProxy, null);
+ context.engineInit(null, null, null);
+ context.engineGetClientSessionContext().setPersistentCache(cacheProxy);
SSLSocketFactory socketFactory = context.engineGetSocketFactory();
context.engineGetClientSessionContext().setSessionCacheSize(1);
makeRequests(socketFactory);
@@ -1033,7 +1037,8 @@ public class SSLSocketTest extends TestCase {
// Try again now that file-based cache is populated.
fileCache = FileClientSessionCache.usingDirectory(cacheDir);
cacheProxy = new ClientSessionCacheProxy(fileCache);
- context.engineInit(null, null, null, cacheProxy, null);
+ context.engineInit(null, null, null);
+ context.engineGetClientSessionContext().setPersistentCache(cacheProxy);
socketFactory = context.engineGetSocketFactory();
context.engineGetClientSessionContext().setSessionCacheSize(1);
makeRequests(socketFactory);
diff --git a/voip/java/android/net/sip/ISipSession.aidl b/voip/java/android/net/sip/ISipSession.aidl
index 1a23527..29fcb32 100644
--- a/voip/java/android/net/sip/ISipSession.aidl
+++ b/voip/java/android/net/sip/ISipSession.aidl
@@ -17,7 +17,6 @@
package android.net.sip;
import android.net.sip.ISipSessionListener;
-import android.net.sip.SessionDescription;
import android.net.sip.SipProfile;
/**
diff --git a/voip/java/android/net/sip/SipAudioCall.java b/voip/java/android/net/sip/SipAudioCall.java
index 39083a5..1d1be69 100644
--- a/voip/java/android/net/sip/SipAudioCall.java
+++ b/voip/java/android/net/sip/SipAudioCall.java
@@ -88,10 +88,11 @@ public interface SipAudioCall {
* Called when an error occurs.
*
* @param call the call object that carries out the audio call
- * @param errorCode error code defined in {@link SipErrorCode}
+ * @param errorCode error code of this error
* @param errorMessage error message
*/
- void onError(SipAudioCall call, String errorCode, String errorMessage);
+ void onError(SipAudioCall call, SipErrorCode errorCode,
+ String errorMessage);
}
/**
@@ -125,7 +126,7 @@ public interface SipAudioCall {
public void onCallHeld(SipAudioCall call) {
onChanged(call);
}
- public void onError(SipAudioCall call, String errorCode,
+ public void onError(SipAudioCall call, SipErrorCode errorCode,
String errorMessage) {
onChanged(call);
}
diff --git a/voip/java/android/net/sip/SipAudioCallImpl.java b/voip/java/android/net/sip/SipAudioCallImpl.java
index 67ba97f..8bf486a 100644
--- a/voip/java/android/net/sip/SipAudioCallImpl.java
+++ b/voip/java/android/net/sip/SipAudioCallImpl.java
@@ -79,6 +79,9 @@ public class SipAudioCallImpl extends SipSessionAdapter
private WifiManager mWm;
private WifiManager.WifiLock mWifiHighPerfLock;
+ private SipErrorCode mErrorCode;
+ private String mErrorMessage;
+
public SipAudioCallImpl(Context context, SipProfile localProfile) {
mContext = context;
mLocalProfile = localProfile;
@@ -92,23 +95,33 @@ public class SipAudioCallImpl extends SipSessionAdapter
public void setListener(SipAudioCall.Listener listener,
boolean callbackImmediately) {
mListener = listener;
- if ((listener == null) || !callbackImmediately) return;
try {
- SipSessionState state = getState();
- switch (state) {
- case READY_TO_CALL:
- listener.onReadyToCall(this);
- break;
- case INCOMING_CALL:
- listener.onRinging(this, getPeerProfile(mSipSession));
- startRinging();
- break;
- case OUTGOING_CALL:
- listener.onCalling(this);
- break;
- default:
- listener.onError(this, SipErrorCode.CLIENT_ERROR.toString(),
- "wrong state to attach call: " + state);
+ if ((listener == null) || !callbackImmediately) {
+ // do nothing
+ } else if (mErrorCode != null) {
+ listener.onError(this, mErrorCode, mErrorMessage);
+ } else if (mInCall) {
+ if (mHold) {
+ listener.onCallHeld(this);
+ } else {
+ listener.onCallEstablished(this);
+ }
+ } else {
+ SipSessionState state = getState();
+ switch (state) {
+ case READY_TO_CALL:
+ listener.onReadyToCall(this);
+ break;
+ case INCOMING_CALL:
+ listener.onRinging(this, getPeerProfile(mSipSession));
+ break;
+ case OUTGOING_CALL:
+ listener.onCalling(this);
+ break;
+ case OUTGOING_CALL_RING_BACK:
+ listener.onRingingBack(this);
+ break;
+ }
}
} catch (Throwable t) {
Log.e(TAG, "setListener()", t);
@@ -135,6 +148,8 @@ public class SipAudioCallImpl extends SipSessionAdapter
mInCall = false;
mHold = false;
mSessionId = -1L;
+ mErrorCode = null;
+ mErrorMessage = null;
}
public synchronized SipProfile getLocalProfile() {
@@ -169,7 +184,7 @@ public class SipAudioCallImpl extends SipSessionAdapter
Listener listener = mListener;
if (listener != null) {
try {
- listener.onCalling(SipAudioCallImpl.this);
+ listener.onCalling(this);
} catch (Throwable t) {
Log.e(TAG, "onCalling()", t);
}
@@ -183,7 +198,7 @@ public class SipAudioCallImpl extends SipSessionAdapter
Listener listener = mListener;
if (listener != null) {
try {
- listener.onRingingBack(SipAudioCallImpl.this);
+ listener.onRingingBack(this);
} catch (Throwable t) {
Log.e(TAG, "onRingingBack()", t);
}
@@ -236,9 +251,9 @@ public class SipAudioCallImpl extends SipSessionAdapter
if (listener != null) {
try {
if (mHold) {
- listener.onCallHeld(SipAudioCallImpl.this);
+ listener.onCallHeld(this);
} else {
- listener.onCallEstablished(SipAudioCallImpl.this);
+ listener.onCallEstablished(this);
}
} catch (Throwable t) {
Log.e(TAG, "onCallEstablished()", t);
@@ -253,7 +268,7 @@ public class SipAudioCallImpl extends SipSessionAdapter
Listener listener = mListener;
if (listener != null) {
try {
- listener.onCallEnded(SipAudioCallImpl.this);
+ listener.onCallEnded(this);
} catch (Throwable t) {
Log.e(TAG, "onCallEnded()", t);
}
@@ -267,21 +282,27 @@ public class SipAudioCallImpl extends SipSessionAdapter
Listener listener = mListener;
if (listener != null) {
try {
- listener.onCallBusy(SipAudioCallImpl.this);
+ listener.onCallBusy(this);
} catch (Throwable t) {
Log.e(TAG, "onCallBusy()", t);
}
}
}
+ private SipErrorCode getErrorCode(String errorCode) {
+ return Enum.valueOf(SipErrorCode.class, errorCode);
+ }
+
@Override
public void onCallChangeFailed(ISipSession session, String errorCode,
String message) {
Log.d(TAG, "sip call change failed: " + message);
+ mErrorCode = getErrorCode(errorCode);
+ mErrorMessage = message;
Listener listener = mListener;
if (listener != null) {
try {
- listener.onError(SipAudioCallImpl.this, errorCode, message);
+ listener.onError(this, mErrorCode, message);
} catch (Throwable t) {
Log.e(TAG, "onCallBusy()", t);
}
@@ -289,16 +310,21 @@ public class SipAudioCallImpl extends SipSessionAdapter
}
@Override
- public void onError(ISipSession session, String errorCode,
+ public void onError(ISipSession session, String errorCodeString,
String message) {
- Log.d(TAG, "sip session error: " + errorCode + ": " + message);
+ Log.d(TAG, "sip session error: " + errorCodeString + ": " + message);
+ SipErrorCode errorCode = mErrorCode = getErrorCode(errorCodeString);
+ mErrorMessage = message;
synchronized (this) {
- if (!isInCall()) close(true);
+ if ((mErrorCode == SipErrorCode.DATA_CONNECTION_LOST)
+ || !isInCall()) {
+ close(true);
+ }
}
Listener listener = mListener;
if (listener != null) {
try {
- listener.onError(SipAudioCallImpl.this, errorCode, message);
+ listener.onError(this, errorCode, message);
} catch (Throwable t) {
Log.e(TAG, "onError()", t);
}
@@ -311,6 +337,8 @@ public class SipAudioCallImpl extends SipSessionAdapter
try {
mPeerSd = new SdpSessionDescription(sessionDescription);
session.setListener(this);
+
+ if (getState() == SipSessionState.INCOMING_CALL) startRinging();
} catch (Throwable e) {
Log.e(TAG, "attachCall()", e);
throwSipException(e);
diff --git a/voip/java/android/net/sip/SipErrorCode.java b/voip/java/android/net/sip/SipErrorCode.java
index 8624811..963733e 100644
--- a/voip/java/android/net/sip/SipErrorCode.java
+++ b/voip/java/android/net/sip/SipErrorCode.java
@@ -47,5 +47,8 @@ public enum SipErrorCode {
INVALID_CREDENTIALS,
/** The client is in a transaction and cannot initiate a new one. */
- IN_PROGRESS;
+ IN_PROGRESS,
+
+ /** When data connection is lost. */
+ DATA_CONNECTION_LOST;
}
diff --git a/voip/java/android/net/sip/SipManager.java b/voip/java/android/net/sip/SipManager.java
index ccae7f9..149053c 100644
--- a/voip/java/android/net/sip/SipManager.java
+++ b/voip/java/android/net/sip/SipManager.java
@@ -502,13 +502,14 @@ public class SipManager {
@Override
public void onRegistrationFailed(ISipSession session, String errorCode,
String message) {
- mListener.onRegistrationFailed(getUri(session), errorCode, message);
+ mListener.onRegistrationFailed(getUri(session),
+ Enum.valueOf(SipErrorCode.class, errorCode), message);
}
@Override
public void onRegistrationTimeout(ISipSession session) {
mListener.onRegistrationFailed(getUri(session),
- SipErrorCode.TIME_OUT.toString(), "registration timed out");
+ SipErrorCode.TIME_OUT, "registration timed out");
}
}
}
diff --git a/voip/java/android/net/sip/SipProfile.java b/voip/java/android/net/sip/SipProfile.java
index aa2da75..1a7d8bf 100644
--- a/voip/java/android/net/sip/SipProfile.java
+++ b/voip/java/android/net/sip/SipProfile.java
@@ -167,11 +167,15 @@ public class SipProfile implements Parcelable, Serializable, Cloneable {
*
* @param port port number of the server
* @return this builder object
- * @throws InvalidArgumentException if the port number is out of range
+ * @throws IllegalArgumentException if the port number is out of range
*/
- public Builder setPort(int port) throws InvalidArgumentException {
- mUri.setPort(port);
- return this;
+ public Builder setPort(int port) throws IllegalArgumentException {
+ try {
+ mUri.setPort(port);
+ return this;
+ } catch (InvalidArgumentException e) {
+ throw new IllegalArgumentException(e);
+ }
}
/**
@@ -180,16 +184,16 @@ public class SipProfile implements Parcelable, Serializable, Cloneable {
*
* @param protocol the protocol string
* @return this builder object
- * @throws InvalidArgumentException if the protocol is not recognized
+ * @throws IllegalArgumentException if the protocol is not recognized
*/
public Builder setProtocol(String protocol)
- throws InvalidArgumentException {
+ throws IllegalArgumentException {
if (protocol == null) {
throw new NullPointerException("protocol cannot be null");
}
protocol = protocol.toUpperCase();
if (!protocol.equals("UDP") && !protocol.equals("TCP")) {
- throw new InvalidArgumentException(
+ throw new IllegalArgumentException(
"unsupported protocol: " + protocol);
}
mProfile.mProtocol = protocol;
diff --git a/voip/java/android/net/sip/SipRegistrationListener.java b/voip/java/android/net/sip/SipRegistrationListener.java
index 22488d7..e751e46 100644
--- a/voip/java/android/net/sip/SipRegistrationListener.java
+++ b/voip/java/android/net/sip/SipRegistrationListener.java
@@ -40,9 +40,9 @@ public interface SipRegistrationListener {
* Called when the registration fails.
*
* @param localProfileUri the URI string of the SIP profile to register with
- * @param errorCode error code defined in {@link SipErrorCode}
+ * @param errorCode error code of this error
* @param errorMessage error message
*/
- void onRegistrationFailed(String localProfileUri, String errorCode,
+ void onRegistrationFailed(String localProfileUri, SipErrorCode errorCode,
String errorMessage);
}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 6e0bc9d..0ee559e 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -21,6 +21,8 @@ import android.net.wifi.WifiConfiguration;
import android.net.wifi.ScanResult;
import android.net.DhcpInfo;
+import android.os.WorkSource;
+
/**
* Interface that allows controlling and querying Wi-Fi connectivity.
*
@@ -66,7 +68,9 @@ interface IWifiManager
DhcpInfo getDhcpInfo();
- boolean acquireWifiLock(IBinder lock, int lockType, String tag);
+ boolean acquireWifiLock(IBinder lock, int lockType, String tag, in WorkSource ws);
+
+ void updateWifiLockWorkSource(IBinder lock, in WorkSource ws);
boolean releaseWifiLock(IBinder lock);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 9d21521..dd162f2 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -23,6 +23,7 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.Handler;
import android.os.RemoteException;
+import android.os.WorkSource;
import java.util.List;
@@ -872,6 +873,7 @@ public class WifiManager {
int mLockType;
private boolean mRefCounted;
private boolean mHeld;
+ private WorkSource mWorkSource;
private WifiLock(int lockType, String tag) {
mTag = tag;
@@ -897,7 +899,7 @@ public class WifiManager {
synchronized (mBinder) {
if (mRefCounted ? (++mRefCount > 0) : (!mHeld)) {
try {
- mService.acquireWifiLock(mBinder, mLockType, mTag);
+ mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource);
synchronized (WifiManager.this) {
if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
mService.releaseWifiLock(mBinder);
@@ -969,6 +971,32 @@ public class WifiManager {
}
}
+ public void setWorkSource(WorkSource ws) {
+ synchronized (mBinder) {
+ if (ws != null && ws.size() == 0) {
+ ws = null;
+ }
+ boolean changed = true;
+ if (ws == null) {
+ mWorkSource = null;
+ } else if (mWorkSource == null) {
+ changed = mWorkSource != null;
+ mWorkSource = new WorkSource(ws);
+ } else {
+ changed = mWorkSource.diff(ws);
+ if (changed) {
+ mWorkSource.set(ws);
+ }
+ }
+ if (changed && mHeld) {
+ try {
+ mService.updateWifiLockWorkSource(mBinder, mWorkSource);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+
public String toString() {
String s1, s2, s3;
synchronized (mBinder) {