Merge "Adds OWNERS file to TouchLatency Test: Presumits BUG: 241152647 Change-Id: I15e0c757472fffdb5f6b808a8d9a35657455c229"
diff --git a/MULTIUSER_OWNERS b/MULTIUSER_OWNERS
index 9d92e0f..b8857ec 100644
--- a/MULTIUSER_OWNERS
+++ b/MULTIUSER_OWNERS
@@ -1,5 +1,9 @@
# OWNERS of Multiuser related files
+annabauza@google.com
bookatz@google.com
+nykkumar@google.com
olilan@google.com
omakoto@google.com
+tetianameronyk@google.com
+tyk@google.com
yamasani@google.com
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp
index 2cda57d..8b8d361 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.cpp
+++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp
@@ -18,24 +18,22 @@
#include "com_android_commands_hid_Device.h"
-#include <linux/uhid.h>
-
+#include <android-base/stringprintf.h>
+#include <android/looper.h>
#include <fcntl.h>
#include <inttypes.h>
-#include <unistd.h>
-#include <cstdio>
-#include <cstring>
-#include <memory>
-
-#include <android/looper.h>
#include <jni.h>
+#include <linux/uhid.h>
#include <log/log.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalRef.h>
#include <nativehelper/ScopedPrimitiveArray.h>
#include <nativehelper/ScopedUtfChars.h>
+#include <unistd.h>
-#include <android-base/stringprintf.h>
+#include <cstdio>
+#include <cstring>
+#include <memory>
// Log debug messages about the output.
static constexpr bool DEBUG_OUTPUT = false;
@@ -109,15 +107,15 @@
void DeviceCallback::onDeviceGetReport(uint32_t requestId, uint8_t reportId) {
JNIEnv* env = getJNIEnv();
- env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceGetReport,
- requestId, reportId);
+ env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceGetReport, requestId,
+ reportId);
checkAndClearException(env, "onDeviceGetReport");
}
-void DeviceCallback::onDeviceSetReport(uint8_t rType,
- const std::vector<uint8_t>& data) {
+void DeviceCallback::onDeviceSetReport(uint32_t id, uint8_t rType,
+ const std::vector<uint8_t>& data) {
JNIEnv* env = getJNIEnv();
- env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceSetReport, rType,
+ env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceSetReport, id, rType,
toJbyteArray(env, data).get());
checkAndClearException(env, "onDeviceSetReport");
}
@@ -236,6 +234,14 @@
writeEvent(mFd, ev, "UHID_GET_REPORT_REPLY");
}
+void Device::sendSetReportReply(uint32_t id, bool success) const {
+ struct uhid_event ev = {};
+ ev.type = UHID_SET_REPORT_REPLY;
+ ev.u.set_report_reply.id = id;
+ ev.u.set_report_reply.err = success ? 0 : EIO;
+ writeEvent(mFd, ev, "UHID_SET_REPORT_REPLY");
+}
+
int Device::handleEvents(int events) {
if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
ALOGE("uhid node was closed or an error occurred. events=0x%x", events);
@@ -249,7 +255,6 @@
mDeviceCallback->onDeviceError();
return 0;
}
-
switch (ev.type) {
case UHID_OPEN: {
mDeviceCallback->onDeviceOpen();
@@ -271,7 +276,7 @@
ALOGD("Received SET_REPORT: id=%" PRIu32 " rnum=%" PRIu8 " data=%s", set_report.id,
set_report.rnum, toString(data).c_str());
}
- mDeviceCallback->onDeviceSetReport(set_report.rtype, data);
+ mDeviceCallback->onDeviceSetReport(set_report.id, set_report.rtype, data);
break;
}
case UHID_OUTPUT: {
@@ -347,6 +352,15 @@
}
}
+static void sendSetReportReply(JNIEnv*, jclass /* clazz */, jlong ptr, jint id, jboolean success) {
+ uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
+ if (d) {
+ d->sendSetReportReply(id, success);
+ } else {
+ ALOGE("Could not send set report reply, Device* is null!");
+ }
+}
+
static void closeDevice(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) {
uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
if (d) {
@@ -362,6 +376,7 @@
{"nativeSendReport", "(J[B)V", reinterpret_cast<void*>(sendReport)},
{"nativeSendGetFeatureReportReply", "(JI[B)V",
reinterpret_cast<void*>(sendGetFeatureReportReply)},
+ {"nativeSendSetReportReply", "(JIZ)V", reinterpret_cast<void*>(sendSetReportReply)},
{"nativeCloseDevice", "(J)V", reinterpret_cast<void*>(closeDevice)},
};
@@ -376,7 +391,7 @@
uhid::gDeviceCallbackClassInfo.onDeviceGetReport =
env->GetMethodID(clazz, "onDeviceGetReport", "(II)V");
uhid::gDeviceCallbackClassInfo.onDeviceSetReport =
- env->GetMethodID(clazz, "onDeviceSetReport", "(B[B)V");
+ env->GetMethodID(clazz, "onDeviceSetReport", "(IB[B)V");
uhid::gDeviceCallbackClassInfo.onDeviceOutput =
env->GetMethodID(clazz, "onDeviceOutput", "(B[B)V");
uhid::gDeviceCallbackClassInfo.onDeviceError =
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.h b/cmds/hid/jni/com_android_commands_hid_Device.h
index d10a9aa..9c6060d 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.h
+++ b/cmds/hid/jni/com_android_commands_hid_Device.h
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-#include <memory>
-#include <vector>
-
+#include <android-base/unique_fd.h>
#include <jni.h>
-#include <android-base/unique_fd.h>
+#include <memory>
+#include <vector>
namespace android {
namespace uhid {
@@ -31,7 +30,7 @@
void onDeviceOpen();
void onDeviceGetReport(uint32_t requestId, uint8_t reportId);
- void onDeviceSetReport(uint8_t rType, const std::vector<uint8_t>& data);
+ void onDeviceSetReport(uint32_t id, uint8_t rType, const std::vector<uint8_t>& data);
void onDeviceOutput(uint8_t rType, const std::vector<uint8_t>& data);
void onDeviceError();
@@ -50,9 +49,9 @@
~Device();
void sendReport(const std::vector<uint8_t>& report) const;
+ void sendSetReportReply(uint32_t id, bool success) const;
void sendGetFeatureReportReply(uint32_t id, const std::vector<uint8_t>& report) const;
void close();
-
int handleEvents(int events);
private:
diff --git a/cmds/hid/src/com/android/commands/hid/Device.java b/cmds/hid/src/com/android/commands/hid/Device.java
index 95b1e9a..0415037 100644
--- a/cmds/hid/src/com/android/commands/hid/Device.java
+++ b/cmds/hid/src/com/android/commands/hid/Device.java
@@ -42,7 +42,8 @@
private static final int MSG_OPEN_DEVICE = 1;
private static final int MSG_SEND_REPORT = 2;
private static final int MSG_SEND_GET_FEATURE_REPORT_REPLY = 3;
- private static final int MSG_CLOSE_DEVICE = 4;
+ private static final int MSG_SEND_SET_REPORT_REPLY = 4;
+ private static final int MSG_CLOSE_DEVICE = 5;
// Sync with linux uhid_event_type::UHID_OUTPUT
private static final byte UHID_EVENT_TYPE_UHID_OUTPUT = 6;
@@ -56,21 +57,45 @@
private final Map<ByteBuffer, byte[]> mOutputs;
private final OutputStream mOutputStream;
private long mTimeToSend;
-
private final Object mCond = new Object();
+ /**
+ * The report id of the report received in UHID_EVENT_TYPE_SET_REPORT.
+ * Used for SET_REPORT_REPLY.
+ * This field gets overridden each time SET_REPORT is received.
+ */
+ private int mResponseId;
static {
System.loadLibrary("hidcommand_jni");
}
- private static native long nativeOpenDevice(String name, int id, int vid, int pid, int bus,
- byte[] descriptor, DeviceCallback callback);
+ private static native long nativeOpenDevice(
+ String name,
+ int id,
+ int vid,
+ int pid,
+ int bus,
+ byte[] descriptor,
+ DeviceCallback callback);
+
private static native void nativeSendReport(long ptr, byte[] data);
+
private static native void nativeSendGetFeatureReportReply(long ptr, int id, byte[] data);
+
+ private static native void nativeSendSetReportReply(long ptr, int id, boolean success);
+
private static native void nativeCloseDevice(long ptr);
- public Device(int id, String name, int vid, int pid, int bus, byte[] descriptor,
- byte[] report, SparseArray<byte[]> featureReports, Map<ByteBuffer, byte[]> outputs) {
+ public Device(
+ int id,
+ String name,
+ int vid,
+ int pid,
+ int bus,
+ byte[] descriptor,
+ byte[] report,
+ SparseArray<byte[]> featureReports,
+ Map<ByteBuffer, byte[]> outputs) {
mId = id;
mThread = new HandlerThread("HidDeviceHandler");
mThread.start();
@@ -100,6 +125,17 @@
mHandler.sendMessageAtTime(msg, mTimeToSend);
}
+ public void setGetReportResponse(byte[] report) {
+ mFeatureReports.put(report[0], report);
+ }
+
+ public void sendSetReportReply(boolean success) {
+ Message msg =
+ mHandler.obtainMessage(MSG_SEND_SET_REPORT_REPLY, mResponseId, success ? 1 : 0);
+
+ mHandler.sendMessageAtTime(msg, mTimeToSend);
+ }
+
public void addDelay(int delay) {
mTimeToSend = Math.max(SystemClock.uptimeMillis(), mTimeToSend) + delay;
}
@@ -111,7 +147,8 @@
synchronized (mCond) {
mCond.wait();
}
- } catch (InterruptedException ignore) {}
+ } catch (InterruptedException ignore) {
+ }
}
private class DeviceHandler extends Handler {
@@ -127,8 +164,15 @@
switch (msg.what) {
case MSG_OPEN_DEVICE:
SomeArgs args = (SomeArgs) msg.obj;
- mPtr = nativeOpenDevice((String) args.arg1, args.argi1, args.argi2, args.argi3,
- args.argi4, (byte[]) args.arg2, new DeviceCallback());
+ mPtr =
+ nativeOpenDevice(
+ (String) args.arg1,
+ args.argi1,
+ args.argi2,
+ args.argi3,
+ args.argi4,
+ (byte[]) args.arg2,
+ new DeviceCallback());
pauseEvents();
break;
case MSG_SEND_REPORT:
@@ -145,6 +189,14 @@
Log.e(TAG, "Tried to send feature report reply to closed device.");
}
break;
+ case MSG_SEND_SET_REPORT_REPLY:
+ if (mPtr != 0) {
+ final boolean success = msg.arg2 == 1;
+ nativeSendSetReportReply(mPtr, msg.arg1, success);
+ } else {
+ Log.e(TAG, "Tried to send set report reply to closed device.");
+ }
+ break;
case MSG_CLOSE_DEVICE:
if (mPtr != 0) {
nativeCloseDevice(mPtr);
@@ -173,14 +225,18 @@
}
private class DeviceCallback {
+
public void onDeviceOpen() {
mHandler.resumeEvents();
}
public void onDeviceGetReport(int requestId, int reportId) {
if (mFeatureReports == null) {
- Log.e(TAG, "Received GET_REPORT request for reportId=" + reportId
- + ", but 'feature_reports' section is not found");
+ Log.e(
+ TAG,
+ "Received GET_REPORT request for reportId="
+ + reportId
+ + ", but 'feature_reports' section is not found");
return;
}
byte[] report = mFeatureReports.get(reportId);
@@ -220,14 +276,15 @@
} catch (IOException e) {
throw new RuntimeException(e);
}
-
}
// native callback
- public void onDeviceSetReport(byte rtype, byte[] data) {
+ public void onDeviceSetReport(int id, byte rType, byte[] data) {
+ // Used by sendSetReportReply()
+ mResponseId = id;
// We don't need to reply for the SET_REPORT but just send it to HID output for test
// verification.
- sendReportOutput(UHID_EVENT_TYPE_SET_REPORT, rtype, data);
+ sendReportOutput(UHID_EVENT_TYPE_SET_REPORT, rType, data);
}
// native callback
@@ -239,7 +296,8 @@
}
byte[] response = mOutputs.get(ByteBuffer.wrap(data));
if (response == null) {
- Log.i(TAG,
+ Log.i(
+ TAG,
"Requested response for output " + Arrays.toString(data) + " is not found");
return;
}
diff --git a/cmds/hid/src/com/android/commands/hid/Event.java b/cmds/hid/src/com/android/commands/hid/Event.java
index d4bf1d8..3efb797 100644
--- a/cmds/hid/src/com/android/commands/hid/Event.java
+++ b/cmds/hid/src/com/android/commands/hid/Event.java
@@ -35,6 +35,8 @@
public static final String COMMAND_REGISTER = "register";
public static final String COMMAND_DELAY = "delay";
public static final String COMMAND_REPORT = "report";
+ public static final String COMMAND_SET_GET_REPORT_RESPONSE = "set_get_report_response";
+ public static final String COMMAND_SEND_SET_REPORT_REPLY = "send_set_report_reply";
// These constants come from "include/uapi/linux/input.h" in the kernel
enum Bus {
@@ -62,6 +64,7 @@
private SparseArray<byte[]> mFeatureReports;
private Map<ByteBuffer, byte[]> mOutputs;
private int mDuration;
+ private Boolean mReply;
public int getId() {
return mId;
@@ -107,6 +110,10 @@
return mDuration;
}
+ public Boolean getReply() {
+ return mReply;
+ }
+
public String toString() {
return "Event{id=" + mId
+ ", command=" + String.valueOf(mCommand)
@@ -119,6 +126,7 @@
+ ", feature_reports=" + mFeatureReports.toString()
+ ", outputs=" + mOutputs.toString()
+ ", duration=" + mDuration
+ + ", success=" + mReply.toString()
+ "}";
}
@@ -173,6 +181,10 @@
mEvent.mDuration = duration;
}
+ public void setReply(boolean success) {
+ mEvent.mReply = success;
+ }
+
public Event build() {
if (mEvent.mId == -1) {
throw new IllegalStateException("No event id");
@@ -183,6 +195,16 @@
if (mEvent.mDescriptor == null) {
throw new IllegalStateException("Device registration is missing descriptor");
}
+ }
+ if (COMMAND_SET_GET_REPORT_RESPONSE.equals(mEvent.mCommand)) {
+ if (mEvent.mReport == null) {
+ throw new IllegalStateException("Report command is missing response data");
+ }
+ }
+ if (COMMAND_SEND_SET_REPORT_REPLY.equals(mEvent.mCommand)) {
+ if (mEvent.mReply == null) {
+ throw new IllegalStateException("Reply command is missing reply");
+ }
} else if (COMMAND_DELAY.equals(mEvent.mCommand)) {
if (mEvent.mDuration <= 0) {
throw new IllegalStateException("Delay has missing or invalid duration");
@@ -246,6 +268,9 @@
case "duration":
eb.setDuration(readInt());
break;
+ case "success":
+ eb.setReply(readBool());
+ break;
default:
mReader.skipValue();
}
@@ -292,6 +317,11 @@
return Integer.decode(val);
}
+ private boolean readBool() throws IOException {
+ String val = mReader.nextString();
+ return Boolean.parseBoolean(val);
+ }
+
private Bus readBus() throws IOException {
String val = mReader.nextString();
return Bus.valueOf(val.toUpperCase());
diff --git a/cmds/hid/src/com/android/commands/hid/Hid.java b/cmds/hid/src/com/android/commands/hid/Hid.java
index fac0ab2..2db791fe 100644
--- a/cmds/hid/src/com/android/commands/hid/Hid.java
+++ b/cmds/hid/src/com/android/commands/hid/Hid.java
@@ -93,6 +93,10 @@
d.addDelay(e.getDuration());
} else if (Event.COMMAND_REPORT.equals(e.getCommand())) {
d.sendReport(e.getReport());
+ } else if (Event.COMMAND_SET_GET_REPORT_RESPONSE.equals(e.getCommand())) {
+ d.setGetReportResponse(e.getReport());
+ } else if (Event.COMMAND_SEND_SET_REPORT_REPLY.equals(e.getCommand())) {
+ d.sendSetReportReply(e.getReply());
} else {
if (Event.COMMAND_REGISTER.equals(e.getCommand())) {
error("Device id=" + e.getId() + " is already registered. Ignoring event.");
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 0a6a405..2c0be87 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -541,7 +541,8 @@
}
public void postUpdateSlider(int volume, int lastAudibleVolume, boolean mute) {
- obtainMessage(UPDATE_SLIDER, volume, lastAudibleVolume, new Boolean(mute)).sendToTarget();
+ obtainMessage(UPDATE_SLIDER, volume, lastAudibleVolume, Boolean.valueOf(mute))
+ .sendToTarget();
}
}
diff --git a/core/java/android/security/keymaster/OWNERS b/core/java/android/security/keymaster/OWNERS
index 65129a4..c4d605c 100644
--- a/core/java/android/security/keymaster/OWNERS
+++ b/core/java/android/security/keymaster/OWNERS
@@ -1,5 +1,5 @@
# Bug component: 189335
swillden@google.com
-jdanis@google.com
+eranm@google.com
jbires@google.com
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index ea5f0b2..b1e7d15 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -1001,24 +1001,16 @@
}
/**
- * This will enable jdwp by default for all apps. It is OK to cache this property
- * because we expect to reboot the system whenever this property changes
- */
- private static final boolean ENABLE_JDWP = SystemProperties.get(
- "persist.debuggable.dalvik.vm.jdwp.enabled").equals("1");
-
- /**
* Applies debugger system properties to the zygote arguments.
*
- * For eng builds all apps are debuggable. On userdebug and user builds
- * if persist.debuggable.dalvik.vm.jdwp.enabled is 1 all apps are
- * debuggable. Otherwise, the debugger state is specified via the
- * "--enable-jdwp" flag in the spawn request.
+ * If "ro.debuggable" is "1", all apps are debuggable. Otherwise,
+ * the debugger state is specified via the "--enable-jdwp" flag
+ * in the spawn request.
*
* @param args non-null; zygote spawner args
*/
static void applyDebuggerSystemProperty(ZygoteArguments args) {
- if (Build.IS_ENG || ENABLE_JDWP) {
+ if (RoSystemProperties.DEBUGGABLE) {
args.mRuntimeFlags |= Zygote.DEBUG_ENABLE_JDWP;
}
}
diff --git a/media/jni/audioeffect/Android.bp b/media/jni/audioeffect/Android.bp
index 2ddfacf..8b5b726 100644
--- a/media/jni/audioeffect/Android.bp
+++ b/media/jni/audioeffect/Android.bp
@@ -28,7 +28,7 @@
"libaudioclient",
"libaudioutils",
"libaudiofoundation",
- "libbinder"
+ "libbinder",
],
export_shared_lib_headers: [
@@ -42,6 +42,7 @@
"-Werror",
"-Wunused",
"-Wunreachable-code",
+ "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
],
// Workaround Clang LTO crash.
diff --git a/media/jni/audioeffect/Visualizer.cpp b/media/jni/audioeffect/Visualizer.cpp
index d0f1ec6..09c45ea 100644
--- a/media/jni/audioeffect/Visualizer.cpp
+++ b/media/jni/audioeffect/Visualizer.cpp
@@ -142,7 +142,8 @@
mCaptureRate = rate;
if (cbk != NULL) {
- mCaptureThread = new CaptureThread(this, rate, ((flags & CAPTURE_CALL_JAVA) != 0));
+ mCaptureThread = sp<CaptureThread>::make(
+ sp<Visualizer>::fromExisting(this), rate, ((flags & CAPTURE_CALL_JAVA) != 0));
}
ALOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x",
rate, mCaptureThread.get(), mCaptureFlags);
@@ -439,7 +440,7 @@
//-------------------------------------------------------------------------
-Visualizer::CaptureThread::CaptureThread(Visualizer* receiver, uint32_t captureRate,
+Visualizer::CaptureThread::CaptureThread(const sp<Visualizer>& receiver, uint32_t captureRate,
bool bCanCallJava)
: Thread(bCanCallJava), mReceiver(receiver)
{
diff --git a/media/jni/audioeffect/Visualizer.h b/media/jni/audioeffect/Visualizer.h
index 3d5d74a..b38c01f 100644
--- a/media/jni/audioeffect/Visualizer.h
+++ b/media/jni/audioeffect/Visualizer.h
@@ -157,7 +157,8 @@
class CaptureThread : public Thread
{
public:
- CaptureThread(Visualizer* visualizer, uint32_t captureRate, bool bCanCallJava = false);
+ CaptureThread(const sp<Visualizer>& visualizer,
+ uint32_t captureRate, bool bCanCallJava = false);
private:
friend class Visualizer;
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index 2fb85a7..63e48aa 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -205,15 +205,15 @@
Mutex::Autolock l(sLock);
AudioEffect* const ae =
(AudioEffect*)env->GetLongField(thiz, fields.fidNativeAudioEffect);
- return sp<AudioEffect>(ae);
+ return sp<AudioEffect>::fromExisting(ae);
}
static sp<AudioEffect> setAudioEffect(JNIEnv* env, jobject thiz,
const sp<AudioEffect>& ae)
{
Mutex::Autolock l(sLock);
- sp<AudioEffect> old =
- (AudioEffect*)env->GetLongField(thiz, fields.fidNativeAudioEffect);
+ sp<AudioEffect> old = sp<AudioEffect>::fromExisting(
+ (AudioEffect*)env->GetLongField(thiz, fields.fidNativeAudioEffect));
if (ae.get()) {
ae->incStrong((void*)setAudioEffect);
}
@@ -347,8 +347,8 @@
// create the native AudioEffect object
parcel = parcelForJavaObject(env, jAttributionSource);
attributionSource.readFromParcel(parcel);
- lpAudioEffect = new AudioEffect(attributionSource);
- if (lpAudioEffect == 0) {
+ lpAudioEffect = sp<AudioEffect>::make(attributionSource);
+ if (lpAudioEffect == 0) { // FIXME: I don't think this is actually possible.
ALOGE("Error creating AudioEffect");
goto setup_failure;
}
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index 7b00f93..8cd6dfa 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -251,15 +251,15 @@
Mutex::Autolock l(sLock);
Visualizer* const v =
(Visualizer*)env->GetLongField(thiz, fields.fidNativeVisualizer);
- return sp<Visualizer>(v);
+ return sp<Visualizer>::fromExisting(v);
}
static sp<Visualizer> setVisualizer(JNIEnv* env, jobject thiz,
const sp<Visualizer>& v)
{
Mutex::Autolock l(sLock);
- sp<Visualizer> old =
- (Visualizer*)env->GetLongField(thiz, fields.fidNativeVisualizer);
+ sp<Visualizer> old = sp<Visualizer>::fromExisting(
+ (Visualizer*)env->GetLongField(thiz, fields.fidNativeVisualizer));
if (v.get()) {
v->incStrong((void*)setVisualizer);
}
diff --git a/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java b/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java
index 129810c..5db6000 100644
--- a/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java
+++ b/services/core/java/com/android/server/timedetector/GnssTimeUpdateService.java
@@ -18,21 +18,26 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.app.AlarmManager;
import android.app.timedetector.GnssTimeSuggestion;
import android.app.timedetector.TimeDetector;
import android.content.Context;
-import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationManagerInternal;
import android.location.LocationRequest;
import android.location.LocationTime;
import android.os.Binder;
+import android.os.Handler;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
import android.os.SystemClock;
import android.os.TimestampedValue;
+import android.util.LocalLog;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.server.FgThread;
@@ -42,6 +47,8 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.time.Duration;
+import java.util.Objects;
+import java.util.concurrent.Executor;
/**
* Monitors the GNSS time.
@@ -66,7 +73,15 @@
@Override
public void onStart() {
- mService = new GnssTimeUpdateService(getContext());
+ Context context = getContext().createAttributionContext(ATTRIBUTION_TAG);
+ AlarmManager alarmManager = context.getSystemService(AlarmManager.class);
+ LocationManager locationManager = context.getSystemService(LocationManager.class);
+ LocationManagerInternal locationManagerInternal =
+ LocalServices.getService(LocationManagerInternal.class);
+ TimeDetector timeDetector = context.getSystemService(TimeDetector.class);
+
+ mService = new GnssTimeUpdateService(context, alarmManager, locationManager,
+ locationManagerInternal, timeDetector);
publishBinderService("gnss_time_update_service", mService);
}
@@ -79,7 +94,7 @@
// Instead of polling GNSS time periodically, passive location updates are enabled.
// Once an update is received, the gnss time will be queried and suggested to
// TimeDetectorService.
- mService.requestGnssTimeUpdates();
+ mService.startGnssListeningInternal();
}
}
}
@@ -87,107 +102,169 @@
private static final Duration GNSS_TIME_UPDATE_ALARM_INTERVAL = Duration.ofHours(4);
private static final String ATTRIBUTION_TAG = "GnssTimeUpdateService";
+ /**
+ * A log that records the decisions to fetch a GNSS time update.
+ * This is logged in bug reports to assist with debugging issues with GNSS time suggestions.
+ */
+ private final LocalLog mLocalLog = new LocalLog(10, false /* useLocalTimestamps */);
+ /** The executor used for async operations */
+ private final Executor mExecutor = FgThread.getExecutor();
+ /** The handler used for async operations */
+ private final Handler mHandler = FgThread.getHandler();
+
private final Context mContext;
private final TimeDetector mTimeDetector;
private final AlarmManager mAlarmManager;
private final LocationManager mLocationManager;
private final LocationManagerInternal mLocationManagerInternal;
- @Nullable private AlarmManager.OnAlarmListener mAlarmListener;
- @Nullable private LocationListener mLocationListener;
- @Nullable private TimestampedValue<Long> mLastSuggestedGnssTime;
+
+ private final Object mLock = new Object();
+ @GuardedBy("mLock") @Nullable private AlarmManager.OnAlarmListener mAlarmListener;
+ @GuardedBy("mLock") @Nullable private LocationListener mLocationListener;
+
+ @Nullable private volatile TimestampedValue<Long> mLastSuggestedGnssTime;
@VisibleForTesting
- GnssTimeUpdateService(@NonNull Context context) {
- mContext = context.createAttributionContext(ATTRIBUTION_TAG);
- mTimeDetector = mContext.getSystemService(TimeDetector.class);
- mLocationManager = mContext.getSystemService(LocationManager.class);
- mAlarmManager = mContext.getSystemService(AlarmManager.class);
- mLocationManagerInternal = LocalServices.getService(LocationManagerInternal.class);
+ GnssTimeUpdateService(@NonNull Context context, @NonNull AlarmManager alarmManager,
+ @NonNull LocationManager locationManager,
+ @NonNull LocationManagerInternal locationManagerInternal,
+ @NonNull TimeDetector timeDetector) {
+ mContext = Objects.requireNonNull(context);
+ mAlarmManager = Objects.requireNonNull(alarmManager);
+ mLocationManager = Objects.requireNonNull(locationManager);
+ mLocationManagerInternal = Objects.requireNonNull(locationManagerInternal);
+ mTimeDetector = Objects.requireNonNull(timeDetector);
}
/**
- * Request passive location updates. Such a request will not trigger any active locations or
- * power usage itself.
+ * Used by {@link com.android.server.timedetector.GnssTimeUpdateServiceShellCommand} to force
+ * the service into GNSS listening mode.
+ */
+ @RequiresPermission(android.Manifest.permission.SET_TIME)
+ boolean startGnssListening() {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.SET_TIME, "Start GNSS listening");
+ mLocalLog.log("startGnssListening() called");
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return startGnssListeningInternal();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ /**
+ * Starts listening for passive location updates. Such a request will not trigger any active
+ * locations or power usage itself. Returns {@code true} if the service is listening after the
+ * method returns and {@code false} otherwise. At present this method only returns {@code false}
+ * if there is no GPS provider on the device.
+ *
+ * <p>If the service is already listening for locations this is a no-op. If the device is in a
+ * "sleeping" state between listening periods then it will return to listening.
*/
@VisibleForTesting
- void requestGnssTimeUpdates() {
- if (D) {
- Log.d(TAG, "requestGnssTimeUpdates()");
+ boolean startGnssListeningInternal() {
+ if (!mLocationManager.hasProvider(LocationManager.GPS_PROVIDER)) {
+ logError("GPS provider does not exist on this device");
+ return false;
}
- if (!mLocationManager.hasProvider(LocationManager.GPS_PROVIDER)) {
- Log.e(TAG, "GPS provider does not exist on this device");
- return;
+ synchronized (mLock) {
+ if (mLocationListener != null) {
+ logDebug("Already listening for GNSS updates");
+ return true;
+ }
+
+ // If startGnssListening() is called during manual tests to jump back into location
+ // listening then there will usually be an alarm set.
+ if (mAlarmListener != null) {
+ mAlarmManager.cancel(mAlarmListener);
+ mAlarmListener = null;
+ }
+
+ startGnssListeningLocked();
+ return true;
}
+ }
+
+ @GuardedBy("mLock")
+ private void startGnssListeningLocked() {
+ logDebug("startGnssListeningLocked()");
// Location Listener triggers onLocationChanged() when GNSS data is available, so
// that the getGnssTimeMillis() function doesn't need to be continuously polled.
- mLocationListener = new LocationListener() {
- @Override
- public void onLocationChanged(Location location) {
- if (D) {
- Log.d(TAG, "onLocationChanged()");
- }
-
- // getGnssTimeMillis() can return null when the Master Location Switch for the
- // foreground user is disabled.
- LocationTime locationTime = mLocationManagerInternal.getGnssTimeMillis();
- if (locationTime != null) {
- suggestGnssTime(locationTime);
- } else {
- if (D) {
- Log.d(TAG, "getGnssTimeMillis() returned null");
- }
- }
-
- mLocationManager.removeUpdates(mLocationListener);
- mLocationListener = null;
-
- mAlarmListener = new AlarmManager.OnAlarmListener() {
- @Override
- public void onAlarm() {
- if (D) {
- Log.d(TAG, "onAlarm()");
- }
- mAlarmListener = null;
- requestGnssTimeUpdates();
- }
- };
-
- // Set next alarm to re-enable location updates.
- long next = SystemClock.elapsedRealtime()
- + GNSS_TIME_UPDATE_ALARM_INTERVAL.toMillis();
- mAlarmManager.set(
- AlarmManager.ELAPSED_REALTIME_WAKEUP,
- next,
- TAG,
- mAlarmListener,
- FgThread.getHandler());
- }
- };
-
+ mLocationListener = location -> handleLocationAvailable();
mLocationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
new LocationRequest.Builder(LocationRequest.PASSIVE_INTERVAL)
.setMinUpdateIntervalMillis(0)
.build(),
- FgThread.getExecutor(),
+ mExecutor,
mLocationListener);
}
+ private void handleLocationAvailable() {
+ logDebug("handleLocationAvailable()");
+
+ // getGnssTimeMillis() can return null when the Master Location Switch for the
+ // foreground user is disabled.
+ LocationTime locationTime = mLocationManagerInternal.getGnssTimeMillis();
+ if (locationTime != null) {
+ String msg = "Passive location time received: " + locationTime;
+ logDebug(msg);
+ mLocalLog.log(msg);
+ suggestGnssTime(locationTime);
+ } else {
+ logDebug("getGnssTimeMillis() returned null");
+ }
+
+ synchronized (mLock) {
+ if (mLocationListener == null) {
+ logWarning("mLocationListener unexpectedly null");
+ } else {
+ mLocationManager.removeUpdates(mLocationListener);
+ mLocationListener = null;
+ }
+
+ if (mAlarmListener != null) {
+ logWarning("mAlarmListener was unexpectedly non-null");
+ mAlarmManager.cancel(mAlarmListener);
+ }
+
+ // Set next alarm to re-enable location updates.
+ long next = SystemClock.elapsedRealtime()
+ + GNSS_TIME_UPDATE_ALARM_INTERVAL.toMillis();
+ mAlarmListener = this::handleAlarmFired;
+ mAlarmManager.set(
+ AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ next,
+ TAG,
+ mAlarmListener,
+ mHandler);
+ }
+ }
+
+ private void handleAlarmFired() {
+ logDebug("handleAlarmFired()");
+
+ synchronized (mLock) {
+ mAlarmListener = null;
+ startGnssListeningLocked();
+ }
+ }
+
/**
* Convert LocationTime to TimestampedValue. Then suggest TimestampedValue to Time Detector.
*/
private void suggestGnssTime(LocationTime locationTime) {
- if (D) {
- Log.d(TAG, "suggestGnssTime()");
- }
+ logDebug("suggestGnssTime()");
+
long gnssTime = locationTime.getTime();
long elapsedRealtimeMs = locationTime.getElapsedRealtimeNanos() / 1_000_000L;
- TimestampedValue<Long> timeSignal = new TimestampedValue<>(
- elapsedRealtimeMs, gnssTime);
+ TimestampedValue<Long> timeSignal = new TimestampedValue<>(elapsedRealtimeMs, gnssTime);
mLastSuggestedGnssTime = timeSignal;
GnssTimeSuggestion timeSuggestion = new GnssTimeSuggestion(timeSignal);
@@ -198,11 +275,38 @@
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
pw.println("mLastSuggestedGnssTime: " + mLastSuggestedGnssTime);
- pw.print("state: ");
- if (mLocationListener != null) {
- pw.println("time updates enabled");
- } else {
- pw.println("alarm enabled");
+ synchronized (mLock) {
+ pw.print("state: ");
+ if (mLocationListener != null) {
+ pw.println("time updates enabled");
+ } else {
+ pw.println("alarm enabled");
+ }
+ }
+ pw.println("Log:");
+ mLocalLog.dump(pw);
+ }
+
+ @Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+ String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
+ new GnssTimeUpdateServiceShellCommand(this).exec(
+ this, in, out, err, args, callback, resultReceiver);
+ }
+
+ private void logError(String msg) {
+ Log.e(TAG, msg);
+ mLocalLog.log(msg);
+ }
+
+ private void logWarning(String msg) {
+ Log.w(TAG, msg);
+ mLocalLog.log(msg);
+ }
+
+ private void logDebug(String msg) {
+ if (D) {
+ Log.d(TAG, msg);
}
}
}
diff --git a/services/core/java/com/android/server/timedetector/GnssTimeUpdateServiceShellCommand.java b/services/core/java/com/android/server/timedetector/GnssTimeUpdateServiceShellCommand.java
new file mode 100644
index 0000000..e757578
--- /dev/null
+++ b/services/core/java/com/android/server/timedetector/GnssTimeUpdateServiceShellCommand.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timedetector;
+
+import android.annotation.NonNull;
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+import java.util.Objects;
+
+/** Implements the shell command interface for {@link GnssTimeUpdateService}. */
+class GnssTimeUpdateServiceShellCommand extends ShellCommand {
+
+ /**
+ * The name of the service.
+ */
+ private static final String SHELL_COMMAND_SERVICE_NAME = "gnss_time_update_service";
+
+ /**
+ * A shell command that forces the service in to GNSS listening mode if it isn't already.
+ */
+ private static final String SHELL_COMMAND_START_GNSS_LISTENING = "start_gnss_listening";
+
+ @NonNull
+ private final GnssTimeUpdateService mGnssTimeUpdateService;
+
+ GnssTimeUpdateServiceShellCommand(GnssTimeUpdateService gnssTimeUpdateService) {
+ mGnssTimeUpdateService = Objects.requireNonNull(gnssTimeUpdateService);
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+
+ switch (cmd) {
+ case SHELL_COMMAND_START_GNSS_LISTENING:
+ return runStartGnssListening();
+ default: {
+ return handleDefaultCommands(cmd);
+ }
+ }
+ }
+
+ private int runStartGnssListening() {
+ boolean success = mGnssTimeUpdateService.startGnssListening();
+ getOutPrintWriter().println(success);
+ return 0;
+ }
+
+ @Override
+ public void onHelp() {
+ final PrintWriter pw = getOutPrintWriter();
+ pw.printf("Network Time Update Service (%s) commands:\n", SHELL_COMMAND_SERVICE_NAME);
+ pw.printf(" help\n");
+ pw.printf(" Print this help text.\n");
+ pw.printf(" %s\n", SHELL_COMMAND_START_GNSS_LISTENING);
+ pw.printf(" Forces the service in to GNSS listening mode (if it isn't already).\n");
+ pw.printf(" Prints true if the service is listening after this command.\n");
+ pw.println();
+ }
+}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 30b5083..c5f21eb 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -322,7 +322,7 @@
final int callingPid = Binder.getCallingPid();
// Validate and resolve ClipDescription data before clearing the calling identity
validateAndResolveDragMimeTypeExtras(data, callingUid, callingPid, mPackageName);
- validateDragFlags(flags, callingUid);
+ validateDragFlags(flags);
final long ident = Binder.clearCallingIdentity();
try {
return mDragDropController.performDrag(mPid, mUid, window, flags, surface, touchSource,
@@ -347,11 +347,7 @@
* Validates the given drag flags.
*/
@VisibleForTesting
- void validateDragFlags(int flags, int callingUid) {
- if (callingUid == Process.SYSTEM_UID) {
- throw new IllegalStateException("Need to validate before calling identify is cleared");
- }
-
+ void validateDragFlags(int flags) {
if ((flags & View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION) != 0) {
if (!mCanStartTasksFromRecents) {
throw new SecurityException("Requires START_TASKS_FROM_RECENTS permission");
@@ -365,9 +361,6 @@
@VisibleForTesting
void validateAndResolveDragMimeTypeExtras(ClipData data, int callingUid, int callingPid,
String callingPackage) {
- if (callingUid == Process.SYSTEM_UID) {
- throw new IllegalStateException("Need to validate before calling identify is cleared");
- }
final ClipDescription desc = data != null ? data.getDescription() : null;
if (desc == null) {
return;
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 3c68662..f05b1d4 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -218,6 +218,9 @@
BackgroundThread.get().getThreadHandler().post(
() -> {
try {
+ if (sSelfService.mIProfcollect == null) {
+ return;
+ }
sSelfService.mIProfcollect.process();
} catch (RemoteException e) {
Log.e(LOG_TAG, "Failed to process profiles in background: "
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java
index aad5cd6..030c58f 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/GnssTimeUpdateServiceTest.java
@@ -16,16 +16,18 @@
package com.android.server.timedetector;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyLong;
-import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import android.app.AlarmManager;
+import android.app.AlarmManager.OnAlarmListener;
import android.app.timedetector.GnssTimeSuggestion;
import android.app.timedetector.TimeDetector;
import android.content.Context;
@@ -39,9 +41,6 @@
import androidx.test.runner.AndroidJUnit4;
-import com.android.server.LocalServices;
-
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -59,7 +58,7 @@
@Mock private TimeDetector mMockTimeDetector;
@Mock private AlarmManager mMockAlarmManager;
@Mock private LocationManager mMockLocationManager;
- @Mock private LocationManagerInternal mLocationManagerInternal;
+ @Mock private LocationManagerInternal mMockLocationManagerInternal;
private GnssTimeUpdateService mGnssTimeUpdateService;
@@ -67,36 +66,11 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
- when(mMockContext.createAttributionContext(anyString()))
- .thenReturn(mMockContext);
+ installGpsProviderInMockLocationManager();
- when(mMockContext.getSystemServiceName(TimeDetector.class))
- .thenReturn((TimeDetector.class).getSimpleName());
- when(mMockContext.getSystemService(TimeDetector.class))
- .thenReturn(mMockTimeDetector);
-
- when(mMockContext.getSystemServiceName(LocationManager.class))
- .thenReturn((LocationManager.class).getSimpleName());
- when(mMockContext.getSystemService(LocationManager.class))
- .thenReturn(mMockLocationManager);
-
- when(mMockContext.getSystemServiceName(AlarmManager.class))
- .thenReturn((AlarmManager.class).getSimpleName());
- when(mMockContext.getSystemService(AlarmManager.class))
- .thenReturn(mMockAlarmManager);
-
- when(mMockLocationManager.hasProvider(LocationManager.GPS_PROVIDER))
- .thenReturn(true);
-
- LocalServices.addService(LocationManagerInternal.class, mLocationManagerInternal);
-
- mGnssTimeUpdateService =
- new GnssTimeUpdateService(mMockContext);
- }
-
- @After
- public void tearDown() {
- LocalServices.removeServiceForTest(LocationManagerInternal.class);
+ mGnssTimeUpdateService = new GnssTimeUpdateService(
+ mMockContext, mMockAlarmManager, mMockLocationManager, mMockLocationManagerInternal,
+ mMockTimeDetector);
}
@Test
@@ -105,11 +79,11 @@
ELAPSED_REALTIME_MS, GNSS_TIME);
GnssTimeSuggestion timeSuggestion = new GnssTimeSuggestion(timeSignal);
LocationTime locationTime = new LocationTime(GNSS_TIME, ELAPSED_REALTIME_NS);
- doReturn(locationTime).when(mLocationManagerInternal).getGnssTimeMillis();
+ doReturn(locationTime).when(mMockLocationManagerInternal).getGnssTimeMillis();
- mGnssTimeUpdateService.requestGnssTimeUpdates();
+ assertTrue(mGnssTimeUpdateService.startGnssListeningInternal());
- ArgumentCaptor<LocationListener> argumentCaptor =
+ ArgumentCaptor<LocationListener> locationListenerCaptor =
ArgumentCaptor.forClass(LocationListener.class);
verify(mMockLocationManager).requestLocationUpdates(
eq(LocationManager.GPS_PROVIDER),
@@ -117,8 +91,8 @@
.setMinUpdateIntervalMillis(0)
.build()),
any(),
- argumentCaptor.capture());
- LocationListener locationListener = argumentCaptor.getValue();
+ locationListenerCaptor.capture());
+ LocationListener locationListener = locationListenerCaptor.getValue();
Location location = new Location(LocationManager.GPS_PROVIDER);
locationListener.onLocationChanged(location);
@@ -135,11 +109,11 @@
@Test
public void testLocationListenerOnLocationChanged_nullLocationTime_doesNotSuggestGnssTime() {
- doReturn(null).when(mLocationManagerInternal).getGnssTimeMillis();
+ doReturn(null).when(mMockLocationManagerInternal).getGnssTimeMillis();
- mGnssTimeUpdateService.requestGnssTimeUpdates();
+ assertTrue(mGnssTimeUpdateService.startGnssListeningInternal());
- ArgumentCaptor<LocationListener> argumentCaptor =
+ ArgumentCaptor<LocationListener> locationListenerCaptor =
ArgumentCaptor.forClass(LocationListener.class);
verify(mMockLocationManager).requestLocationUpdates(
eq(LocationManager.GPS_PROVIDER),
@@ -147,14 +121,14 @@
.setMinUpdateIntervalMillis(0)
.build()),
any(),
- argumentCaptor.capture());
- LocationListener locationListener = argumentCaptor.getValue();
+ locationListenerCaptor.capture());
+ LocationListener locationListener = locationListenerCaptor.getValue();
Location location = new Location(LocationManager.GPS_PROVIDER);
locationListener.onLocationChanged(location);
verify(mMockLocationManager).removeUpdates(locationListener);
- verify(mMockTimeDetector, never()).suggestGnssTime(any());
+ verifyZeroInteractions(mMockTimeDetector);
verify(mMockAlarmManager).set(
eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
anyLong(),
@@ -162,4 +136,90 @@
any(),
any());
}
+
+ @Test
+ public void testLocationListeningRestartsAfterSleep() {
+ ArgumentCaptor<LocationListener> locationListenerCaptor =
+ ArgumentCaptor.forClass(LocationListener.class);
+ ArgumentCaptor<OnAlarmListener> alarmListenerCaptor =
+ ArgumentCaptor.forClass(OnAlarmListener.class);
+
+ advanceServiceToSleepingState(locationListenerCaptor, alarmListenerCaptor);
+
+ // Simulate the alarm manager's wake-up call.
+ OnAlarmListener wakeUpListener = alarmListenerCaptor.getValue();
+ wakeUpListener.onAlarm();
+
+ // Verify the service returned to location listening.
+ verify(mMockLocationManager).requestLocationUpdates(any(), any(), any(), any());
+ verifyZeroInteractions(mMockAlarmManager, mMockTimeDetector);
+ }
+
+ // Tests what happens when a call is made to startGnssListeningInternal() when service is
+ // sleeping. This can happen when the start_gnss_listening shell command is used.
+ @Test
+ public void testStartGnssListeningInternalCalledWhenSleeping() {
+ ArgumentCaptor<LocationListener> locationListenerCaptor =
+ ArgumentCaptor.forClass(LocationListener.class);
+ ArgumentCaptor<OnAlarmListener> alarmListenerCaptor =
+ ArgumentCaptor.forClass(OnAlarmListener.class);
+
+ advanceServiceToSleepingState(locationListenerCaptor, alarmListenerCaptor);
+
+ // Call startGnssListeningInternal(), as can happen if the start_gnss_listening shell
+ // command is used.
+ assertTrue(mGnssTimeUpdateService.startGnssListeningInternal());
+
+ // Verify the alarm manager is told to stopped sleeping and the location manager is
+ // listening again.
+ verify(mMockAlarmManager).cancel(alarmListenerCaptor.getValue());
+ verify(mMockLocationManager).requestLocationUpdates(any(), any(), any(), any());
+ verifyZeroInteractions(mMockTimeDetector);
+ }
+
+ private void advanceServiceToSleepingState(
+ ArgumentCaptor<LocationListener> locationListenerCaptor,
+ ArgumentCaptor<OnAlarmListener> alarmListenerCaptor) {
+ TimestampedValue<Long> timeSignal = new TimestampedValue<>(
+ ELAPSED_REALTIME_MS, GNSS_TIME);
+ GnssTimeSuggestion timeSuggestion = new GnssTimeSuggestion(timeSignal);
+ LocationTime locationTime = new LocationTime(GNSS_TIME, ELAPSED_REALTIME_NS);
+ doReturn(locationTime).when(mMockLocationManagerInternal).getGnssTimeMillis();
+
+ assertTrue(mGnssTimeUpdateService.startGnssListeningInternal());
+
+ verify(mMockLocationManager).requestLocationUpdates(
+ any(), any(), any(), locationListenerCaptor.capture());
+ LocationListener locationListener = locationListenerCaptor.getValue();
+ Location location = new Location(LocationManager.GPS_PROVIDER);
+ verifyZeroInteractions(mMockAlarmManager, mMockTimeDetector);
+
+ locationListener.onLocationChanged(location);
+
+ verify(mMockLocationManager).removeUpdates(locationListener);
+ verify(mMockTimeDetector).suggestGnssTime(timeSuggestion);
+
+ // Verify the service is now "sleeping", i.e. waiting for a period before listening for
+ // GNSS locations again.
+ verify(mMockAlarmManager).set(
+ eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+ anyLong(),
+ any(),
+ alarmListenerCaptor.capture(),
+ any());
+
+ // Reset mocks making it easier to verify the calls that follow.
+ reset(mMockAlarmManager, mMockTimeDetector, mMockLocationManager,
+ mMockLocationManagerInternal);
+ installGpsProviderInMockLocationManager();
+ }
+
+ /**
+ * Configures the mock response to ensure {@code
+ * locationManager.hasProvider(LocationManager.GPS_PROVIDER) == true }
+ */
+ private void installGpsProviderInMockLocationManager() {
+ when(mMockLocationManager.hasProvider(LocationManager.GPS_PROVIDER))
+ .thenReturn(true);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 28fc352..4526d18 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -467,8 +467,7 @@
public void onAnimatorScaleChanged(float scale) {}
});
try {
- session.validateDragFlags(View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION,
- TEST_UID);
+ session.validateDragFlags(View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION);
fail("Expected failure without permission");
} catch (SecurityException e) {
// Expected failure
@@ -484,8 +483,7 @@
public void onAnimatorScaleChanged(float scale) {}
});
try {
- session.validateDragFlags(View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION,
- TEST_UID);
+ session.validateDragFlags(View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION);
// Expected pass
} catch (SecurityException e) {
fail("Expected no failure with permission");