Merge "Add RequiresFeature annotation."
diff --git a/Android.mk b/Android.mk
index 3b8d6a8..58e21ff 100644
--- a/Android.mk
+++ b/Android.mk
@@ -793,6 +793,8 @@
$(call all-proto-files-under, core/proto) \
$(call all-proto-files-under, libs/incident/proto) \
$(call all-proto-files-under, cmds/statsd/src)
+# b/72714520
+LOCAL_ERROR_PRONE_FLAGS := -Xep:MissingOverride:OFF
include $(BUILD_HOST_JAVA_LIBRARY)
# ==== java proto device library (for test only) ==============================
diff --git a/api/current.txt b/api/current.txt
index df18f10..a70363d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -27998,23 +27998,23 @@
method public int updateNetwork(android.net.wifi.WifiConfiguration);
field public static final java.lang.String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
field public static final java.lang.String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
- field public static final int ERROR_AUTHENTICATING = 1; // 0x1
+ field public static final deprecated int ERROR_AUTHENTICATING = 1; // 0x1
field public static final deprecated java.lang.String EXTRA_BSSID = "bssid";
field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
field public static final java.lang.String EXTRA_NEW_RSSI = "newRssi";
- field public static final java.lang.String EXTRA_NEW_STATE = "newState";
+ field public static final deprecated java.lang.String EXTRA_NEW_STATE = "newState";
field public static final java.lang.String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
field public static final java.lang.String EXTRA_RESULTS_UPDATED = "resultsUpdated";
- field public static final java.lang.String EXTRA_SUPPLICANT_CONNECTED = "connected";
- field public static final java.lang.String EXTRA_SUPPLICANT_ERROR = "supplicantError";
+ field public static final deprecated java.lang.String EXTRA_SUPPLICANT_CONNECTED = "connected";
+ field public static final deprecated java.lang.String EXTRA_SUPPLICANT_ERROR = "supplicantError";
field public static final deprecated java.lang.String EXTRA_WIFI_INFO = "wifiInfo";
field public static final java.lang.String EXTRA_WIFI_STATE = "wifi_state";
field public static final java.lang.String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
field public static final java.lang.String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
field public static final java.lang.String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
field public static final java.lang.String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
- field public static final java.lang.String SUPPLICANT_CONNECTION_CHANGE_ACTION = "android.net.wifi.supplicant.CONNECTION_CHANGE";
- field public static final java.lang.String SUPPLICANT_STATE_CHANGED_ACTION = "android.net.wifi.supplicant.STATE_CHANGE";
+ field public static final deprecated java.lang.String SUPPLICANT_CONNECTION_CHANGE_ACTION = "android.net.wifi.supplicant.CONNECTION_CHANGE";
+ field public static final deprecated java.lang.String SUPPLICANT_STATE_CHANGED_ACTION = "android.net.wifi.supplicant.STATE_CHANGE";
field public static final int WIFI_MODE_FULL = 1; // 0x1
field public static final int WIFI_MODE_FULL_HIGH_PERF = 3; // 0x3
field public static final int WIFI_MODE_SCAN_ONLY = 2; // 0x2
@@ -28069,20 +28069,21 @@
method public abstract deprecated void onSucceeded();
}
- public class WpsInfo implements android.os.Parcelable {
- ctor public WpsInfo();
- ctor public WpsInfo(android.net.wifi.WpsInfo);
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field public java.lang.String BSSID;
- field public static final android.os.Parcelable.Creator<android.net.wifi.WpsInfo> CREATOR;
- field public static final int DISPLAY = 1; // 0x1
- field public static final int INVALID = 4; // 0x4
- field public static final int KEYPAD = 2; // 0x2
- field public static final int LABEL = 3; // 0x3
- field public static final int PBC = 0; // 0x0
- field public java.lang.String pin;
- field public int setup;
+ public deprecated class WpsInfo implements android.os.Parcelable {
+ ctor public deprecated WpsInfo();
+ ctor public deprecated WpsInfo(android.net.wifi.WpsInfo);
+ method public deprecated int describeContents();
+ method public deprecated java.lang.String toString();
+ method public deprecated void writeToParcel(android.os.Parcel, int);
+ field public deprecated java.lang.String BSSID;
+ field public static final deprecated android.os.Parcelable.Creator<android.net.wifi.WpsInfo> CREATOR;
+ field public static final deprecated int DISPLAY = 1; // 0x1
+ field public static final deprecated int INVALID = 4; // 0x4
+ field public static final deprecated int KEYPAD = 2; // 0x2
+ field public static final deprecated int LABEL = 3; // 0x3
+ field public static final deprecated int PBC = 0; // 0x0
+ field public deprecated java.lang.String pin;
+ field public deprecated int setup;
}
}
@@ -36640,6 +36641,7 @@
field public static final deprecated java.lang.String RADIO_NFC = "nfc";
field public static final deprecated java.lang.String RADIO_WIFI = "wifi";
field public static final java.lang.String RINGTONE = "ringtone";
+ field public static final java.lang.String RTT_CALLING_MODE = "rtt_calling_mode";
field public static final java.lang.String SCREEN_BRIGHTNESS = "screen_brightness";
field public static final java.lang.String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
field public static final int SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1; // 0x1
@@ -38449,6 +38451,7 @@
method public boolean isRandomizedEncryptionRequired();
method public boolean isStrongBoxBacked();
method public boolean isTrustedUserPresenceRequired();
+ method public boolean isUnlockedDeviceRequired();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationValidWhileOnBody();
method public boolean isUserConfirmationRequired();
@@ -38476,6 +38479,7 @@
method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setTrustedUserPresenceRequired(boolean);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
@@ -38567,6 +38571,8 @@
method public boolean isDigestsSpecified();
method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isRandomizedEncryptionRequired();
+ method public boolean isTrustedUserPresenceRequired();
+ method public boolean isUnlockedDeviceRequired();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationValidWhileOnBody();
method public boolean isUserConfirmationRequired();
@@ -38585,6 +38591,8 @@
method public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date);
method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
+ method public android.security.keystore.KeyProtection.Builder setTrustedUserPresenceRequired(boolean);
+ method public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int);
@@ -40645,6 +40653,7 @@
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
+ field public static final int PROPERTY_RTT = 1024; // 0x400
field public static final int PROPERTY_SELF_MANAGED = 256; // 0x100
field public static final int PROPERTY_WIFI = 8; // 0x8
}
@@ -44487,10 +44496,12 @@
public class TypefaceSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
ctor public TypefaceSpan(java.lang.String);
+ ctor public TypefaceSpan(android.graphics.Typeface);
ctor public TypefaceSpan(android.os.Parcel);
method public int describeContents();
method public java.lang.String getFamily();
method public int getSpanTypeId();
+ method public android.graphics.Typeface getTypeface();
method public void updateDrawState(android.text.TextPaint);
method public void updateMeasureState(android.text.TextPaint);
method public void writeToParcel(android.os.Parcel, int);
@@ -49795,6 +49806,8 @@
method public boolean isFieldClassificationEnabled();
method public void notifyValueChanged(android.view.View);
method public void notifyValueChanged(android.view.View, int, android.view.autofill.AutofillValue);
+ method public void notifyViewClicked(android.view.View);
+ method public void notifyViewClicked(android.view.View, int);
method public void notifyViewEntered(android.view.View);
method public void notifyViewEntered(android.view.View, int, android.graphics.Rect);
method public void notifyViewExited(android.view.View);
@@ -50302,6 +50315,7 @@
method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence);
method public default java.util.Collection<java.lang.String> getEntitiesForPreset(int);
method public default android.view.textclassifier.logging.Logger getLogger(android.view.textclassifier.logging.Logger.Config);
+ method public default int getMaxGenerateLinksTextLength();
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
@@ -50756,41 +50770,37 @@
}
public class TracingConfig {
- ctor public TracingConfig(int);
- ctor public TracingConfig(int, java.lang.String, int);
- method public java.lang.String getCustomCategoryPattern();
- method public int getPresetCategories();
+ method public java.util.List<java.lang.String> getCustomIncludedCategories();
+ method public int getPredefinedCategories();
method public int getTracingMode();
- field public static final int CATEGORIES_FRAME_VIEWER = 4; // 0x4
- field public static final int CATEGORIES_INPUT_LATENCY = 1; // 0x1
- field public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 3; // 0x3
- field public static final int CATEGORIES_NONE = -1; // 0xffffffff
- field public static final int CATEGORIES_RENDERING = 2; // 0x2
- field public static final int CATEGORIES_WEB_DEVELOPER = 0; // 0x0
+ field public static final int CATEGORIES_ALL = 1; // 0x1
+ field public static final int CATEGORIES_ANDROID_WEBVIEW = 2; // 0x2
+ field public static final int CATEGORIES_FRAME_VIEWER = 64; // 0x40
+ field public static final int CATEGORIES_INPUT_LATENCY = 8; // 0x8
+ field public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 32; // 0x20
+ field public static final int CATEGORIES_NONE = 0; // 0x0
+ field public static final int CATEGORIES_RENDERING = 16; // 0x10
+ field public static final int CATEGORIES_WEB_DEVELOPER = 4; // 0x4
field public static final int RECORD_CONTINUOUSLY = 1; // 0x1
- field public static final int RECORD_TO_CONSOLE = 3; // 0x3
field public static final int RECORD_UNTIL_FULL = 0; // 0x0
field public static final int RECORD_UNTIL_FULL_LARGE_BUFFER = 2; // 0x2
}
+ public static class TracingConfig.Builder {
+ ctor public TracingConfig.Builder();
+ method public android.webkit.TracingConfig.Builder addCategories(int...);
+ method public android.webkit.TracingConfig.Builder addCategories(java.lang.String...);
+ method public android.webkit.TracingConfig.Builder addCategories(java.util.Collection<java.lang.String>);
+ method public android.webkit.TracingConfig build();
+ method public android.webkit.TracingConfig.Builder setTracingMode(int);
+ }
+
public abstract class TracingController {
ctor public TracingController();
method public static android.webkit.TracingController getInstance();
method public abstract boolean isTracing();
- method public abstract boolean start(android.webkit.TracingConfig);
- method public abstract boolean stop();
- method public abstract boolean stopAndFlush(android.webkit.TracingController.TracingOutputStream, android.os.Handler);
- }
-
- public static abstract interface TracingController.TracingOutputStream {
- method public abstract void complete();
- method public abstract void write(byte[]);
- }
-
- public class TracingFileOutputStream implements android.webkit.TracingController.TracingOutputStream {
- ctor public TracingFileOutputStream(java.lang.String) throws java.io.FileNotFoundException;
- method public void complete();
- method public void write(byte[]);
+ method public abstract void start(android.webkit.TracingConfig);
+ method public abstract boolean stop(java.io.OutputStream, java.util.concurrent.Executor);
}
public final class URLUtil {
diff --git a/api/test-current.txt b/api/test-current.txt
index 9bfc105..2e47e00 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1061,6 +1061,7 @@
public final class AutofillId implements android.os.Parcelable {
ctor public AutofillId(int);
+ ctor public AutofillId(android.view.autofill.AutofillId, int);
}
}
diff --git a/cmds/incidentd/.clang-format b/cmds/incidentd/.clang-format
new file mode 100644
index 0000000..6fa5b47
--- /dev/null
+++ b/cmds/incidentd/.clang-format
@@ -0,0 +1,17 @@
+BasedOnStyle: Google
+AllowShortIfStatementsOnASingleLine: true
+AllowShortFunctionsOnASingleLine: true
+AllowShortLoopsOnASingleLine: true
+BinPackArguments: true
+BinPackParameters: true
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+ContinuationIndentWidth: 8
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+AccessModifierOffset: -4
+IncludeCategories:
+ - Regex: '^"Log\.h"'
+ Priority: -1
diff --git a/cmds/incidentd/Android.mk b/cmds/incidentd/Android.mk
index 23cd2af..d2d24c8 100644
--- a/cmds/incidentd/Android.mk
+++ b/cmds/incidentd/Android.mk
@@ -32,7 +32,7 @@
src/Privacy.cpp \
src/Reporter.cpp \
src/Section.cpp \
- src/io_util.cpp \
+ src/incidentd_util.cpp \
src/main.cpp \
src/report_directory.cpp
@@ -116,7 +116,7 @@
src/Privacy.cpp \
src/Reporter.cpp \
src/Section.cpp \
- src/io_util.cpp \
+ src/incidentd_util.cpp \
src/report_directory.cpp \
tests/section_list.cpp \
tests/PrivacyBuffer_test.cpp \
diff --git a/cmds/incidentd/README.md b/cmds/incidentd/README.md
index 71c6deb..1730a640 100644
--- a/cmds/incidentd/README.md
+++ b/cmds/incidentd/README.md
@@ -20,4 +20,8 @@
```
root$ atest incidentd_test
-```
\ No newline at end of file
+```
+
+Use clang-format to style the file
+
+clang-format -style=file -i <file list>
\ No newline at end of file
diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp
index 0fff4e6..883924c8 100644
--- a/cmds/incidentd/src/FdBuffer.cpp
+++ b/cmds/incidentd/src/FdBuffer.cpp
@@ -13,8 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "FdBuffer.h"
@@ -26,30 +25,16 @@
#include <unistd.h>
#include <wait.h>
-const bool DEBUG = false;
-const ssize_t BUFFER_SIZE = 16 * 1024; // 16 KB
-const ssize_t MAX_BUFFER_COUNT = 256; // 4 MB max
+const ssize_t BUFFER_SIZE = 16 * 1024; // 16 KB
+const ssize_t MAX_BUFFER_COUNT = 256; // 4 MB max
FdBuffer::FdBuffer()
- :mBuffer(BUFFER_SIZE),
- mStartTime(-1),
- mFinishTime(-1),
- mTimedOut(false),
- mTruncated(false)
-{
-}
+ : mBuffer(BUFFER_SIZE), mStartTime(-1), mFinishTime(-1), mTimedOut(false), mTruncated(false) {}
-FdBuffer::~FdBuffer()
-{
-}
+FdBuffer::~FdBuffer() {}
-status_t
-FdBuffer::read(int fd, int64_t timeout)
-{
- struct pollfd pfds = {
- .fd = fd,
- .events = POLLIN
- };
+status_t FdBuffer::read(int fd, int64_t timeout) {
+ struct pollfd pfds = {.fd = fd, .events = POLLIN};
mStartTime = uptimeMillis();
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
@@ -63,22 +48,22 @@
int64_t remainingTime = (mStartTime + timeout) - uptimeMillis();
if (remainingTime <= 0) {
- if (DEBUG) ALOGD("timed out due to long read");
+ VLOG("timed out due to long read");
mTimedOut = true;
break;
}
int count = poll(&pfds, 1, remainingTime);
if (count == 0) {
- if (DEBUG) ALOGD("timed out due to block calling poll");
+ VLOG("timed out due to block calling poll");
mTimedOut = true;
break;
} else if (count < 0) {
- if (DEBUG) ALOGD("poll failed: %s", strerror(errno));
+ VLOG("poll failed: %s", strerror(errno));
return -errno;
} else {
if ((pfds.revents & POLLERR) != 0) {
- if (DEBUG) ALOGD("return event has error %s", strerror(errno));
+ VLOG("return event has error %s", strerror(errno));
return errno != 0 ? -errno : UNKNOWN_ERROR;
} else {
ssize_t amt = ::read(fd, mBuffer.writeBuffer(), mBuffer.currentToWrite());
@@ -86,7 +71,7 @@
if (errno == EAGAIN || errno == EWOULDBLOCK) {
continue;
} else {
- if (DEBUG) ALOGD("Fail to read %d: %s", fd, strerror(errno));
+ VLOG("Fail to read %d: %s", fd, strerror(errno));
return -errno;
}
} else if (amt == 0) {
@@ -100,13 +85,12 @@
return NO_ERROR;
}
-status_t
-FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeoutMs, const bool isSysfs)
-{
+status_t FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeoutMs,
+ const bool isSysfs) {
struct pollfd pfds[] = {
- { .fd = fd, .events = POLLIN },
- { .fd = toFd, .events = POLLOUT },
- { .fd = fromFd, .events = POLLIN },
+ {.fd = fd, .events = POLLIN},
+ {.fd = toFd, .events = POLLOUT},
+ {.fd = fromFd, .events = POLLIN},
};
mStartTime = uptimeMillis();
@@ -131,7 +115,7 @@
int64_t remainingTime = (mStartTime + timeoutMs) - uptimeMillis();
if (remainingTime <= 0) {
- if (DEBUG) ALOGD("timed out due to long read");
+ VLOG("timed out due to long read");
mTimedOut = true;
break;
}
@@ -139,11 +123,11 @@
// wait for any pfds to be ready to perform IO
int count = poll(pfds, 3, remainingTime);
if (count == 0) {
- if (DEBUG) ALOGD("timed out due to block calling poll");
+ VLOG("timed out due to block calling poll");
mTimedOut = true;
break;
} else if (count < 0) {
- if (DEBUG) ALOGD("Fail to poll: %s", strerror(errno));
+ VLOG("Fail to poll: %s", strerror(errno));
return -errno;
}
@@ -151,10 +135,10 @@
for (int i = 0; i < 3; ++i) {
if ((pfds[i].revents & POLLERR) != 0) {
if (i == 0 && isSysfs) {
- if (DEBUG) ALOGD("fd %d is sysfs, ignore its POLLERR return value", fd);
+ VLOG("fd %d is sysfs, ignore its POLLERR return value", fd);
continue;
}
- if (DEBUG) ALOGD("fd[%d]=%d returns error events: %s", i, fd, strerror(errno));
+ VLOG("fd[%d]=%d returns error events: %s", i, fd, strerror(errno));
return errno != 0 ? -errno : UNKNOWN_ERROR;
}
}
@@ -169,9 +153,9 @@
}
if (amt < 0) {
if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
- if (DEBUG) ALOGD("Fail to read fd %d: %s", fd, strerror(errno));
+ VLOG("Fail to read fd %d: %s", fd, strerror(errno));
return -errno;
- } // otherwise just continue
+ } // otherwise just continue
} else if (amt == 0) { // reach EOF so don't have to poll pfds[0].
::close(pfds[0].fd);
pfds[0].fd = -1;
@@ -191,9 +175,9 @@
}
if (amt < 0) {
if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
- if (DEBUG) ALOGD("Fail to write toFd %d: %s", toFd, strerror(errno));
+ VLOG("Fail to write toFd %d: %s", toFd, strerror(errno));
return -errno;
- } // otherwise just continue
+ } // otherwise just continue
} else {
wpos += amt;
cirSize -= amt;
@@ -218,9 +202,9 @@
ssize_t amt = ::read(fromFd, mBuffer.writeBuffer(), mBuffer.currentToWrite());
if (amt < 0) {
if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
- if (DEBUG) ALOGD("Fail to read fromFd %d: %s", fromFd, strerror(errno));
+ VLOG("Fail to read fromFd %d: %s", fromFd, strerror(errno));
return -errno;
- } // otherwise just continue
+ } // otherwise just continue
} else if (amt == 0) {
break;
} else {
@@ -232,14 +216,6 @@
return NO_ERROR;
}
-size_t
-FdBuffer::size() const
-{
- return mBuffer.size();
-}
+size_t FdBuffer::size() const { return mBuffer.size(); }
-EncodedBuffer::iterator
-FdBuffer::data() const
-{
- return mBuffer.begin();
-}
+EncodedBuffer::iterator FdBuffer::data() const { return mBuffer.begin(); }
diff --git a/cmds/incidentd/src/FdBuffer.h b/cmds/incidentd/src/FdBuffer.h
index 48dc855..5bfa093 100644
--- a/cmds/incidentd/src/FdBuffer.h
+++ b/cmds/incidentd/src/FdBuffer.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#ifndef FD_BUFFER_H
#define FD_BUFFER_H
@@ -27,8 +28,7 @@
/**
* Reads a file into a buffer, and then writes that data to an FdSet.
*/
-class FdBuffer
-{
+class FdBuffer {
public:
FdBuffer();
~FdBuffer();
@@ -50,7 +50,8 @@
*
* Poll will return POLLERR if fd is from sysfs, handle this edge case.
*/
- status_t readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeoutMs, const bool isSysfs=false);
+ status_t readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeoutMs,
+ const bool isSysfs = false);
/**
* Whether we timed out.
@@ -90,4 +91,4 @@
bool mTruncated;
};
-#endif // FD_BUFFER_H
+#endif // FD_BUFFER_H
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index 654036e..9ae6240 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -13,15 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "IncidentService.h"
+#include "FdBuffer.h"
+#include "PrivacyBuffer.h"
#include "Reporter.h"
+#include "incidentd_util.h"
+#include "section_list.h"
#include <binder/IPCThreadState.h>
+#include <binder/IResultReceiver.h>
#include <binder/IServiceManager.h>
+#include <binder/IShellCallback.h>
#include <cutils/log.h>
#include <private/android_filesystem_config.h>
#include <utils/Looper.h>
@@ -29,11 +34,9 @@
#include <unistd.h>
using namespace android;
+using namespace android::base;
-enum {
- WHAT_RUN_REPORT = 1,
- WHAT_SEND_BACKLOG_TO_DROPBOX = 2
-};
+enum { WHAT_RUN_REPORT = 1, WHAT_SEND_BACKLOG_TO_DROPBOX = 2 };
//#define DEFAULT_BACKLOG_DELAY_NS (1000000000LL * 60 * 5)
#define DEFAULT_BACKLOG_DELAY_NS (1000000000LL)
@@ -42,9 +45,7 @@
String16 const DUMP_PERMISSION("android.permission.DUMP");
String16 const USAGE_STATS_PERMISSION("android.permission.PACKAGE_USAGE_STATS");
-static Status
-checkIncidentPermissions(const IncidentReportArgs& args)
-{
+static Status checkIncidentPermissions(const IncidentReportArgs& args) {
uid_t callingUid = IPCThreadState::self()->getCallingUid();
pid_t callingPid = IPCThreadState::self()->getCallingPid();
if (callingUid == AID_ROOT || callingUid == AID_SHELL) {
@@ -55,14 +56,16 @@
// checking calling permission.
if (!checkCallingPermission(DUMP_PERMISSION)) {
ALOGW("Calling pid %d and uid %d does not have permission: android.permission.DUMP",
- callingPid, callingUid);
- return Status::fromExceptionCode(Status::EX_SECURITY,
+ callingPid, callingUid);
+ return Status::fromExceptionCode(
+ Status::EX_SECURITY,
"Calling process does not have permission: android.permission.DUMP");
}
if (!checkCallingPermission(USAGE_STATS_PERMISSION)) {
ALOGW("Calling pid %d and uid %d does not have permission: android.permission.USAGE_STATS",
- callingPid, callingUid);
- return Status::fromExceptionCode(Status::EX_SECURITY,
+ callingPid, callingUid);
+ return Status::fromExceptionCode(
+ Status::EX_SECURITY,
"Calling process does not have permission: android.permission.USAGE_STATS");
}
@@ -71,40 +74,34 @@
case DEST_LOCAL:
if (callingUid != AID_SHELL && callingUid != AID_ROOT) {
ALOGW("Calling pid %d and uid %d does not have permission to get local data.",
- callingPid, callingUid);
- return Status::fromExceptionCode(Status::EX_SECURITY,
- "Calling process does not have permission to get local data.");
+ callingPid, callingUid);
+ return Status::fromExceptionCode(
+ Status::EX_SECURITY,
+ "Calling process does not have permission to get local data.");
}
case DEST_EXPLICIT:
- if (callingUid != AID_SHELL && callingUid != AID_ROOT &&
- callingUid != AID_STATSD && callingUid != AID_SYSTEM) {
+ if (callingUid != AID_SHELL && callingUid != AID_ROOT && callingUid != AID_STATSD &&
+ callingUid != AID_SYSTEM) {
ALOGW("Calling pid %d and uid %d does not have permission to get explicit data.",
- callingPid, callingUid);
- return Status::fromExceptionCode(Status::EX_SECURITY,
- "Calling process does not have permission to get explicit data.");
+ callingPid, callingUid);
+ return Status::fromExceptionCode(
+ Status::EX_SECURITY,
+ "Calling process does not have permission to get explicit data.");
}
}
return Status::ok();
}
// ================================================================================
-ReportRequestQueue::ReportRequestQueue()
-{
-}
+ReportRequestQueue::ReportRequestQueue() {}
-ReportRequestQueue::~ReportRequestQueue()
-{
-}
+ReportRequestQueue::~ReportRequestQueue() {}
-void
-ReportRequestQueue::addRequest(const sp<ReportRequest>& request)
-{
+void ReportRequestQueue::addRequest(const sp<ReportRequest>& request) {
unique_lock<mutex> lock(mLock);
mQueue.push_back(request);
}
-sp<ReportRequest>
-ReportRequestQueue::getNextRequest()
-{
+sp<ReportRequest> ReportRequestQueue::getNextRequest() {
unique_lock<mutex> lock(mLock);
if (mQueue.empty()) {
return NULL;
@@ -115,22 +112,13 @@
}
}
-
// ================================================================================
ReportHandler::ReportHandler(const sp<Looper>& handlerLooper, const sp<ReportRequestQueue>& queue)
- :mBacklogDelay(DEFAULT_BACKLOG_DELAY_NS),
- mHandlerLooper(handlerLooper),
- mQueue(queue)
-{
-}
+ : mBacklogDelay(DEFAULT_BACKLOG_DELAY_NS), mHandlerLooper(handlerLooper), mQueue(queue) {}
-ReportHandler::~ReportHandler()
-{
-}
+ReportHandler::~ReportHandler() {}
-void
-ReportHandler::handleMessage(const Message& message)
-{
+void ReportHandler::handleMessage(const Message& message) {
switch (message.what) {
case WHAT_RUN_REPORT:
run_report();
@@ -141,33 +129,24 @@
}
}
-void
-ReportHandler::scheduleRunReport(const sp<ReportRequest>& request)
-{
+void ReportHandler::scheduleRunReport(const sp<ReportRequest>& request) {
mQueue->addRequest(request);
mHandlerLooper->removeMessages(this, WHAT_RUN_REPORT);
mHandlerLooper->sendMessage(this, Message(WHAT_RUN_REPORT));
}
-void
-ReportHandler::scheduleSendBacklogToDropbox()
-{
+void ReportHandler::scheduleSendBacklogToDropbox() {
unique_lock<mutex> lock(mLock);
mBacklogDelay = DEFAULT_BACKLOG_DELAY_NS;
schedule_send_backlog_to_dropbox_locked();
}
-void
-ReportHandler::schedule_send_backlog_to_dropbox_locked()
-{
+void ReportHandler::schedule_send_backlog_to_dropbox_locked() {
mHandlerLooper->removeMessages(this, WHAT_SEND_BACKLOG_TO_DROPBOX);
- mHandlerLooper->sendMessageDelayed(mBacklogDelay, this,
- Message(WHAT_SEND_BACKLOG_TO_DROPBOX));
+ mHandlerLooper->sendMessageDelayed(mBacklogDelay, this, Message(WHAT_SEND_BACKLOG_TO_DROPBOX));
}
-void
-ReportHandler::run_report()
-{
+void ReportHandler::run_report() {
sp<Reporter> reporter = new Reporter();
// Merge all of the requests into one that has all of the
@@ -190,15 +169,13 @@
}
}
-void
-ReportHandler::send_backlog_to_dropbox()
-{
+void ReportHandler::send_backlog_to_dropbox() {
if (Reporter::upload_backlog() == Reporter::REPORT_NEEDS_DROPBOX) {
// There was a failure. Exponential backoff.
unique_lock<mutex> lock(mLock);
mBacklogDelay *= 2;
ALOGI("Error sending to dropbox. Trying again in %lld minutes",
- (mBacklogDelay / (1000000000LL * 60)));
+ (mBacklogDelay / (1000000000LL * 60)));
schedule_send_backlog_to_dropbox_locked();
} else {
mBacklogDelay = DEFAULT_BACKLOG_DELAY_NS;
@@ -207,18 +184,13 @@
// ================================================================================
IncidentService::IncidentService(const sp<Looper>& handlerLooper)
- :mQueue(new ReportRequestQueue())
-{
+ : mQueue(new ReportRequestQueue()) {
mHandler = new ReportHandler(handlerLooper, mQueue);
}
-IncidentService::~IncidentService()
-{
-}
+IncidentService::~IncidentService() {}
-Status
-IncidentService::reportIncident(const IncidentReportArgs& args)
-{
+Status IncidentService::reportIncident(const IncidentReportArgs& args) {
ALOGI("reportIncident");
Status status = checkIncidentPermissions(args);
@@ -231,10 +203,9 @@
return Status::ok();
}
-Status
-IncidentService::reportIncidentToStream(const IncidentReportArgs& args,
- const sp<IIncidentReportStatusListener>& listener, const unique_fd& stream)
-{
+Status IncidentService::reportIncidentToStream(const IncidentReportArgs& args,
+ const sp<IIncidentReportStatusListener>& listener,
+ const unique_fd& stream) {
ALOGI("reportIncidentToStream");
Status status = checkIncidentPermissions(args);
@@ -252,12 +223,10 @@
return Status::ok();
}
-Status
-IncidentService::systemRunning()
-{
+Status IncidentService::systemRunning() {
if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
return Status::fromExceptionCode(Status::EX_SECURITY,
- "Only system uid can call systemRunning");
+ "Only system uid can call systemRunning");
}
// When system_server is up and running, schedule the dropbox task to run.
@@ -266,3 +235,120 @@
return Status::ok();
}
+/**
+ * Implement our own because the default binder implementation isn't
+ * properly handling SHELL_COMMAND_TRANSACTION.
+ */
+status_t IncidentService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags) {
+ status_t err;
+
+ switch (code) {
+ case SHELL_COMMAND_TRANSACTION: {
+ int in = data.readFileDescriptor();
+ int out = data.readFileDescriptor();
+ int err = data.readFileDescriptor();
+ int argc = data.readInt32();
+ Vector<String8> args;
+ for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
+ args.add(String8(data.readString16()));
+ }
+ sp<IShellCallback> shellCallback = IShellCallback::asInterface(data.readStrongBinder());
+ sp<IResultReceiver> resultReceiver =
+ IResultReceiver::asInterface(data.readStrongBinder());
+
+ FILE* fin = fdopen(in, "r");
+ FILE* fout = fdopen(out, "w");
+ FILE* ferr = fdopen(err, "w");
+
+ if (fin == NULL || fout == NULL || ferr == NULL) {
+ resultReceiver->send(NO_MEMORY);
+ } else {
+ err = command(fin, fout, ferr, args);
+ resultReceiver->send(err);
+ }
+
+ if (fin != NULL) {
+ fflush(fin);
+ fclose(fin);
+ }
+ if (fout != NULL) {
+ fflush(fout);
+ fclose(fout);
+ }
+ if (fout != NULL) {
+ fflush(ferr);
+ fclose(ferr);
+ }
+
+ return NO_ERROR;
+ }
+ default: { return BnIncidentManager::onTransact(code, data, reply, flags); }
+ }
+}
+
+status_t IncidentService::command(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
+ const int argCount = args.size();
+
+ if (argCount >= 1) {
+ if (!args[0].compare(String8("privacy"))) {
+ return cmd_privacy(in, out, err, args);
+ }
+ }
+ return cmd_help(out);
+}
+
+status_t IncidentService::cmd_help(FILE* out) {
+ fprintf(out, "usage: adb shell cmd incident privacy print <section_id>\n");
+ fprintf(out, "usage: adb shell cmd incident privacy parse <section_id> < proto.txt\n");
+ fprintf(out, " Prints/parses for the section id.\n");
+ return NO_ERROR;
+}
+
+static void printPrivacy(const Privacy* p, FILE* out, String8 indent) {
+ if (p == NULL) return;
+ fprintf(out, "%sid:%d, type:%d, dest:%d\n", indent.string(), p->field_id, p->type, p->dest);
+ if (p->children == NULL) return;
+ for (int i = 0; p->children[i] != NULL; i++) { // NULL-terminated.
+ printPrivacy(p->children[i], out, indent + " ");
+ }
+}
+
+status_t IncidentService::cmd_privacy(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
+ const int argCount = args.size();
+ if (argCount >= 3) {
+ String8 opt = args[1];
+ int sectionId = atoi(args[2].string());
+
+ const Privacy* p = get_privacy_of_section(sectionId);
+ if (p == NULL) {
+ fprintf(err, "Can't find section id %d\n", sectionId);
+ return NO_ERROR;
+ }
+ fprintf(err, "Get privacy for %d\n", sectionId);
+ if (opt == "print") {
+ printPrivacy(p, out, String8(""));
+ } else if (opt == "parse") {
+ FdBuffer buf;
+ status_t error = buf.read(fileno(in), 60000);
+ if (error != NO_ERROR) {
+ fprintf(err, "Error reading from stdin\n");
+ return error;
+ }
+ fprintf(err, "Read %zu bytes\n", buf.size());
+ auto data = buf.data();
+ PrivacyBuffer pBuf(p, data);
+
+ PrivacySpec spec = PrivacySpec::new_spec(argCount > 3 ? atoi(args[3]) : -1);
+ error = pBuf.strip(spec);
+ if (error != NO_ERROR) {
+ fprintf(err, "Error strip pii fields with spec %d\n", spec.dest);
+ return error;
+ }
+ return pBuf.flush(fileno(out));
+ }
+ } else {
+ return cmd_help(out);
+ }
+ return NO_ERROR;
+}
diff --git a/cmds/incidentd/src/IncidentService.h b/cmds/incidentd/src/IncidentService.h
index d6f33df..3c66507 100644
--- a/cmds/incidentd/src/IncidentService.h
+++ b/cmds/incidentd/src/IncidentService.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#ifndef INCIDENT_SERVICE_H
#define INCIDENT_SERVICE_H
@@ -32,8 +33,7 @@
using namespace std;
// ================================================================================
-class ReportRequestQueue : public virtual RefBase
-{
+class ReportRequestQueue : public virtual RefBase {
public:
ReportRequestQueue();
virtual ~ReportRequestQueue();
@@ -46,10 +46,8 @@
deque<sp<ReportRequest> > mQueue;
};
-
// ================================================================================
-class ReportHandler : public MessageHandler
-{
+class ReportHandler : public MessageHandler {
public:
ReportHandler(const sp<Looper>& handlerLooper, const sp<ReportRequestQueue>& queue);
virtual ~ReportHandler();
@@ -89,7 +87,6 @@
void send_backlog_to_dropbox();
};
-
// ================================================================================
class IncidentService : public BnIncidentManager {
public:
@@ -99,14 +96,29 @@
virtual Status reportIncident(const IncidentReportArgs& args);
virtual Status reportIncidentToStream(const IncidentReportArgs& args,
- const sp<IIncidentReportStatusListener>& listener, const unique_fd& stream);
+ const sp<IIncidentReportStatusListener>& listener,
+ const unique_fd& stream);
virtual Status systemRunning();
+ // Implement commands for debugging purpose.
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags) override;
+ virtual status_t command(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
+
private:
sp<ReportRequestQueue> mQueue;
sp<ReportHandler> mHandler;
+
+ /**
+ * Commands print out help.
+ */
+ status_t cmd_help(FILE* out);
+
+ /**
+ * Commands related to privacy filtering.
+ */
+ status_t cmd_privacy(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
};
-
-#endif // INCIDENT_SERVICE_H
+#endif // INCIDENT_SERVICE_H
diff --git a/cmds/incidentd/src/Log.h b/cmds/incidentd/src/Log.h
new file mode 100644
index 0000000..46efbd1
--- /dev/null
+++ b/cmds/incidentd/src/Log.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/*
+ * This file must be included at the top of the file. Other header files
+ * occasionally include log.h, and if LOG_TAG isn't set when that happens
+ * we'll get a preprocesser error when we try to define it here.
+ */
+
+#pragma once
+
+#define LOG_TAG "incidentd"
+#define DEBUG false
+
+#include <log/log.h>
+
+// Use the local value to turn on/off debug logs instead of using log.tag.properties.
+// The advantage is that in production compiler can remove the logging code if the local
+// DEBUG/VERBOSE is false.
+#define VLOG(...) \
+ if (DEBUG) ALOGD(__VA_ARGS__);
\ No newline at end of file
diff --git a/cmds/incidentd/src/Privacy.cpp b/cmds/incidentd/src/Privacy.cpp
index c5078f0..c42a87b 100644
--- a/cmds/incidentd/src/Privacy.cpp
+++ b/cmds/incidentd/src/Privacy.cpp
@@ -21,10 +21,9 @@
uint64_t encode_field_id(const Privacy* p) { return (uint64_t)p->type << 32 | p->field_id; }
-const Privacy* lookup(const Privacy* p, uint32_t fieldId)
-{
+const Privacy* lookup(const Privacy* p, uint32_t fieldId) {
if (p->children == NULL) return NULL;
- for (int i=0; p->children[i] != NULL; i++) { // NULL-terminated.
+ for (int i = 0; p->children[i] != NULL; i++) { // NULL-terminated.
if (p->children[i]->field_id == fieldId) return p->children[i];
// Incident section gen tool guarantees field ids in ascending order.
if (p->children[i]->field_id > fieldId) return NULL;
@@ -32,41 +31,31 @@
return NULL;
}
-static bool allowDest(const uint8_t dest, const uint8_t policy)
-{
+static bool allowDest(const uint8_t dest, const uint8_t policy) {
switch (policy) {
- case android::os::DEST_LOCAL:
- return dest == android::os::DEST_LOCAL;
- case android::os::DEST_EXPLICIT:
- case DEST_UNSET:
- return dest == android::os::DEST_LOCAL ||
- dest == android::os::DEST_EXPLICIT ||
- dest == DEST_UNSET;
- case android::os::DEST_AUTOMATIC:
- return true;
- default:
- return false;
+ case android::os::DEST_LOCAL:
+ return dest == android::os::DEST_LOCAL;
+ case android::os::DEST_EXPLICIT:
+ case DEST_UNSET:
+ return dest == android::os::DEST_LOCAL || dest == android::os::DEST_EXPLICIT ||
+ dest == DEST_UNSET;
+ case android::os::DEST_AUTOMATIC:
+ return true;
+ default:
+ return false;
}
}
-bool
-PrivacySpec::operator<(const PrivacySpec& other) const
-{
- return dest < other.dest;
-}
+bool PrivacySpec::operator<(const PrivacySpec& other) const { return dest < other.dest; }
-bool
-PrivacySpec::CheckPremission(const Privacy* privacy, const uint8_t defaultDest) const
-{
+bool PrivacySpec::CheckPremission(const Privacy* privacy, const uint8_t defaultDest) const {
uint8_t policy = privacy != NULL ? privacy->dest : defaultDest;
return allowDest(dest, policy);
}
-bool
-PrivacySpec::RequireAll() const { return dest == android::os::DEST_LOCAL; }
+bool PrivacySpec::RequireAll() const { return dest == android::os::DEST_LOCAL; }
-PrivacySpec PrivacySpec::new_spec(int dest)
-{
+PrivacySpec PrivacySpec::new_spec(int dest) {
switch (dest) {
case android::os::DEST_AUTOMATIC:
case android::os::DEST_EXPLICIT:
diff --git a/cmds/incidentd/src/Privacy.h b/cmds/incidentd/src/Privacy.h
index ce1b8e9..6b6de9c 100644
--- a/cmds/incidentd/src/Privacy.h
+++ b/cmds/incidentd/src/Privacy.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#ifndef PRIVACY_H
#define PRIVACY_H
@@ -20,7 +21,7 @@
#include <stdint.h>
// This is the default value of DEST enum, sync with privacy.proto
-const uint8_t DEST_UNSET = 255; // DEST_UNSET is not exposed to libincident
+const uint8_t DEST_UNSET = 255; // DEST_UNSET is not exposed to libincident
const uint8_t DEST_DEFAULT_VALUE = DEST_UNSET;
/*
@@ -68,15 +69,17 @@
bool operator<(const PrivacySpec& other) const;
// check permission of a policy, if returns true, don't strip the data.
- bool CheckPremission(const Privacy* privacy, const uint8_t defaultDest = DEST_DEFAULT_VALUE) const;
+ bool CheckPremission(const Privacy* privacy,
+ const uint8_t defaultDest = DEST_DEFAULT_VALUE) const;
// if returns true, no data need to be stripped.
bool RequireAll() const;
// Constructs spec using static methods below.
static PrivacySpec new_spec(int dest);
+
private:
PrivacySpec(uint8_t dest) : dest(dest) {}
};
-#endif // PRIVACY_H
+#endif // PRIVACY_H
diff --git a/cmds/incidentd/src/PrivacyBuffer.cpp b/cmds/incidentd/src/PrivacyBuffer.cpp
index f53befe..e4128f4 100644
--- a/cmds/incidentd/src/PrivacyBuffer.cpp
+++ b/cmds/incidentd/src/PrivacyBuffer.cpp
@@ -13,29 +13,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "PrivacyBuffer.h"
-#include "io_util.h"
+#include "incidentd_util.h"
+#include <android-base/file.h>
#include <android/util/protobuf.h>
#include <cutils/log.h>
using namespace android::util;
-const bool DEBUG = false;
-
/**
* Write the field to buf based on the wire type, iterator will point to next field.
* If skip is set to true, no data will be written to buf. Return number of bytes written.
*/
-void
-PrivacyBuffer::writeFieldOrSkip(uint32_t fieldTag, bool skip)
-{
- if (DEBUG) ALOGD("%s field %d (wiretype = %d)", skip ? "skip" : "write",
- read_field_id(fieldTag), read_wire_type(fieldTag));
-
+void PrivacyBuffer::writeFieldOrSkip(uint32_t fieldTag, bool skip) {
uint8_t wireType = read_wire_type(fieldTag);
size_t bytesToWrite = 0;
uint32_t varint = 0;
@@ -54,18 +47,17 @@
break;
case WIRE_TYPE_LENGTH_DELIMITED:
bytesToWrite = mData.readRawVarint();
- if(!skip) mProto.writeLengthDelimitedHeader(read_field_id(fieldTag), bytesToWrite);
+ if (!skip) mProto.writeLengthDelimitedHeader(read_field_id(fieldTag), bytesToWrite);
break;
case WIRE_TYPE_FIXED32:
if (!skip) mProto.writeRawVarint(fieldTag);
bytesToWrite = 4;
break;
}
- if (DEBUG) ALOGD("%s %d bytes of data", skip ? "skip" : "write", (int)bytesToWrite);
if (skip) {
mData.rp()->move(bytesToWrite);
} else {
- for (size_t i=0; i<bytesToWrite; i++) {
+ for (size_t i = 0; i < bytesToWrite; i++) {
mProto.writeRawByte(mData.next());
}
}
@@ -78,28 +70,29 @@
* The iterator must point to the head of a protobuf formatted field for successful operation.
* After exit with NO_ERROR, iterator points to the next protobuf field's head.
*/
-status_t
-PrivacyBuffer::stripField(const Privacy* parentPolicy, const PrivacySpec& spec)
-{
+status_t PrivacyBuffer::stripField(const Privacy* parentPolicy, const PrivacySpec& spec,
+ int depth /* use as a counter for this recusive method. */) {
if (!mData.hasNext() || parentPolicy == NULL) return BAD_VALUE;
uint32_t fieldTag = mData.readRawVarint();
- const Privacy* policy = lookup(parentPolicy, read_field_id(fieldTag));
+ uint32_t fieldId = read_field_id(fieldTag);
+ const Privacy* policy = lookup(parentPolicy, fieldId);
+ VLOG("[Depth %2d]Try to strip id %d, wiretype %d", depth, fieldId, read_wire_type(fieldTag));
if (policy == NULL || policy->children == NULL) {
- if (DEBUG) ALOGD("Not a message field %d: dest(%d)", read_field_id(fieldTag),
- policy != NULL ? policy->dest : parentPolicy->dest);
-
bool skip = !spec.CheckPremission(policy, parentPolicy->dest);
// iterator will point to head of next field
+ size_t currentAt = mData.rp()->pos();
writeFieldOrSkip(fieldTag, skip);
+ VLOG("[Depth %2d]Field %d %ss %d bytes", depth, fieldId, skip ? "skip" : "write",
+ (int)(get_varint_size(fieldTag) + mData.rp()->pos() - currentAt));
return NO_ERROR;
}
// current field is message type and its sub-fields have extra privacy policies
uint32_t msgSize = mData.readRawVarint();
- EncodedBuffer::Pointer start = mData.rp()->copy();
+ size_t start = mData.rp()->pos();
long long token = mProto.start(encode_field_id(policy));
- while (mData.rp()->pos() - start.pos() != msgSize) {
- status_t err = stripField(policy, spec);
+ while (mData.rp()->pos() - start != msgSize) {
+ status_t err = stripField(policy, spec, depth + 1);
if (err != NO_ERROR) return err;
}
mProto.end(token);
@@ -108,53 +101,39 @@
// ================================================================================
PrivacyBuffer::PrivacyBuffer(const Privacy* policy, EncodedBuffer::iterator& data)
- :mPolicy(policy),
- mData(data),
- mProto(),
- mSize(0)
-{
-}
+ : mPolicy(policy), mData(data), mProto(), mSize(0) {}
-PrivacyBuffer::~PrivacyBuffer()
-{
-}
+PrivacyBuffer::~PrivacyBuffer() {}
-status_t
-PrivacyBuffer::strip(const PrivacySpec& spec)
-{
- if (DEBUG) ALOGD("Strip with spec %d", spec.dest);
+status_t PrivacyBuffer::strip(const PrivacySpec& spec) {
+ VLOG("Strip with spec %d", spec.dest);
// optimization when no strip happens
if (mPolicy == NULL || mPolicy->children == NULL || spec.RequireAll()) {
if (spec.CheckPremission(mPolicy)) mSize = mData.size();
return NO_ERROR;
}
while (mData.hasNext()) {
- status_t err = stripField(mPolicy, spec);
+ status_t err = stripField(mPolicy, spec, 0);
if (err != NO_ERROR) return err;
}
if (mData.bytesRead() != mData.size()) return BAD_VALUE;
mSize = mProto.size();
- mData.rp()->rewind(); // rewind the read pointer back to beginning after the strip.
+ mData.rp()->rewind(); // rewind the read pointer back to beginning after the strip.
return NO_ERROR;
}
-void
-PrivacyBuffer::clear()
-{
+void PrivacyBuffer::clear() {
mSize = 0;
mProto.clear();
}
-size_t
-PrivacyBuffer::size() const { return mSize; }
+size_t PrivacyBuffer::size() const { return mSize; }
-status_t
-PrivacyBuffer::flush(int fd)
-{
+status_t PrivacyBuffer::flush(int fd) {
status_t err = NO_ERROR;
EncodedBuffer::iterator iter = size() == mData.size() ? mData : mProto.data();
while (iter.readBuffer() != NULL) {
- err = write_all(fd, iter.readBuffer(), iter.currentToRead());
+ err = WriteFully(fd, iter.readBuffer(), iter.currentToRead()) ? NO_ERROR : -errno;
iter.rp()->move(iter.currentToRead());
if (err != NO_ERROR) return err;
}
diff --git a/cmds/incidentd/src/PrivacyBuffer.h b/cmds/incidentd/src/PrivacyBuffer.h
index c9ca9a7..92e1a25 100644
--- a/cmds/incidentd/src/PrivacyBuffer.h
+++ b/cmds/incidentd/src/PrivacyBuffer.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#ifndef PRIVACY_BUFFER_H
#define PRIVACY_BUFFER_H
@@ -31,14 +32,14 @@
* PrivacyBuffer holds the original protobuf data and strips PII-sensitive fields
* based on the request and holds stripped data in its own buffer for output.
*/
-class PrivacyBuffer
-{
+class PrivacyBuffer {
public:
PrivacyBuffer(const Privacy* policy, EncodedBuffer::iterator& data);
~PrivacyBuffer();
/**
- * Strip based on the request and hold data in its own buffer. Return NO_ERROR if strip succeeds.
+ * Strip based on the request and hold data in its own buffer. Return NO_ERROR if strip
+ * succeeds.
*/
status_t strip(const PrivacySpec& spec);
@@ -64,8 +65,8 @@
ProtoOutputStream mProto;
size_t mSize;
- status_t stripField(const Privacy* parentPolicy, const PrivacySpec& spec);
+ status_t stripField(const Privacy* parentPolicy, const PrivacySpec& spec, int depth);
void writeFieldOrSkip(uint32_t fieldTag, bool skip);
};
-#endif // PRIVACY_BUFFER_H
\ No newline at end of file
+#endif // PRIVACY_BUFFER_H
\ No newline at end of file
diff --git a/cmds/incidentd/src/Reporter.cpp b/cmds/incidentd/src/Reporter.cpp
index 06baeba..c0b5358 100644
--- a/cmds/incidentd/src/Reporter.cpp
+++ b/cmds/incidentd/src/Reporter.cpp
@@ -13,8 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "Reporter.h"
@@ -26,11 +25,11 @@
#include <private/android_filesystem_config.h>
#include <utils/SystemClock.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <dirent.h>
-#include <fcntl.h>
#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
/**
* The directory where the incident reports are stored.
@@ -39,62 +38,37 @@
// ================================================================================
ReportRequest::ReportRequest(const IncidentReportArgs& a,
- const sp<IIncidentReportStatusListener> &l, int f)
- :args(a),
- listener(l),
- fd(f),
- err(NO_ERROR)
-{
-}
+ const sp<IIncidentReportStatusListener>& l, int f)
+ : args(a), listener(l), fd(f), err(NO_ERROR) {}
-ReportRequest::~ReportRequest()
-{
+ReportRequest::~ReportRequest() {
if (fd >= 0) {
// clean up the opened file descriptor
close(fd);
}
}
-bool
-ReportRequest::ok()
-{
- return fd >= 0 && err == NO_ERROR;
-}
+bool ReportRequest::ok() { return fd >= 0 && err == NO_ERROR; }
// ================================================================================
ReportRequestSet::ReportRequestSet()
- :mRequests(),
- mSections(),
- mMainFd(-1),
- mMainDest(-1),
- mMetadata(),
- mSectionStats()
-{
-}
+ : mRequests(), mSections(), mMainFd(-1), mMainDest(-1), mMetadata(), mSectionStats() {}
-ReportRequestSet::~ReportRequestSet()
-{
-}
+ReportRequestSet::~ReportRequestSet() {}
// TODO: dedup on exact same args and fd, report the status back to listener!
-void
-ReportRequestSet::add(const sp<ReportRequest>& request)
-{
+void ReportRequestSet::add(const sp<ReportRequest>& request) {
mRequests.push_back(request);
mSections.merge(request->args);
mMetadata.set_request_size(mMetadata.request_size() + 1);
}
-void
-ReportRequestSet::setMainFd(int fd)
-{
+void ReportRequestSet::setMainFd(int fd) {
mMainFd = fd;
mMetadata.set_use_dropbox(fd > 0);
}
-void
-ReportRequestSet::setMainDest(int dest)
-{
+void ReportRequestSet::setMainDest(int dest) {
mMainDest = dest;
PrivacySpec spec = PrivacySpec::new_spec(dest);
switch (spec.dest) {
@@ -110,13 +84,9 @@
}
}
-bool
-ReportRequestSet::containsSection(int id) {
- return mSections.containsSection(id);
-}
+bool ReportRequestSet::containsSection(int id) { return mSections.containsSection(id); }
-IncidentMetadata::SectionStats*
-ReportRequestSet::sectionStats(int id) {
+IncidentMetadata::SectionStats* ReportRequestSet::sectionStats(int id) {
if (mSectionStats.find(id) == mSectionStats.end()) {
auto stats = mMetadata.add_sections();
stats->set_id(id);
@@ -128,9 +98,7 @@
// ================================================================================
Reporter::Reporter() : Reporter(INCIDENT_DIRECTORY) { isTest = false; };
-Reporter::Reporter(const char* directory)
- :batch()
-{
+Reporter::Reporter(const char* directory) : batch() {
char buf[100];
// TODO: Make the max size smaller for user builds.
@@ -148,13 +116,9 @@
mFilename = mIncidentDirectory + buf;
}
-Reporter::~Reporter()
-{
-}
+Reporter::~Reporter() {}
-Reporter::run_report_status_t
-Reporter::runReport()
-{
+Reporter::run_report_status_t Reporter::runReport() {
status_t err = NO_ERROR;
bool needMainFd = false;
int mainFd = -1;
@@ -163,7 +127,7 @@
MetadataSection metadataSection;
// See if we need the main file
- for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+ for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
if ((*it)->fd < 0 && mainFd < 0) {
needMainFd = true;
mainDest = (*it)->args.dest();
@@ -194,7 +158,7 @@
}
// Tell everyone that we're starting.
- for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+ for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
if ((*it)->listener != NULL) {
(*it)->listener->onReportStarted();
}
@@ -205,15 +169,14 @@
// For each of the report fields, see if we need it, and if so, execute the command
// and report to those that care that we're doing it.
- for (const Section** section=SECTION_LIST; *section; section++) {
+ for (const Section** section = SECTION_LIST; *section; section++) {
const int id = (*section)->id;
if (this->batch.containsSection(id)) {
ALOGD("Taking incident report section %d '%s'", id, (*section)->name.string());
- // Notify listener of starting.
- for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+ for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
if ((*it)->listener != NULL && (*it)->args.containsSection(id)) {
- (*it)->listener->onReportSectionStatus(id,
- IIncidentReportStatusListener::STATUS_STARTING);
+ (*it)->listener->onReportSectionStatus(
+ id, IIncidentReportStatusListener::STATUS_STARTING);
}
}
@@ -227,15 +190,15 @@
stats->set_exec_duration_ms(endTime - startTime);
if (err != NO_ERROR) {
ALOGW("Incident section %s (%d) failed: %s. Stopping report.",
- (*section)->name.string(), id, strerror(-err));
+ (*section)->name.string(), id, strerror(-err));
goto DONE;
}
- // Notify listener of ending.
- for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+ // Notify listener of starting
+ for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
if ((*it)->listener != NULL && (*it)->args.containsSection(id)) {
- (*it)->listener->onReportSectionStatus(id,
- IIncidentReportStatusListener::STATUS_FINISHED);
+ (*it)->listener->onReportSectionStatus(
+ id, IIncidentReportStatusListener::STATUS_FINISHED);
}
}
ALOGD("Finish incident report section %d '%s'", id, (*section)->name.string());
@@ -252,7 +215,7 @@
}
// Tell everyone that we're done.
- for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+ for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
if ((*it)->listener != NULL) {
if (err == NO_ERROR) {
(*it)->listener->onReportFinished();
@@ -274,7 +237,7 @@
// If the status was ok, delete the file. If not, leave it around until the next
// boot or the next checkin. If the directory gets too big older files will
// be rotated out.
- if(!isTest) unlink(mFilename.c_str());
+ if (!isTest) unlink(mFilename.c_str());
}
return REPORT_FINISHED;
@@ -283,9 +246,7 @@
/**
* Create our output file and set the access permissions to -rw-rw----
*/
-status_t
-Reporter::create_file(int* fd)
-{
+status_t Reporter::create_file(int* fd) {
const char* filename = mFilename.c_str();
*fd = open(filename, O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0660);
@@ -307,9 +268,7 @@
return NO_ERROR;
}
-Reporter::run_report_status_t
-Reporter::upload_backlog()
-{
+Reporter::run_report_status_t Reporter::upload_backlog() {
DIR* dir;
struct dirent* entry;
struct stat st;
@@ -360,4 +319,3 @@
return REPORT_FINISHED;
}
-
diff --git a/cmds/incidentd/src/Reporter.h b/cmds/incidentd/src/Reporter.h
index 6058068..0f3f221 100644
--- a/cmds/incidentd/src/Reporter.h
+++ b/cmds/incidentd/src/Reporter.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#ifndef REPORTER_H
#define REPORTER_H
@@ -33,23 +34,21 @@
using namespace std;
// ================================================================================
-struct ReportRequest : public virtual RefBase
-{
+struct ReportRequest : public virtual RefBase {
IncidentReportArgs args;
sp<IIncidentReportStatusListener> listener;
int fd;
status_t err;
- ReportRequest(const IncidentReportArgs& args,
- const sp<IIncidentReportStatusListener> &listener, int fd);
+ ReportRequest(const IncidentReportArgs& args, const sp<IIncidentReportStatusListener>& listener,
+ int fd);
virtual ~ReportRequest();
- bool ok(); // returns true if the request is ok for write.
+ bool ok(); // returns true if the request is ok for write.
};
// ================================================================================
-class ReportRequestSet
-{
+class ReportRequestSet {
public:
ReportRequestSet();
~ReportRequestSet();
@@ -81,18 +80,14 @@
};
// ================================================================================
-class Reporter : public virtual RefBase
-{
+class Reporter : public virtual RefBase {
public:
- enum run_report_status_t {
- REPORT_FINISHED = 0,
- REPORT_NEEDS_DROPBOX = 1
- };
+ enum run_report_status_t { REPORT_FINISHED = 0, REPORT_NEEDS_DROPBOX = 1 };
ReportRequestSet batch;
- Reporter(); // PROD must use this constructor.
- Reporter(const char* directory); // For testing purpose only.
+ Reporter(); // PROD must use this constructor.
+ Reporter(const char* directory); // For testing purpose only.
virtual ~Reporter();
// Run the report as described in the batch and args parameters.
@@ -110,8 +105,7 @@
status_t create_file(int* fd);
- bool isTest = true; // default to true for testing
+ bool isTest = true; // default to true for testing
};
-
-#endif // REPORTER_H
+#endif // REPORTER_H
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 3c76298..2e4e980 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -13,8 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "Section.h"
@@ -26,20 +25,21 @@
#include <memory>
#include <mutex>
+#include <android-base/file.h>
#include <android/util/protobuf.h>
#include <binder/IServiceManager.h>
#include <log/log_event_list.h>
-#include <log/logprint.h>
#include <log/log_read.h>
+#include <log/logprint.h>
#include <private/android_logger.h>
#include "FdBuffer.h"
-#include "frameworks/base/core/proto/android/util/log.proto.h"
-#include "io_util.h"
#include "Privacy.h"
#include "PrivacyBuffer.h"
-#include "section_list.h"
+#include "frameworks/base/core/proto/android/util/log.proto.h"
+#include "incidentd_util.h"
+using namespace android::base;
using namespace android::util;
using namespace std;
@@ -48,21 +48,18 @@
const int FIELD_ID_INCIDENT_METADATA = 2;
// incident section parameters
-const int WAIT_MAX = 5;
+const int WAIT_MAX = 5;
const struct timespec WAIT_INTERVAL_NS = {0, 200 * 1000 * 1000};
const char INCIDENT_HELPER[] = "/system/bin/incident_helper";
-static pid_t
-fork_execute_incident_helper(const int id, const char* name, Fpipe& p2cPipe, Fpipe& c2pPipe)
-{
- const char* ihArgs[] { INCIDENT_HELPER, "-s", String8::format("%d", id).string(), NULL };
+static pid_t fork_execute_incident_helper(const int id, const char* name, Fpipe& p2cPipe,
+ Fpipe& c2pPipe) {
+ const char* ihArgs[]{INCIDENT_HELPER, "-s", String8::format("%d", id).string(), NULL};
// fork used in multithreaded environment, avoid adding unnecessary code in child process
pid_t pid = fork();
if (pid == 0) {
- if (TEMP_FAILURE_RETRY(dup2(p2cPipe.readFd(), STDIN_FILENO)) != 0
- || !p2cPipe.close()
- || TEMP_FAILURE_RETRY(dup2(c2pPipe.writeFd(), STDOUT_FILENO)) != 1
- || !c2pPipe.close()) {
+ if (TEMP_FAILURE_RETRY(dup2(p2cPipe.readFd(), STDIN_FILENO)) != 0 || !p2cPipe.close() ||
+ TEMP_FAILURE_RETRY(dup2(c2pPipe.writeFd(), STDOUT_FILENO)) != 1 || !c2pPipe.close()) {
ALOGW("%s can't setup stdin and stdout for incident helper", name);
_exit(EXIT_FAILURE);
}
@@ -73,7 +70,7 @@
execv(INCIDENT_HELPER, const_cast<char**>(ihArgs));
ALOGW("%s failed in incident helper process: %s", name, strerror(errno));
- _exit(EXIT_FAILURE); // always exits with failure if any
+ _exit(EXIT_FAILURE); // always exits with failure if any
}
// close the fds used in incident helper
close(p2cPipe.readFd());
@@ -84,18 +81,18 @@
// ================================================================================
static status_t statusCode(int status) {
if (WIFSIGNALED(status)) {
- ALOGD("return by signal: %s", strerror(WTERMSIG(status)));
- return -WTERMSIG(status);
+ VLOG("return by signal: %s", strerror(WTERMSIG(status)));
+ return -WTERMSIG(status);
} else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) {
- ALOGD("return by exit: %s", strerror(WEXITSTATUS(status)));
- return -WEXITSTATUS(status);
+ VLOG("return by exit: %s", strerror(WEXITSTATUS(status)));
+ return -WEXITSTATUS(status);
}
return NO_ERROR;
}
static status_t kill_child(pid_t pid) {
int status;
- ALOGD("try to kill child process %d", pid);
+ VLOG("try to kill child process %d", pid);
kill(pid, SIGKILL);
if (waitpid(pid, &status, 0) == -1) return -1;
return statusCode(status);
@@ -105,7 +102,7 @@
int status;
bool died = false;
// wait for child to report status up to 1 seconds
- for(int loop = 0; !died && loop < WAIT_MAX; loop++) {
+ for (int loop = 0; !died && loop < WAIT_MAX; loop++) {
if (waitpid(pid, &status, WNOHANG) == pid) died = true;
// sleep for 0.2 second
nanosleep(&WAIT_INTERVAL_NS, NULL);
@@ -114,38 +111,14 @@
return statusCode(status);
}
// ================================================================================
-static const Privacy*
-get_privacy_of_section(int id)
-{
- int l = 0;
- int r = PRIVACY_POLICY_COUNT - 1;
- while (l <= r) {
- int mid = (l + r) >> 1;
- const Privacy* p = PRIVACY_POLICY_LIST[mid];
-
- if (p->field_id < (uint32_t)id) {
- l = mid + 1;
- } else if (p->field_id > (uint32_t)id) {
- r = mid - 1;
- } else {
- return p;
- }
- }
- return NULL;
-}
-
-// ================================================================================
-static status_t
-write_section_header(int fd, int sectionId, size_t size)
-{
+static status_t write_section_header(int fd, int sectionId, size_t size) {
uint8_t buf[20];
- uint8_t *p = write_length_delimited_tag_header(buf, sectionId, size);
- return write_all(fd, buf, p-buf);
+ uint8_t* p = write_length_delimited_tag_header(buf, sectionId, size);
+ return WriteFully(fd, buf, p - buf) ? NO_ERROR : -errno;
}
-static status_t
-write_report_requests(const int id, const FdBuffer& buffer, ReportRequestSet* requests)
-{
+static status_t write_report_requests(const int id, const FdBuffer& buffer,
+ ReportRequestSet* requests) {
status_t err = -EBADF;
EncodedBuffer::iterator data = buffer.data();
PrivacyBuffer privacyBuffer(get_privacy_of_section(id), data);
@@ -171,18 +144,24 @@
for (auto mit = requestsBySpec.begin(); mit != requestsBySpec.end(); mit++) {
PrivacySpec spec = mit->first;
err = privacyBuffer.strip(spec);
- if (err != NO_ERROR) return err; // it means the privacyBuffer data is corrupted.
+ if (err != NO_ERROR) return err; // it means the privacyBuffer data is corrupted.
if (privacyBuffer.size() == 0) continue;
for (auto it = mit->second.begin(); it != mit->second.end(); it++) {
sp<ReportRequest> request = *it;
err = write_section_header(request->fd, id, privacyBuffer.size());
- if (err != NO_ERROR) { request->err = err; continue; }
+ if (err != NO_ERROR) {
+ request->err = err;
+ continue;
+ }
err = privacyBuffer.flush(request->fd);
- if (err != NO_ERROR) { request->err = err; continue; }
+ if (err != NO_ERROR) {
+ request->err = err;
+ continue;
+ }
writeable++;
- ALOGD("Section %d flushed %zu bytes to fd %d with spec %d", id,
- privacyBuffer.size(), request->fd, spec.dest);
+ VLOG("Section %d flushed %zu bytes to fd %d with spec %d", id, privacyBuffer.size(),
+ request->fd, spec.dest);
}
privacyBuffer.clear();
}
@@ -191,16 +170,22 @@
if (requests->mainFd() >= 0) {
PrivacySpec spec = PrivacySpec::new_spec(requests->mainDest());
err = privacyBuffer.strip(spec);
- if (err != NO_ERROR) return err; // the buffer data is corrupted.
+ if (err != NO_ERROR) return err; // the buffer data is corrupted.
if (privacyBuffer.size() == 0) goto DONE;
err = write_section_header(requests->mainFd(), id, privacyBuffer.size());
- if (err != NO_ERROR) { requests->setMainFd(-1); goto DONE; }
+ if (err != NO_ERROR) {
+ requests->setMainFd(-1);
+ goto DONE;
+ }
err = privacyBuffer.flush(requests->mainFd());
- if (err != NO_ERROR) { requests->setMainFd(-1); goto DONE; }
+ if (err != NO_ERROR) {
+ requests->setMainFd(-1);
+ goto DONE;
+ }
writeable++;
- ALOGD("Section %d flushed %zu bytes to dropbox %d with spec %d", id,
- privacyBuffer.size(), requests->mainFd(), spec.dest);
+ VLOG("Section %d flushed %zu bytes to dropbox %d with spec %d", id, privacyBuffer.size(),
+ requests->mainFd(), spec.dest);
stats->set_report_size_bytes(privacyBuffer.size());
}
@@ -210,40 +195,28 @@
}
// ================================================================================
-Section::Section(int i, const int64_t timeoutMs)
- :id(i),
- timeoutMs(timeoutMs)
-{
-}
+Section::Section(int i, const int64_t timeoutMs) : id(i), timeoutMs(timeoutMs) {}
-Section::~Section()
-{
-}
+Section::~Section() {}
// ================================================================================
-HeaderSection::HeaderSection()
- :Section(FIELD_ID_INCIDENT_HEADER, 0)
-{
-}
+HeaderSection::HeaderSection() : Section(FIELD_ID_INCIDENT_HEADER, 0) {}
-HeaderSection::~HeaderSection()
-{
-}
+HeaderSection::~HeaderSection() {}
-status_t
-HeaderSection::Execute(ReportRequestSet* requests) const
-{
- for (ReportRequestSet::iterator it=requests->begin(); it!=requests->end(); it++) {
+status_t HeaderSection::Execute(ReportRequestSet* requests) const {
+ for (ReportRequestSet::iterator it = requests->begin(); it != requests->end(); it++) {
const sp<ReportRequest> request = *it;
const vector<vector<uint8_t>>& headers = request->args.headers();
- for (vector<vector<uint8_t>>::const_iterator buf=headers.begin(); buf!=headers.end(); buf++) {
+ for (vector<vector<uint8_t>>::const_iterator buf = headers.begin(); buf != headers.end();
+ buf++) {
if (buf->empty()) continue;
// So the idea is only requests with negative fd are written to dropbox file.
int fd = request->fd >= 0 ? request->fd : requests->mainFd();
write_section_header(fd, id, buf->size());
- write_all(fd, (uint8_t const*)buf->data(), buf->size());
+ WriteFully(fd, (uint8_t const*)buf->data(), buf->size());
// If there was an error now, there will be an error later and we will remove
// it from the list then.
}
@@ -251,54 +224,49 @@
return NO_ERROR;
}
// ================================================================================
-MetadataSection::MetadataSection()
- :Section(FIELD_ID_INCIDENT_METADATA, 0)
-{
-}
+MetadataSection::MetadataSection() : Section(FIELD_ID_INCIDENT_METADATA, 0) {}
-MetadataSection::~MetadataSection()
-{
-}
+MetadataSection::~MetadataSection() {}
-status_t
-MetadataSection::Execute(ReportRequestSet* requests) const
-{
+status_t MetadataSection::Execute(ReportRequestSet* requests) const {
std::string metadataBuf;
requests->metadata().SerializeToString(&metadataBuf);
- for (ReportRequestSet::iterator it=requests->begin(); it!=requests->end(); it++) {
+ for (ReportRequestSet::iterator it = requests->begin(); it != requests->end(); it++) {
const sp<ReportRequest> request = *it;
if (metadataBuf.empty() || request->fd < 0 || request->err != NO_ERROR) {
continue;
}
write_section_header(request->fd, id, metadataBuf.size());
- write_all(request->fd, (uint8_t const*)metadataBuf.data(), metadataBuf.size());
+ if (!WriteFully(request->fd, (uint8_t const*)metadataBuf.data(), metadataBuf.size())) {
+ ALOGW("Failed to write metadata to fd %d", request->fd);
+ // we don't fail if we can't write to a single request's fd.
+ }
}
if (requests->mainFd() >= 0 && !metadataBuf.empty()) {
write_section_header(requests->mainFd(), id, metadataBuf.size());
- write_all(requests->mainFd(), (uint8_t const*)metadataBuf.data(), metadataBuf.size());
+ if (!WriteFully(requests->mainFd(), (uint8_t const*)metadataBuf.data(), metadataBuf.size())) {
+ ALOGW("Failed to write metadata to dropbox fd %d", requests->mainFd());
+ return -1;
+ }
}
return NO_ERROR;
}
// ================================================================================
FileSection::FileSection(int id, const char* filename, const int64_t timeoutMs)
- :Section(id, timeoutMs),
- mFilename(filename)
-{
+ : Section(id, timeoutMs), mFilename(filename) {
name = filename;
mIsSysfs = strncmp(filename, "/sys/", 5) == 0;
}
FileSection::~FileSection() {}
-status_t
-FileSection::Execute(ReportRequestSet* requests) const
-{
+status_t FileSection::Execute(ReportRequestSet* requests) const {
// read from mFilename first, make sure the file is available
// add O_CLOEXEC to make sure it is closed when exec incident helper
int fd = open(mFilename, O_RDONLY | O_CLOEXEC);
if (fd == -1) {
- ALOGW("FileSection '%s' failed to open file", this->name.string());
- return -errno;
+ ALOGW("FileSection '%s' failed to open file", this->name.string());
+ return -errno;
}
FdBuffer buffer;
@@ -318,22 +286,23 @@
// parent process
status_t readStatus = buffer.readProcessedDataInStream(fd, p2cPipe.writeFd(), c2pPipe.readFd(),
- this->timeoutMs, mIsSysfs);
+ this->timeoutMs, mIsSysfs);
if (readStatus != NO_ERROR || buffer.timedOut()) {
ALOGW("FileSection '%s' failed to read data from incident helper: %s, timedout: %s",
- this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
+ this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
kill_child(pid);
return readStatus;
}
status_t ihStatus = wait_child(pid);
if (ihStatus != NO_ERROR) {
- ALOGW("FileSection '%s' abnormal child process: %s", this->name.string(), strerror(-ihStatus));
+ ALOGW("FileSection '%s' abnormal child process: %s", this->name.string(),
+ strerror(-ihStatus));
return ihStatus;
}
- ALOGD("FileSection '%s' wrote %zd bytes in %d ms", this->name.string(), buffer.size(),
- (int)buffer.durationMs());
+ VLOG("FileSection '%s' wrote %zd bytes in %d ms", this->name.string(), buffer.size(),
+ (int)buffer.durationMs());
status_t err = write_report_requests(this->id, buffer, requests);
if (err != NO_ERROR) {
ALOGW("FileSection '%s' failed writing: %s", this->name.string(), strerror(-err));
@@ -344,8 +313,7 @@
}
// ================================================================================
-struct WorkerThreadData : public virtual RefBase
-{
+struct WorkerThreadData : public virtual RefBase {
const WorkerThreadSection* section;
int fds[2];
@@ -362,31 +330,19 @@
};
WorkerThreadData::WorkerThreadData(const WorkerThreadSection* sec)
- :section(sec),
- workerDone(false),
- workerError(NO_ERROR)
-{
+ : section(sec), workerDone(false), workerError(NO_ERROR) {
fds[0] = -1;
fds[1] = -1;
}
-WorkerThreadData::~WorkerThreadData()
-{
-}
+WorkerThreadData::~WorkerThreadData() {}
// ================================================================================
-WorkerThreadSection::WorkerThreadSection(int id)
- :Section(id)
-{
-}
+WorkerThreadSection::WorkerThreadSection(int id) : Section(id) {}
-WorkerThreadSection::~WorkerThreadSection()
-{
-}
+WorkerThreadSection::~WorkerThreadSection() {}
-static void*
-worker_thread_func(void* cookie)
-{
+static void* worker_thread_func(void* cookie) {
WorkerThreadData* data = (WorkerThreadData*)cookie;
status_t err = data->section->BlockingCall(data->writeFd());
@@ -402,9 +358,7 @@
return NULL;
}
-status_t
-WorkerThreadSection::Execute(ReportRequestSet* requests) const
-{
+status_t WorkerThreadSection::Execute(ReportRequestSet* requests) const {
status_t err = NO_ERROR;
pthread_t thread;
pthread_attr_t attr;
@@ -447,7 +401,7 @@
if (err != NO_ERROR) {
// TODO: Log this error into the incident report.
ALOGW("WorkerThreadSection '%s' reader failed with error '%s'", this->name.string(),
- strerror(-err));
+ strerror(-err));
}
// Done with the read fd. The worker thread closes the write one so
@@ -466,7 +420,7 @@
err = data->workerError;
// TODO: Log this error into the incident report.
ALOGW("WorkerThreadSection '%s' worker failed with error '%s'", this->name.string(),
- strerror(-err));
+ strerror(-err));
}
}
}
@@ -484,13 +438,13 @@
// just exit with a log messasge.
if (err != NO_ERROR) {
ALOGW("WorkerThreadSection '%s' failed with error '%s'", this->name.string(),
- strerror(-err));
+ strerror(-err));
return NO_ERROR;
}
// Write the data that was collected
- ALOGD("WorkerThreadSection '%s' wrote %zd bytes in %d ms", name.string(), buffer.size(),
- (int)buffer.durationMs());
+ VLOG("WorkerThreadSection '%s' wrote %zd bytes in %d ms", name.string(), buffer.size(),
+ (int)buffer.durationMs());
err = write_report_requests(this->id, buffer, requests);
if (err != NO_ERROR) {
ALOGW("WorkerThreadSection '%s' failed writing: '%s'", this->name.string(), strerror(-err));
@@ -501,14 +455,12 @@
}
// ================================================================================
-void
-CommandSection::init(const char* command, va_list args)
-{
+void CommandSection::init(const char* command, va_list args) {
va_list copied_args;
int numOfArgs = 0;
va_copy(copied_args, args);
- while(va_arg(copied_args, const char*) != NULL) {
+ while (va_arg(copied_args, const char*) != NULL) {
numOfArgs++;
}
va_end(copied_args);
@@ -518,41 +470,33 @@
mCommand[0] = command;
name = command;
- for (int i=0; i<numOfArgs; i++) {
+ for (int i = 0; i < numOfArgs; i++) {
const char* arg = va_arg(args, const char*);
- mCommand[i+1] = arg;
+ mCommand[i + 1] = arg;
name += " ";
name += arg;
}
- mCommand[numOfArgs+1] = NULL;
+ mCommand[numOfArgs + 1] = NULL;
}
CommandSection::CommandSection(int id, const int64_t timeoutMs, const char* command, ...)
- :Section(id, timeoutMs)
-{
+ : Section(id, timeoutMs) {
va_list args;
va_start(args, command);
init(command, args);
va_end(args);
}
-CommandSection::CommandSection(int id, const char* command, ...)
- :Section(id)
-{
+CommandSection::CommandSection(int id, const char* command, ...) : Section(id) {
va_list args;
va_start(args, command);
init(command, args);
va_end(args);
}
-CommandSection::~CommandSection()
-{
- free(mCommand);
-}
+CommandSection::~CommandSection() { free(mCommand); }
-status_t
-CommandSection::Execute(ReportRequestSet* requests) const
-{
+status_t CommandSection::Execute(ReportRequestSet* requests) const {
FdBuffer buffer;
Fpipe cmdPipe;
Fpipe ihPipe;
@@ -571,13 +515,15 @@
if (cmdPid == 0) {
// replace command's stdout with ihPipe's write Fd
if (dup2(cmdPipe.writeFd(), STDOUT_FILENO) != 1 || !ihPipe.close() || !cmdPipe.close()) {
- ALOGW("CommandSection '%s' failed to set up stdout: %s", this->name.string(), strerror(errno));
+ ALOGW("CommandSection '%s' failed to set up stdout: %s", this->name.string(),
+ strerror(errno));
_exit(EXIT_FAILURE);
}
- execvp(this->mCommand[0], (char *const *) this->mCommand);
- int err = errno; // record command error code
- ALOGW("CommandSection '%s' failed in executing command: %s", this->name.string(), strerror(errno));
- _exit(err); // exit with command error code
+ execvp(this->mCommand[0], (char* const*)this->mCommand);
+ int err = errno; // record command error code
+ ALOGW("CommandSection '%s' failed in executing command: %s", this->name.string(),
+ strerror(errno));
+ _exit(err); // exit with command error code
}
pid_t ihPid = fork_execute_incident_helper(this->id, this->name.string(), cmdPipe, ihPipe);
if (ihPid == -1) {
@@ -589,24 +535,26 @@
status_t readStatus = buffer.read(ihPipe.readFd(), this->timeoutMs);
if (readStatus != NO_ERROR || buffer.timedOut()) {
ALOGW("CommandSection '%s' failed to read data from incident helper: %s, timedout: %s",
- this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
+ this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
kill_child(cmdPid);
kill_child(ihPid);
return readStatus;
}
- // TODO: wait for command here has one trade-off: the failed status of command won't be detected until
+ // TODO: wait for command here has one trade-off: the failed status of command won't be detected
+ // until
// buffer timeout, but it has advatage on starting the data stream earlier.
status_t cmdStatus = wait_child(cmdPid);
- status_t ihStatus = wait_child(ihPid);
+ status_t ihStatus = wait_child(ihPid);
if (cmdStatus != NO_ERROR || ihStatus != NO_ERROR) {
- ALOGW("CommandSection '%s' abnormal child processes, return status: command: %s, incident helper: %s",
- this->name.string(), strerror(-cmdStatus), strerror(-ihStatus));
+ ALOGW("CommandSection '%s' abnormal child processes, return status: command: %s, incident "
+ "helper: %s",
+ this->name.string(), strerror(-cmdStatus), strerror(-ihStatus));
return cmdStatus != NO_ERROR ? cmdStatus : ihStatus;
}
- ALOGD("CommandSection '%s' wrote %zd bytes in %d ms", this->name.string(), buffer.size(),
- (int)buffer.durationMs());
+ VLOG("CommandSection '%s' wrote %zd bytes in %d ms", this->name.string(), buffer.size(),
+ (int)buffer.durationMs());
status_t err = write_report_requests(this->id, buffer, requests);
if (err != NO_ERROR) {
ALOGW("CommandSection '%s' failed writing: %s", this->name.string(), strerror(-err));
@@ -617,9 +565,7 @@
// ================================================================================
DumpsysSection::DumpsysSection(int id, const char* service, ...)
- :WorkerThreadSection(id),
- mService(service)
-{
+ : WorkerThreadSection(id), mService(service) {
name = "dumpsys ";
name += service;
@@ -637,13 +583,9 @@
va_end(args);
}
-DumpsysSection::~DumpsysSection()
-{
-}
+DumpsysSection::~DumpsysSection() {}
-status_t
-DumpsysSection::BlockingCall(int pipeWriteFd) const
-{
+status_t DumpsysSection::BlockingCall(int pipeWriteFd) const {
// checkService won't wait for the service to show up like getService will.
sp<IBinder> service = defaultServiceManager()->checkService(mService);
@@ -667,30 +609,23 @@
// initialization only once in Section.cpp.
map<log_id_t, log_time> LogSection::gLastLogsRetrieved;
-LogSection::LogSection(int id, log_id_t logID)
- :WorkerThreadSection(id),
- mLogID(logID)
-{
+LogSection::LogSection(int id, log_id_t logID) : WorkerThreadSection(id), mLogID(logID) {
name += "logcat ";
name += android_log_id_to_name(logID);
switch (logID) {
- case LOG_ID_EVENTS:
- case LOG_ID_STATS:
- case LOG_ID_SECURITY:
- mBinary = true;
- break;
- default:
- mBinary = false;
+ case LOG_ID_EVENTS:
+ case LOG_ID_STATS:
+ case LOG_ID_SECURITY:
+ mBinary = true;
+ break;
+ default:
+ mBinary = false;
}
}
-LogSection::~LogSection()
-{
-}
+LogSection::~LogSection() {}
-static size_t
-trimTail(char const* buf, size_t len)
-{
+static size_t trimTail(char const* buf, size_t len) {
while (len > 0) {
char c = buf[len - 1];
if (c == '\0' || c == ' ' || c == '\n' || c == '\r' || c == ':') {
@@ -706,17 +641,15 @@
return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
}
-status_t
-LogSection::BlockingCall(int pipeWriteFd) const
-{
+status_t LogSection::BlockingCall(int pipeWriteFd) const {
status_t err = NO_ERROR;
// Open log buffer and getting logs since last retrieved time if any.
unique_ptr<logger_list, void (*)(logger_list*)> loggers(
- gLastLogsRetrieved.find(mLogID) == gLastLogsRetrieved.end() ?
- android_logger_list_alloc(ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, 0) :
- android_logger_list_alloc_time(ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
- gLastLogsRetrieved[mLogID], 0),
- android_logger_list_free);
+ gLastLogsRetrieved.find(mLogID) == gLastLogsRetrieved.end()
+ ? android_logger_list_alloc(ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, 0)
+ : android_logger_list_alloc_time(ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
+ gLastLogsRetrieved[mLogID], 0),
+ android_logger_list_free);
if (android_logger_open(loggers.get(), mLogID) == NULL) {
ALOGW("LogSection %s: Can't get logger.", this->name.string());
@@ -727,7 +660,7 @@
log_time lastTimestamp(0);
ProtoOutputStream proto;
- while (true) { // keeps reading until logd buffer is fully read.
+ while (true) { // keeps reading until logd buffer is fully read.
status_t err = android_logger_list_read(loggers.get(), &msg);
// err = 0 - no content, unexpected connection drop or EOF.
// err = +ive number - size of retrieved data from logger
@@ -742,7 +675,8 @@
if (mBinary) {
// remove the first uint32 which is tag's index in event log tags
android_log_context context = create_android_log_parser(msg.msg() + sizeof(uint32_t),
- msg.len() - sizeof(uint32_t));;
+ msg.len() - sizeof(uint32_t));
+ ;
android_log_list_element elem;
lastTimestamp.tv_sec = msg.entry_v1.sec;
@@ -752,38 +686,46 @@
long long token = proto.start(LogProto::BINARY_LOGS);
proto.write(BinaryLogEntry::SEC, msg.entry_v1.sec);
proto.write(BinaryLogEntry::NANOSEC, msg.entry_v1.nsec);
- proto.write(BinaryLogEntry::UID, (int) msg.entry_v4.uid);
+ proto.write(BinaryLogEntry::UID, (int)msg.entry_v4.uid);
proto.write(BinaryLogEntry::PID, msg.entry_v1.pid);
proto.write(BinaryLogEntry::TID, msg.entry_v1.tid);
- proto.write(BinaryLogEntry::TAG_INDEX, get4LE(reinterpret_cast<uint8_t const*>(msg.msg())));
+ proto.write(BinaryLogEntry::TAG_INDEX,
+ get4LE(reinterpret_cast<uint8_t const*>(msg.msg())));
do {
elem = android_log_read_next(context);
long long elemToken = proto.start(BinaryLogEntry::ELEMS);
switch (elem.type) {
case EVENT_TYPE_INT:
- proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_INT);
- proto.write(BinaryLogEntry::Elem::VAL_INT32, (int) elem.data.int32);
+ proto.write(BinaryLogEntry::Elem::TYPE,
+ BinaryLogEntry::Elem::EVENT_TYPE_INT);
+ proto.write(BinaryLogEntry::Elem::VAL_INT32, (int)elem.data.int32);
break;
case EVENT_TYPE_LONG:
- proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_LONG);
- proto.write(BinaryLogEntry::Elem::VAL_INT64, (long long) elem.data.int64);
+ proto.write(BinaryLogEntry::Elem::TYPE,
+ BinaryLogEntry::Elem::EVENT_TYPE_LONG);
+ proto.write(BinaryLogEntry::Elem::VAL_INT64, (long long)elem.data.int64);
break;
case EVENT_TYPE_STRING:
- proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_STRING);
+ proto.write(BinaryLogEntry::Elem::TYPE,
+ BinaryLogEntry::Elem::EVENT_TYPE_STRING);
proto.write(BinaryLogEntry::Elem::VAL_STRING, elem.data.string, elem.len);
break;
case EVENT_TYPE_FLOAT:
- proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_FLOAT);
+ proto.write(BinaryLogEntry::Elem::TYPE,
+ BinaryLogEntry::Elem::EVENT_TYPE_FLOAT);
proto.write(BinaryLogEntry::Elem::VAL_FLOAT, elem.data.float32);
break;
case EVENT_TYPE_LIST:
- proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_LIST);
+ proto.write(BinaryLogEntry::Elem::TYPE,
+ BinaryLogEntry::Elem::EVENT_TYPE_LIST);
break;
case EVENT_TYPE_LIST_STOP:
- proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_LIST_STOP);
+ proto.write(BinaryLogEntry::Elem::TYPE,
+ BinaryLogEntry::Elem::EVENT_TYPE_LIST_STOP);
break;
case EVENT_TYPE_UNKNOWN:
- proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_UNKNOWN);
+ proto.write(BinaryLogEntry::Elem::TYPE,
+ BinaryLogEntry::Elem::EVENT_TYPE_UNKNOWN);
break;
}
proto.end(elemToken);
@@ -811,7 +753,8 @@
proto.write(TextLogEntry::PID, entry.pid);
proto.write(TextLogEntry::TID, entry.tid);
proto.write(TextLogEntry::TAG, entry.tag, trimTail(entry.tag, entry.tagLen));
- proto.write(TextLogEntry::LOG, entry.message, trimTail(entry.message, entry.messageLen));
+ proto.write(TextLogEntry::LOG, entry.message,
+ trimTail(entry.message, entry.messageLen));
proto.end(token);
}
}
diff --git a/cmds/incidentd/src/Section.h b/cmds/incidentd/src/Section.h
index 80cc033..d644681 100644
--- a/cmds/incidentd/src/Section.h
+++ b/cmds/incidentd/src/Section.h
@@ -13,31 +13,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#ifndef SECTIONS_H
#define SECTIONS_H
#include "Reporter.h"
-#include <map>
#include <stdarg.h>
+#include <map>
-#include <utils/String8.h>
#include <utils/String16.h>
+#include <utils/String8.h>
#include <utils/Vector.h>
using namespace android;
-const int64_t REMOTE_CALL_TIMEOUT_MS = 10 * 1000; // 10 seconds
+const int64_t REMOTE_CALL_TIMEOUT_MS = 10 * 1000; // 10 seconds
/**
* Base class for sections
*/
-class Section
-{
+class Section {
public:
const int id;
- const int64_t timeoutMs; // each section must have a timeout
+ const int64_t timeoutMs; // each section must have a timeout
String8 name;
Section(int id, const int64_t timeoutMs = REMOTE_CALL_TIMEOUT_MS);
@@ -49,8 +49,7 @@
/**
* Section that generates incident headers.
*/
-class HeaderSection : public Section
-{
+class HeaderSection : public Section {
public:
HeaderSection();
virtual ~HeaderSection();
@@ -61,8 +60,7 @@
/**
* Section that generates incident metadata.
*/
-class MetadataSection : public Section
-{
+class MetadataSection : public Section {
public:
MetadataSection();
virtual ~MetadataSection();
@@ -73,8 +71,7 @@
/**
* Section that reads in a file.
*/
-class FileSection : public Section
-{
+class FileSection : public Section {
public:
FileSection(int id, const char* filename, const int64_t timeoutMs = 5000 /* 5 seconds */);
virtual ~FileSection();
@@ -83,14 +80,13 @@
private:
const char* mFilename;
- bool mIsSysfs; // sysfs files are pollable but return POLLERR by default, handle it separately
+ bool mIsSysfs; // sysfs files are pollable but return POLLERR by default, handle it separately
};
/**
* Base class for sections that call a command that might need a timeout.
*/
-class WorkerThreadSection : public Section
-{
+class WorkerThreadSection : public Section {
public:
WorkerThreadSection(int id);
virtual ~WorkerThreadSection();
@@ -103,8 +99,7 @@
/**
* Section that forks and execs a command, and puts stdout as the section.
*/
-class CommandSection : public Section
-{
+class CommandSection : public Section {
public:
CommandSection(int id, const int64_t timeoutMs, const char* command, ...);
@@ -123,8 +118,7 @@
/**
* Section that calls dumpsys on a system service.
*/
-class DumpsysSection : public WorkerThreadSection
-{
+class DumpsysSection : public WorkerThreadSection {
public:
DumpsysSection(int id, const char* service, ...);
virtual ~DumpsysSection();
@@ -139,8 +133,7 @@
/**
* Section that reads from logd.
*/
-class LogSection : public WorkerThreadSection
-{
+class LogSection : public WorkerThreadSection {
// global last log retrieved timestamp for each log_id_t.
static map<log_id_t, log_time> gLastLogsRetrieved;
@@ -155,5 +148,4 @@
bool mBinary;
};
-#endif // SECTIONS_H
-
+#endif // SECTIONS_H
diff --git a/cmds/incidentd/src/incidentd_util.cpp b/cmds/incidentd/src/incidentd_util.cpp
new file mode 100644
index 0000000..2415860
--- /dev/null
+++ b/cmds/incidentd/src/incidentd_util.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 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 "incidentd_util.h"
+
+#include "section_list.h"
+
+const Privacy* get_privacy_of_section(int id) {
+ int l = 0;
+ int r = PRIVACY_POLICY_COUNT - 1;
+ while (l <= r) {
+ int mid = (l + r) >> 1;
+ const Privacy* p = PRIVACY_POLICY_LIST[mid];
+
+ if (p->field_id < (uint32_t)id) {
+ l = mid + 1;
+ } else if (p->field_id > (uint32_t)id) {
+ r = mid - 1;
+ } else {
+ return p;
+ }
+ }
+ return NULL;
+}
+
+// ================================================================================
+Fpipe::Fpipe() : mRead(), mWrite() {}
+
+Fpipe::~Fpipe() { close(); }
+
+bool Fpipe::close() {
+ mRead.reset();
+ mWrite.reset();
+ return true;
+}
+
+bool Fpipe::init() { return Pipe(&mRead, &mWrite); }
+
+int Fpipe::readFd() const { return mRead.get(); }
+
+int Fpipe::writeFd() const { return mWrite.get(); }
\ No newline at end of file
diff --git a/cmds/incidentd/src/io_util.h b/cmds/incidentd/src/incidentd_util.h
similarity index 74%
rename from cmds/incidentd/src/io_util.h
rename to cmds/incidentd/src/incidentd_util.h
index 320dd6c..09aa040 100644
--- a/cmds/incidentd/src/io_util.h
+++ b/cmds/incidentd/src/incidentd_util.h
@@ -13,16 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
-#ifndef IO_UTIL_H
-#define IO_UTIL_H
+#ifndef INCIDENTD_UTIL_H
+#define INCIDENTD_UTIL_H
-#include <stdint.h>
-#include <utils/Errors.h>
+#include <android-base/unique_fd.h>
-using namespace android;
+#include "Privacy.h"
-status_t write_all(int fd, uint8_t const* buf, size_t size);
+using namespace android::base;
+
+const Privacy* get_privacy_of_section(int id);
class Fpipe {
public:
@@ -35,7 +37,8 @@
int writeFd() const;
private:
- int mFds[2];
+ unique_fd mRead;
+ unique_fd mWrite;
};
-#endif // IO_UTIL_H
\ No newline at end of file
+#endif // INCIDENTD_UTIL_H
\ No newline at end of file
diff --git a/cmds/incidentd/src/io_util.cpp b/cmds/incidentd/src/io_util.cpp
deleted file mode 100644
index 90f543e..0000000
--- a/cmds/incidentd/src/io_util.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "incidentd"
-
-#include "io_util.h"
-
-#include <unistd.h>
-
-status_t write_all(int fd, uint8_t const* buf, size_t size)
-{
- while (size > 0) {
- ssize_t amt = TEMP_FAILURE_RETRY(::write(fd, buf, size));
- if (amt < 0) {
- return -errno;
- }
- size -= amt;
- buf += amt;
- }
- return NO_ERROR;
-}
-
-Fpipe::Fpipe() {}
-
-Fpipe::~Fpipe() { close(); }
-
-bool Fpipe::close() { return !(::close(mFds[0]) || ::close(mFds[1])); }
-
-bool Fpipe::init() { return pipe(mFds) != -1; }
-
-int Fpipe::readFd() const { return mFds[0]; }
-
-int Fpipe::writeFd() const { return mFds[1]; }
diff --git a/cmds/incidentd/src/main.cpp b/cmds/incidentd/src/main.cpp
index 3a7511d..38b7449 100644
--- a/cmds/incidentd/src/main.cpp
+++ b/cmds/incidentd/src/main.cpp
@@ -13,8 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "IncidentService.h"
@@ -23,25 +22,22 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <binder/Status.h>
-#include <cutils/log.h>
#include <utils/Looper.h>
#include <utils/StrongPointer.h>
-#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/types.h>
using namespace android;
// ================================================================================
-int
-main(int /*argc*/, char** /*argv*/)
-{
+int main(int /*argc*/, char** /*argv*/) {
// Set up the looper
sp<Looper> looper(Looper::prepare(0 /* opts */));
// Set up the binder
sp<ProcessState> ps(ProcessState::self());
- ps->setThreadPoolMaxThreadCount(1); // everything is oneway, let it queue and save ram
+ ps->setThreadPoolMaxThreadCount(1); // everything is oneway, let it queue and save ram
ps->startThreadPool();
ps->giveThreadPoolName();
IPCThreadState::self()->disableBackgroundScheduling(true);
diff --git a/cmds/incidentd/src/report_directory.cpp b/cmds/incidentd/src/report_directory.cpp
index 20111d8..b71c066 100644
--- a/cmds/incidentd/src/report_directory.cpp
+++ b/cmds/incidentd/src/report_directory.cpp
@@ -13,19 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "report_directory.h"
-#include <cutils/log.h>
#include <private/android_filesystem_config.h>
#include <utils/String8.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <dirent.h>
#include <libgen.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#include <vector>
@@ -33,9 +31,7 @@
using namespace android;
using namespace std;
-status_t
-create_directory(const char* directory)
-{
+status_t create_directory(const char* directory) {
struct stat st;
status_t err = NO_ERROR;
char* dir = strdup(directory);
@@ -75,14 +71,14 @@
goto done;
}
if ((st.st_mode & 0777) != 0770) {
- ALOGE("No incident reports today. Mode is %0o on report directory %s",
- st.st_mode, directory);
+ ALOGE("No incident reports today. Mode is %0o on report directory %s", st.st_mode,
+ directory);
err = BAD_VALUE;
goto done;
}
if (st.st_uid != AID_INCIDENTD || st.st_gid != AID_INCIDENTD) {
ALOGE("No incident reports today. Owner is %d and group is %d on report directory %s",
- st.st_uid, st.st_gid, directory);
+ st.st_uid, st.st_gid, directory);
err = BAD_VALUE;
goto done;
}
@@ -92,20 +88,17 @@
return err;
}
-static bool
-stat_mtime_cmp(const pair<String8,struct stat>& a, const pair<String8,struct stat>& b)
-{
+static bool stat_mtime_cmp(const pair<String8, struct stat>& a,
+ const pair<String8, struct stat>& b) {
return a.second.st_mtime < b.second.st_mtime;
}
-void
-clean_directory(const char* directory, off_t maxSize, size_t maxCount)
-{
+void clean_directory(const char* directory, off_t maxSize, size_t maxCount) {
DIR* dir;
struct dirent* entry;
struct stat st;
- vector<pair<String8,struct stat>> files;
+ vector<pair<String8, struct stat>> files;
if ((dir = opendir(directory)) == NULL) {
ALOGE("Couldn't open incident directory: %s", directory);
@@ -131,7 +124,7 @@
if (!S_ISREG(st.st_mode)) {
continue;
}
- files.push_back(pair<String8,struct stat>(filename, st));
+ files.push_back(pair<String8, struct stat>(filename, st));
totalSize += st.st_size;
totalCount++;
@@ -148,8 +141,8 @@
sort(files.begin(), files.end(), stat_mtime_cmp);
// Remove files until we're under our limits.
- for (vector<pair<String8,struct stat>>::iterator it = files.begin();
- it != files.end() && totalSize >= maxSize && totalCount >= maxCount; it++) {
+ for (vector<pair<String8, struct stat>>::iterator it = files.begin();
+ it != files.end() && totalSize >= maxSize && totalCount >= maxCount; it++) {
remove(it->first.string());
totalSize -= it->second.st_size;
totalCount--;
diff --git a/cmds/incidentd/src/report_directory.h b/cmds/incidentd/src/report_directory.h
index bed4f86..2a3cf4c 100644
--- a/cmds/incidentd/src/report_directory.h
+++ b/cmds/incidentd/src/report_directory.h
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#ifndef DIRECTORY_CLEANER_H
#define DIRECTORY_CLEANER_H
+#include <sys/types.h>
#include <utils/Errors.h>
-#include <sys/types.h>
-
-using namespace android;
-
-status_t create_directory(const char* directory);
+android::status_t create_directory(const char* directory);
void clean_directory(const char* directory, off_t maxSize, size_t maxCount);
-#endif // DIRECTORY_CLEANER_H
+#endif // DIRECTORY_CLEANER_H
diff --git a/cmds/incidentd/src/section_list.h b/cmds/incidentd/src/section_list.h
index ddc0505..697e66f 100644
--- a/cmds/incidentd/src/section_list.h
+++ b/cmds/incidentd/src/section_list.h
@@ -13,11 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#ifndef SECTION_LIST_H
#define SECTION_LIST_H
-#include <log/log_event_list.h> // include log_id_t enums.
+#include <log/log_event_list.h> // include log_id_t enums.
#include "Privacy.h"
#include "Section.h"
@@ -36,5 +37,4 @@
extern const int PRIVACY_POLICY_COUNT;
-#endif // SECTION_LIST_H
-
+#endif // SECTION_LIST_H
diff --git a/cmds/incidentd/tests/FdBuffer_test.cpp b/cmds/incidentd/tests/FdBuffer_test.cpp
index 3fd2ed8..956c8d3 100644
--- a/cmds/incidentd/tests/FdBuffer_test.cpp
+++ b/cmds/incidentd/tests/FdBuffer_test.cpp
@@ -11,11 +11,10 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "FdBuffer.h"
-#include "io_util.h"
+#include "incidentd_util.h"
#include <android-base/file.h>
#include <android-base/test_utils.h>
@@ -48,7 +47,7 @@
}
void AssertBufferContent(const char* expected) {
- int i=0;
+ int i = 0;
EncodedBuffer::iterator it = buffer.data();
while (it.hasNext()) {
ASSERT_EQ(it.next(), expected[i++]);
@@ -100,7 +99,7 @@
ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
- int i=0;
+ int i = 0;
EncodedBuffer::iterator it = buffer.data();
while (it.hasNext()) {
EXPECT_EQ(it.next(), (uint8_t)testdata[i++]);
@@ -118,7 +117,7 @@
if (pid == 0) {
close(c2pPipe.readFd());
- while(true) {
+ while (true) {
write(c2pPipe.writeFd(), "poo", 3);
sleep(1);
}
@@ -130,7 +129,7 @@
ASSERT_EQ(NO_ERROR, status);
EXPECT_TRUE(buffer.timedOut());
- kill(pid, SIGKILL); // reap the child process
+ kill(pid, SIGKILL); // reap the child process
}
}
@@ -155,8 +154,8 @@
close(p2cPipe.readFd());
close(c2pPipe.writeFd());
- ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
- p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
+ ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(),
+ c2pPipe.readFd(), READ_TIMEOUT));
AssertBufferReadSuccessful(HEAD.size() + testdata.size());
AssertBufferContent(expected.c_str());
wait(&pid);
@@ -187,8 +186,8 @@
close(p2cPipe.readFd());
close(c2pPipe.writeFd());
- ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
- p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
+ ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(),
+ c2pPipe.readFd(), READ_TIMEOUT));
AssertBufferReadSuccessful(HEAD.size() + testdata.size());
AssertBufferContent(expected.c_str());
wait(&pid);
@@ -212,8 +211,8 @@
close(p2cPipe.readFd());
close(c2pPipe.writeFd());
- ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
- p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
+ ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(),
+ c2pPipe.readFd(), READ_TIMEOUT));
AssertBufferReadSuccessful(0);
AssertBufferContent("");
wait(&pid);
@@ -222,7 +221,7 @@
TEST_F(FdBufferTest, ReadInStreamMoreThan4MB) {
const std::string testFile = kTestDataPath + "morethan4MB.txt";
- size_t fourMB = (size_t) 4 * 1024 * 1024;
+ size_t fourMB = (size_t)4 * 1024 * 1024;
int fd = open(testFile.c_str(), O_RDONLY | O_CLOEXEC);
ASSERT_NE(fd, -1);
int pid = fork();
@@ -239,8 +238,8 @@
close(p2cPipe.readFd());
close(c2pPipe.writeFd());
- ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(fd,
- p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
+ ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(fd, p2cPipe.writeFd(),
+ c2pPipe.readFd(), READ_TIMEOUT));
EXPECT_EQ(buffer.size(), fourMB);
EXPECT_FALSE(buffer.timedOut());
EXPECT_TRUE(buffer.truncated());
@@ -276,9 +275,9 @@
close(p2cPipe.readFd());
close(c2pPipe.writeFd());
- ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
- p2cPipe.writeFd(), c2pPipe.readFd(), QUICK_TIMEOUT_MS));
+ ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(),
+ c2pPipe.readFd(), QUICK_TIMEOUT_MS));
EXPECT_TRUE(buffer.timedOut());
- kill(pid, SIGKILL); // reap the child process
+ kill(pid, SIGKILL); // reap the child process
}
}
diff --git a/cmds/incidentd/tests/PrivacyBuffer_test.cpp b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
index c7bfe55..7ea9bbf 100644
--- a/cmds/incidentd/tests/PrivacyBuffer_test.cpp
+++ b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
@@ -11,8 +11,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "FdBuffer.h"
#include "PrivacyBuffer.h"
@@ -37,13 +36,12 @@
const uint8_t STRING_TYPE = 9;
const uint8_t MESSAGE_TYPE = 11;
const string STRING_FIELD_0 = "\x02\viamtestdata";
-const string VARINT_FIELD_1 = "\x08\x96\x01"; // 150
+const string VARINT_FIELD_1 = "\x08\x96\x01"; // 150
const string STRING_FIELD_2 = "\x12\vwhatthefuck";
-const string FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff"; // -1
-const string FIX32_FIELD_4 = "\x25\xff\xff\xff\xff"; // -1
+const string FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff"; // -1
+const string FIX32_FIELD_4 = "\x25\xff\xff\xff\xff"; // -1
const string MESSAGE_FIELD_5 = "\x2a\x10" + VARINT_FIELD_1 + STRING_FIELD_2;
-
class PrivacyBufferTest : public Test {
public:
virtual ~PrivacyBufferTest() {
@@ -55,9 +53,7 @@
}
}
- virtual void SetUp() override {
- ASSERT_NE(tf.fd, -1);
- }
+ virtual void SetUp() override { ASSERT_NE(tf.fd, -1); }
void writeToFdBuffer(string str) {
ASSERT_TRUE(WriteStringToFile(str, tf.path));
@@ -81,11 +77,11 @@
}
void assertStripByFields(uint8_t dest, string expected, int size, Privacy* privacy, ...) {
- Privacy* list[size+1];
+ Privacy* list[size + 1];
list[0] = privacy;
va_list args;
va_start(args, privacy);
- for (int i=1; i<size; i++) {
+ for (int i = 1; i < size; i++) {
Privacy* p = va_arg(args, Privacy*);
list[i] = p;
}
@@ -115,13 +111,14 @@
}
FdBuffer buffer;
+
private:
TemporaryFile tf;
// Littering this code with unique_ptr (or similar) is ugly, so we just
// mass-free everything after the test completes.
- std::vector<Privacy *> privacies;
+ std::vector<Privacy*> privacies;
- Privacy *new_uninit_privacy() {
+ Privacy* new_uninit_privacy() {
Privacy* p = new Privacy;
privacies.push_back(p);
return p;
@@ -165,63 +162,69 @@
TEST_F(PrivacyBufferTest, NoStripVarintField) {
writeToFdBuffer(VARINT_FIELD_1);
- assertStripByFields(DEST_EXPLICIT, VARINT_FIELD_1, 1, create_privacy(1, OTHER_TYPE, DEST_AUTOMATIC));
+ assertStripByFields(DEST_EXPLICIT, VARINT_FIELD_1, 1,
+ create_privacy(1, OTHER_TYPE, DEST_AUTOMATIC));
}
TEST_F(PrivacyBufferTest, NoStripLengthDelimitedField_String) {
writeToFdBuffer(STRING_FIELD_2);
- assertStripByFields(DEST_EXPLICIT, STRING_FIELD_2, 1, create_privacy(2, STRING_TYPE, DEST_AUTOMATIC));
+ assertStripByFields(DEST_EXPLICIT, STRING_FIELD_2, 1,
+ create_privacy(2, STRING_TYPE, DEST_AUTOMATIC));
}
TEST_F(PrivacyBufferTest, NoStripFixed64Field) {
writeToFdBuffer(FIX64_FIELD_3);
- assertStripByFields(DEST_EXPLICIT, FIX64_FIELD_3, 1, create_privacy(3, OTHER_TYPE, DEST_AUTOMATIC));
+ assertStripByFields(DEST_EXPLICIT, FIX64_FIELD_3, 1,
+ create_privacy(3, OTHER_TYPE, DEST_AUTOMATIC));
}
TEST_F(PrivacyBufferTest, NoStripFixed32Field) {
writeToFdBuffer(FIX32_FIELD_4);
- assertStripByFields(DEST_EXPLICIT, FIX32_FIELD_4, 1, create_privacy(4, OTHER_TYPE, DEST_AUTOMATIC));
+ assertStripByFields(DEST_EXPLICIT, FIX32_FIELD_4, 1,
+ create_privacy(4, OTHER_TYPE, DEST_AUTOMATIC));
}
TEST_F(PrivacyBufferTest, NoStripLengthDelimitedField_Message) {
writeToFdBuffer(MESSAGE_FIELD_5);
- assertStripByFields(DEST_EXPLICIT, MESSAGE_FIELD_5, 1, create_privacy(5, MESSAGE_TYPE, DEST_AUTOMATIC));
+ assertStripByFields(DEST_EXPLICIT, MESSAGE_FIELD_5, 1,
+ create_privacy(5, MESSAGE_TYPE, DEST_AUTOMATIC));
}
TEST_F(PrivacyBufferTest, StripVarintAndString) {
- writeToFdBuffer(STRING_FIELD_0 + VARINT_FIELD_1 + STRING_FIELD_2
- + FIX64_FIELD_3 + FIX32_FIELD_4);
+ writeToFdBuffer(STRING_FIELD_0 + VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3 +
+ FIX32_FIELD_4);
string expected = STRING_FIELD_0 + FIX64_FIELD_3 + FIX32_FIELD_4;
- assertStripByFields(DEST_EXPLICIT, expected, 2,
- create_privacy(1, OTHER_TYPE, DEST_LOCAL), create_privacy(2, STRING_TYPE, DEST_LOCAL));
+ assertStripByFields(DEST_EXPLICIT, expected, 2, create_privacy(1, OTHER_TYPE, DEST_LOCAL),
+ create_privacy(2, STRING_TYPE, DEST_LOCAL));
}
TEST_F(PrivacyBufferTest, StripVarintAndFixed64) {
- writeToFdBuffer(STRING_FIELD_0 + VARINT_FIELD_1 + STRING_FIELD_2
- + FIX64_FIELD_3 + FIX32_FIELD_4);
+ writeToFdBuffer(STRING_FIELD_0 + VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3 +
+ FIX32_FIELD_4);
string expected = STRING_FIELD_0 + STRING_FIELD_2 + FIX32_FIELD_4;
- assertStripByFields(DEST_EXPLICIT, expected, 2,
- create_privacy(1, OTHER_TYPE, DEST_LOCAL), create_privacy(3, OTHER_TYPE, DEST_LOCAL));
+ assertStripByFields(DEST_EXPLICIT, expected, 2, create_privacy(1, OTHER_TYPE, DEST_LOCAL),
+ create_privacy(3, OTHER_TYPE, DEST_LOCAL));
}
TEST_F(PrivacyBufferTest, StripVarintInNestedMessage) {
writeToFdBuffer(STRING_FIELD_0 + MESSAGE_FIELD_5);
- Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL };
+ Privacy* list[] = {create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL};
string expected = STRING_FIELD_0 + "\x2a\xd" + STRING_FIELD_2;
assertStripByFields(DEST_EXPLICIT, expected, 1, create_message_privacy(5, list));
}
TEST_F(PrivacyBufferTest, StripFix64AndVarintInNestedMessage) {
writeToFdBuffer(STRING_FIELD_0 + FIX64_FIELD_3 + MESSAGE_FIELD_5);
- Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL };
+ Privacy* list[] = {create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL};
string expected = STRING_FIELD_0 + "\x2a\xd" + STRING_FIELD_2;
- assertStripByFields(DEST_EXPLICIT, expected, 2, create_privacy(3, OTHER_TYPE, DEST_LOCAL), create_message_privacy(5, list));
+ assertStripByFields(DEST_EXPLICIT, expected, 2, create_privacy(3, OTHER_TYPE, DEST_LOCAL),
+ create_message_privacy(5, list));
}
TEST_F(PrivacyBufferTest, ClearAndStrip) {
string data = STRING_FIELD_0 + VARINT_FIELD_1;
writeToFdBuffer(data);
- Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL };
+ Privacy* list[] = {create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL};
EncodedBuffer::iterator bufData = buffer.data();
PrivacyBuffer privacyBuf(create_message_privacy(300, list), bufData);
PrivacySpec spec1 = PrivacySpec::new_spec(DEST_EXPLICIT);
@@ -235,7 +238,7 @@
TEST_F(PrivacyBufferTest, BadDataInFdBuffer) {
writeToFdBuffer("iambaddata");
- Privacy* list[] = { create_privacy(4, OTHER_TYPE, DEST_AUTOMATIC), NULL };
+ Privacy* list[] = {create_privacy(4, OTHER_TYPE, DEST_AUTOMATIC), NULL};
EncodedBuffer::iterator bufData = buffer.data();
PrivacyBuffer privacyBuf(create_message_privacy(300, list), bufData);
PrivacySpec spec;
@@ -244,8 +247,8 @@
TEST_F(PrivacyBufferTest, BadDataInNestedMessage) {
writeToFdBuffer(STRING_FIELD_0 + MESSAGE_FIELD_5 + "aoeoe");
- Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL };
- Privacy* field5[] = { create_message_privacy(5, list), NULL };
+ Privacy* list[] = {create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL};
+ Privacy* field5[] = {create_message_privacy(5, list), NULL};
EncodedBuffer::iterator bufData = buffer.data();
PrivacyBuffer privacyBuf(create_message_privacy(300, field5), bufData);
PrivacySpec spec;
@@ -256,7 +259,7 @@
string input = "\x2a\"" + VARINT_FIELD_1 + STRING_FIELD_2 + MESSAGE_FIELD_5;
writeToFdBuffer(input);
Privacy* field5 = create_message_privacy(5, NULL);
- Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), field5, NULL };
+ Privacy* list[] = {create_privacy(1, OTHER_TYPE, DEST_LOCAL), field5, NULL};
field5->children = list;
string expected = "\x2a\x1c" + STRING_FIELD_2 + "\x2a\xd" + STRING_FIELD_2;
assertStrip(DEST_EXPLICIT, expected, field5);
@@ -264,7 +267,7 @@
TEST_F(PrivacyBufferTest, AutoMessage) {
writeToFdBuffer(STRING_FIELD_2 + MESSAGE_FIELD_5);
- Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL };
+ Privacy* list[] = {create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL};
Privacy* autoMsg = create_privacy(5, MESSAGE_TYPE, DEST_AUTOMATIC);
autoMsg->children = list;
string expected = "\x2a\xd" + STRING_FIELD_2;
diff --git a/cmds/incidentd/tests/Reporter_test.cpp b/cmds/incidentd/tests/Reporter_test.cpp
index a1e3c34..bd359ac 100644
--- a/cmds/incidentd/tests/Reporter_test.cpp
+++ b/cmds/incidentd/tests/Reporter_test.cpp
@@ -11,8 +11,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "Reporter.h"
@@ -26,7 +25,6 @@
#include <gtest/gtest.h>
#include <string.h>
-
using namespace android;
using namespace android::base;
using namespace android::binder;
@@ -35,8 +33,7 @@
using ::testing::StrEq;
using ::testing::Test;
-class TestListener : public IIncidentReportStatusListener
-{
+class TestListener : public IIncidentReportStatusListener {
public:
int startInvoked;
int finishInvoked;
@@ -44,8 +41,8 @@
map<int, int> startSections;
map<int, int> finishSections;
- TestListener() : startInvoked(0), finishInvoked(0), failedInvoked(0) {};
- virtual ~TestListener() {};
+ TestListener() : startInvoked(0), finishInvoked(0), failedInvoked(0){};
+ virtual ~TestListener(){};
virtual Status onReportStarted() {
startInvoked++;
@@ -53,16 +50,14 @@
};
virtual Status onReportSectionStatus(int section, int status) {
switch (status) {
- case IIncidentReportStatusListener::STATUS_STARTING:
- if (startSections.count(section) == 0)
- startSections[section] = 0;
- startSections[section] = startSections[section] + 1;
- break;
- case IIncidentReportStatusListener::STATUS_FINISHED:
- if (finishSections.count(section) == 0)
- finishSections[section] = 0;
- finishSections[section] = finishSections[section] + 1;
- break;
+ case IIncidentReportStatusListener::STATUS_STARTING:
+ if (startSections.count(section) == 0) startSections[section] = 0;
+ startSections[section] = startSections[section] + 1;
+ break;
+ case IIncidentReportStatusListener::STATUS_FINISHED:
+ if (finishSections.count(section) == 0) finishSections[section] = 0;
+ finishSections[section] = finishSections[section] + 1;
+ break;
}
return Status::ok();
};
@@ -156,7 +151,8 @@
string result;
ReadFileToString(tf.path, &result);
- EXPECT_THAT(result, StrEq("\n\x2" "\b\f"));
+ EXPECT_THAT(result, StrEq("\n\x2"
+ "\b\f"));
EXPECT_EQ(l->startInvoked, 2);
EXPECT_EQ(l->finishInvoked, 2);
@@ -178,7 +174,11 @@
ASSERT_EQ(Reporter::REPORT_FINISHED, reporter->runReport());
vector<string> results = InspectFiles();
ASSERT_EQ((int)results.size(), 1);
- EXPECT_EQ(results[0], "\n\x2" "\b\f\n\x6" "\x12\x4" "abcd");
+ EXPECT_EQ(results[0],
+ "\n\x2"
+ "\b\f\n\x6"
+ "\x12\x4"
+ "abcd");
}
TEST_F(ReporterTest, ReportMetadata) {
diff --git a/cmds/incidentd/tests/Section_test.cpp b/cmds/incidentd/tests/Section_test.cpp
index 5752a67..a1f4fdc 100644
--- a/cmds/incidentd/tests/Section_test.cpp
+++ b/cmds/incidentd/tests/Section_test.cpp
@@ -11,8 +11,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
#include "Section.h"
@@ -30,9 +29,9 @@
const int QUICK_TIMEOUT_MS = 100;
-const string VARINT_FIELD_1 = "\x08\x96\x01"; // 150
+const string VARINT_FIELD_1 = "\x08\x96\x01"; // 150
const string STRING_FIELD_2 = "\x12\vwhatthefuck";
-const string FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff"; // -1
+const string FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff"; // -1
using namespace android::base;
using namespace android::binder;
@@ -44,11 +43,10 @@
// NOTICE: this test requires /system/bin/incident_helper is installed.
-class SimpleListener : public IIncidentReportStatusListener
-{
+class SimpleListener : public IIncidentReportStatusListener {
public:
- SimpleListener() {};
- virtual ~SimpleListener() {};
+ SimpleListener(){};
+ virtual ~SimpleListener(){};
virtual Status onReportStarted() { return Status::ok(); };
virtual Status onReportSectionStatus(int /*section*/, int /*status*/) { return Status::ok(); };
@@ -84,7 +82,9 @@
string content;
CaptureStdout();
ASSERT_EQ(NO_ERROR, hs.Execute(&requests));
- EXPECT_THAT(GetCapturedStdout(), StrEq("\n\x5" "\x12\x3" "axe\n\x05\x12\x03pup"));
+ EXPECT_THAT(GetCapturedStdout(), StrEq("\n\x5"
+ "\x12\x3"
+ "axe\n\x05\x12\x03pup"));
EXPECT_TRUE(ReadFileToString(output2.path, &content));
EXPECT_THAT(content, StrEq("\n\x05\x12\x03pup"));
@@ -271,12 +271,12 @@
string content, expect;
expect = VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3;
- char c = (char) expect.size();
+ char c = (char)expect.size();
EXPECT_TRUE(ReadFileToString(output1.path, &content));
EXPECT_THAT(content, StrEq(string("\x02") + c + expect));
expect = STRING_FIELD_2 + FIX64_FIELD_3;
- c = (char) expect.size();
+ c = (char)expect.size();
EXPECT_TRUE(ReadFileToString(output2.path, &content));
EXPECT_THAT(content, StrEq(string("\x02") + c + expect));
@@ -315,7 +315,7 @@
string content, expect;
expect = STRING_FIELD_2 + FIX64_FIELD_3;
- char c = (char) expect.size();
+ char c = (char)expect.size();
// output1 and output2 are the same
EXPECT_TRUE(ReadFileToString(output1.path, &content));
@@ -324,7 +324,7 @@
EXPECT_THAT(content, StrEq(string("\x02") + c + expect));
// output3 has only auto field
- c = (char) STRING_FIELD_2.size();
+ c = (char)STRING_FIELD_2.size();
EXPECT_TRUE(ReadFileToString(output3.path, &content));
EXPECT_THAT(content, StrEq(string("\x02") + c + STRING_FIELD_2));
}
\ No newline at end of file
diff --git a/cmds/incidentd/tests/section_list.cpp b/cmds/incidentd/tests/section_list.cpp
index 1d6213f..bd2d15c 100644
--- a/cmds/incidentd/tests/section_list.cpp
+++ b/cmds/incidentd/tests/section_list.cpp
@@ -1,25 +1,17 @@
// This file is a dummy section_list.cpp used for test only.
#include "section_list.h"
-const Section* SECTION_LIST[] = {
- NULL
-};
+const Section* SECTION_LIST[] = {NULL};
-Privacy sub_field_1 { 1, 1, NULL, DEST_LOCAL, NULL };
-Privacy sub_field_2 { 2, 9, NULL, DEST_AUTOMATIC, NULL };
+Privacy sub_field_1{1, 1, NULL, DEST_LOCAL, NULL};
+Privacy sub_field_2{2, 9, NULL, DEST_AUTOMATIC, NULL};
-Privacy* list[] = {
- &sub_field_1,
- &sub_field_2,
- NULL };
+Privacy* list[] = {&sub_field_1, &sub_field_2, NULL};
-Privacy field_0 { 0, 11, list, DEST_EXPLICIT, NULL };
-Privacy field_1 { 1, 9, NULL, DEST_AUTOMATIC, NULL };
+Privacy field_0{0, 11, list, DEST_EXPLICIT, NULL};
+Privacy field_1{1, 9, NULL, DEST_AUTOMATIC, NULL};
-Privacy* final_list[] = {
- &field_0,
- &field_1
-};
+Privacy* final_list[] = {&field_0, &field_1};
const Privacy** PRIVACY_POLICY_LIST = const_cast<const Privacy**>(final_list);
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index fbb0fdd..d0f55ab 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -59,45 +59,71 @@
}
void ConfigManager::AddListener(const sp<ConfigListener>& listener) {
+ lock_guard<mutex> lock(mMutex);
mListeners.push_back(listener);
}
void ConfigManager::UpdateConfig(const ConfigKey& key, const StatsdConfig& config) {
- // Add to set
- mConfigs.insert(key);
+ vector<sp<ConfigListener>> broadcastList;
+ {
+ lock_guard <mutex> lock(mMutex);
- // Save to disk
- update_saved_configs(key, config);
+ // Add to set
+ mConfigs.insert(key);
+
+ // Save to disk
+ update_saved_configs_locked(key, config);
+
+ for (sp<ConfigListener> listener : mListeners) {
+ broadcastList.push_back(listener);
+ }
+ }
// Tell everyone
- for (auto& listener : mListeners) {
+ for (sp<ConfigListener> listener:broadcastList) {
listener->OnConfigUpdated(key, config);
}
}
void ConfigManager::SetConfigReceiver(const ConfigKey& key, const sp<IBinder>& intentSender) {
+ lock_guard<mutex> lock(mMutex);
mConfigReceivers[key] = intentSender;
}
void ConfigManager::RemoveConfigReceiver(const ConfigKey& key) {
+ lock_guard<mutex> lock(mMutex);
mConfigReceivers.erase(key);
}
void ConfigManager::RemoveConfig(const ConfigKey& key) {
- auto it = mConfigs.find(key);
- if (it != mConfigs.end()) {
- // Remove from map
- mConfigs.erase(it);
+ vector<sp<ConfigListener>> broadcastList;
+ {
+ lock_guard <mutex> lock(mMutex);
- // Tell everyone
- for (auto& listener : mListeners) {
- listener->OnConfigRemoved(key);
+ auto it = mConfigs.find(key);
+ if (it != mConfigs.end()) {
+ // Remove from map
+ mConfigs.erase(it);
+
+ for (sp<ConfigListener> listener : mListeners) {
+ broadcastList.push_back(listener);
+ }
}
+
+ auto itReceiver = mConfigReceivers.find(key);
+ if (itReceiver != mConfigReceivers.end()) {
+ // Remove from map
+ mConfigReceivers.erase(itReceiver);
+ }
+
+ // Remove from disk. There can still be a lingering file on disk so we check
+ // whether or not the config was on memory.
+ remove_saved_configs(key);
}
- // Remove from disk. There can still be a lingering file on disk so we check
- // whether or not the config was on memory.
- remove_saved_configs(key);
+ for (sp<ConfigListener> listener:broadcastList) {
+ listener->OnConfigRemoved(key);
+ }
}
void ConfigManager::remove_saved_configs(const ConfigKey& key) {
@@ -107,23 +133,32 @@
void ConfigManager::RemoveConfigs(int uid) {
vector<ConfigKey> removed;
+ vector<sp<ConfigListener>> broadcastList;
+ {
+ lock_guard <mutex> lock(mMutex);
- for (auto it = mConfigs.begin(); it != mConfigs.end();) {
- // Remove from map
- if (it->GetUid() == uid) {
- remove_saved_configs(*it);
- removed.push_back(*it);
- mConfigReceivers.erase(*it);
- it = mConfigs.erase(it);
- } else {
- it++;
+
+ for (auto it = mConfigs.begin(); it != mConfigs.end();) {
+ // Remove from map
+ if (it->GetUid() == uid) {
+ remove_saved_configs(*it);
+ removed.push_back(*it);
+ mConfigReceivers.erase(*it);
+ it = mConfigs.erase(it);
+ } else {
+ it++;
+ }
+ }
+
+ for (sp<ConfigListener> listener : mListeners) {
+ broadcastList.push_back(listener);
}
}
// Remove separately so if they do anything in the callback they can't mess up our iteration.
for (auto& key : removed) {
// Tell everyone
- for (auto& listener : mListeners) {
+ for (sp<ConfigListener> listener:broadcastList) {
listener->OnConfigRemoved(key);
}
}
@@ -131,27 +166,38 @@
void ConfigManager::RemoveAllConfigs() {
vector<ConfigKey> removed;
+ vector<sp<ConfigListener>> broadcastList;
+ {
+ lock_guard <mutex> lock(mMutex);
- for (auto it = mConfigs.begin(); it != mConfigs.end();) {
- // Remove from map
- removed.push_back(*it);
- auto receiverIt = mConfigReceivers.find(*it);
- if (receiverIt != mConfigReceivers.end()) {
- mConfigReceivers.erase(*it);
+
+ for (auto it = mConfigs.begin(); it != mConfigs.end();) {
+ // Remove from map
+ removed.push_back(*it);
+ auto receiverIt = mConfigReceivers.find(*it);
+ if (receiverIt != mConfigReceivers.end()) {
+ mConfigReceivers.erase(*it);
+ }
+ it = mConfigs.erase(it);
}
- it = mConfigs.erase(it);
+
+ for (sp<ConfigListener> listener : mListeners) {
+ broadcastList.push_back(listener);
+ }
}
// Remove separately so if they do anything in the callback they can't mess up our iteration.
for (auto& key : removed) {
// Tell everyone
- for (auto& listener : mListeners) {
+ for (sp<ConfigListener> listener:broadcastList) {
listener->OnConfigRemoved(key);
}
}
}
vector<ConfigKey> ConfigManager::GetAllConfigKeys() const {
+ lock_guard<mutex> lock(mMutex);
+
vector<ConfigKey> ret;
for (auto it = mConfigs.cbegin(); it != mConfigs.cend(); ++it) {
ret.push_back(*it);
@@ -160,6 +206,8 @@
}
const sp<android::IBinder> ConfigManager::GetConfigReceiver(const ConfigKey& key) const {
+ lock_guard<mutex> lock(mMutex);
+
auto it = mConfigReceivers.find(key);
if (it == mConfigReceivers.end()) {
return nullptr;
@@ -169,6 +217,8 @@
}
void ConfigManager::Dump(FILE* out) {
+ lock_guard<mutex> lock(mMutex);
+
fprintf(out, "CONFIGURATIONS (%d)\n", (int)mConfigs.size());
fprintf(out, " uid name\n");
for (const auto& key : mConfigs) {
@@ -180,7 +230,7 @@
}
}
-void ConfigManager::update_saved_configs(const ConfigKey& key, const StatsdConfig& config) {
+void ConfigManager::update_saved_configs_locked(const ConfigKey& key, const StatsdConfig& config) {
// If there is a pre-existing config with same key we should first delete it.
remove_saved_configs(key);
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
index a2b2a0c..a0c1c1c 100644
--- a/cmds/statsd/src/config/ConfigManager.h
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -21,6 +21,7 @@
#include "config/ConfigListener.h"
#include <map>
+#include <mutex>
#include <set>
#include <string>
@@ -109,10 +110,12 @@
void Dump(FILE* out);
private:
+ mutable std::mutex mMutex;
+
/**
* Save the configs to disk.
*/
- void update_saved_configs(const ConfigKey& key, const StatsdConfig& config);
+ void update_saved_configs_locked(const ConfigKey& key, const StatsdConfig& config);
/**
* Remove saved configs from disk.
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index 944764b..4612009 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -233,6 +233,11 @@
(matcher.eq_int() == values[i].mValue.int_value)) {
return true;
}
+ // eq_int covers both int and long.
+ if (values[i].mValue.getType() == LONG &&
+ (matcher.eq_int() == values[i].mValue.long_value)) {
+ return true;
+ }
}
return false;
case FieldValueMatcher::ValueMatcherCase::kLtInt:
@@ -241,6 +246,11 @@
(values[i].mValue.int_value < matcher.lt_int())) {
return true;
}
+ // lt_int covers both int and long.
+ if (values[i].mValue.getType() == LONG &&
+ (values[i].mValue.long_value < matcher.lt_int())) {
+ return true;
+ }
}
return false;
case FieldValueMatcher::ValueMatcherCase::kGtInt:
@@ -249,6 +259,11 @@
(values[i].mValue.int_value > matcher.gt_int())) {
return true;
}
+ // gt_int covers both int and long.
+ if (values[i].mValue.getType() == LONG &&
+ (values[i].mValue.long_value > matcher.gt_int())) {
+ return true;
+ }
}
return false;
case FieldValueMatcher::ValueMatcherCase::kLtFloat:
@@ -273,6 +288,11 @@
(values[i].mValue.int_value <= matcher.lte_int())) {
return true;
}
+ // lte_int covers both int and long.
+ if (values[i].mValue.getType() == LONG &&
+ (values[i].mValue.long_value <= matcher.lte_int())) {
+ return true;
+ }
}
return false;
case FieldValueMatcher::ValueMatcherCase::kGteInt:
@@ -281,6 +301,11 @@
(values[i].mValue.int_value >= matcher.gte_int())) {
return true;
}
+ // gte_int covers both int and long.
+ if (values[i].mValue.getType() == LONG &&
+ (values[i].mValue.long_value >= matcher.gte_int())) {
+ return true;
+ }
}
return false;
default:
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 3b7936d..9c65371 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -111,12 +111,6 @@
sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker(const Alert &alert) {
std::lock_guard<std::mutex> lock(mMutex);
- if (alert.trigger_if_sum_gt() > alert.num_buckets() * mBucketSizeNs) {
- ALOGW("invalid alert: threshold (%f) > possible recordable value (%d x %lld)",
- alert.trigger_if_sum_gt(), alert.num_buckets(),
- (long long)mBucketSizeNs);
- return nullptr;
- }
sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, mConfigKey);
if (anomalyTracker != nullptr) {
mAnomalyTrackers.push_back(anomalyTracker);
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index b822f2c..a7d07e3 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -21,6 +21,7 @@
Landroid/app/ActivityManager;->isLowRamDeviceStatic()Z
Landroid/app/ActivityManager;->isUserRunning(I)Z
Landroid/app/ActivityManager;->mContext:Landroid/content/Context;
+Landroid/app/ActivityManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/app/IActivityManager;
Landroid/app/ActivityManagerNative;->getDefault()Landroid/app/IActivityManager;
Landroid/app/ActivityManager;->PROCESS_STATE_TOP:I
Landroid/app/ActivityManager$RecentTaskInfo;->firstActiveTime:J
@@ -40,6 +41,7 @@
Landroid/app/Activity;->mWindow:Landroid/view/Window;
Landroid/app/Activity;->mWindowManager:Landroid/view/WindowManager;
Landroid/app/Activity;->setDisablePreviewScreenshots(Z)V
+Landroid/app/Activity;->setPersistent(Z)V
Landroid/app/ActivityThread$ActivityClientRecord;->activityInfo:Landroid/content/pm/ActivityInfo;
Landroid/app/ActivityThread$ActivityClientRecord;->activity:Landroid/app/Activity;
Landroid/app/ActivityThread$ActivityClientRecord;->compatInfo:Landroid/content/res/CompatibilityInfo;
@@ -52,6 +54,7 @@
Landroid/app/ActivityThread$AppBindData;->appInfo:Landroid/content/pm/ApplicationInfo;
Landroid/app/ActivityThread$AppBindData;->info:Landroid/app/LoadedApk;
Landroid/app/ActivityThread$AppBindData;->instrumentationArgs:Landroid/os/Bundle;
+Landroid/app/ActivityThread$AppBindData;->processName:Ljava/lang/String;
Landroid/app/ActivityThread$AppBindData;->providers:Ljava/util/List;
Landroid/app/ActivityThread$BindServiceData;->intent:Landroid/content/Intent;
Landroid/app/ActivityThread$BindServiceData;->token:Landroid/os/IBinder;
@@ -87,15 +90,20 @@
Landroid/app/ActivityThread;->mActivities:Landroid/util/ArrayMap;
Landroid/app/ActivityThread;->mAllApplications:Ljava/util/ArrayList;
Landroid/app/ActivityThread;->mBoundApplication:Landroid/app/ActivityThread$AppBindData;
+Landroid/app/ActivityThread;->mDensityCompatMode:Z
Landroid/app/ActivityThread;->mH:Landroid/app/ActivityThread$H;
Landroid/app/ActivityThread;->mInitialApplication:Landroid/app/Application;
Landroid/app/ActivityThread;->mInstrumentation:Landroid/app/Instrumentation;
+Landroid/app/ActivityThread;->mLocalProvidersByName:Landroid/util/ArrayMap;
Landroid/app/ActivityThread;->mNumVisibleActivities:I
Landroid/app/ActivityThread;->mPackages:Landroid/util/ArrayMap;
Landroid/app/ActivityThread;->mProviderMap:Landroid/util/ArrayMap;
Landroid/app/ActivityThread;->mServices:Landroid/util/ArrayMap;
+Landroid/app/ActivityThread;->performNewIntents(Landroid/os/IBinder;Ljava/util/List;Z)V
Landroid/app/ActivityThread;->performStopActivity(Landroid/os/IBinder;ZLjava/lang/String;)V
+Landroid/app/ActivityThread$ProviderClientRecord;->mHolder:Landroid/app/ContentProviderHolder;
Landroid/app/ActivityThread$ProviderClientRecord;->mLocalProvider:Landroid/content/ContentProvider;
+Landroid/app/ActivityThread$ProviderClientRecord;->mProvider:Landroid/content/IContentProvider;
Landroid/app/ActivityThread$ReceiverData;->compatInfo:Landroid/content/res/CompatibilityInfo;
Landroid/app/ActivityThread$ReceiverData;->info:Landroid/content/pm/ActivityInfo;
Landroid/app/ActivityThread$ReceiverData;->intent:Landroid/content/Intent;
@@ -104,6 +112,7 @@
Landroid/app/ActivityThread$ServiceArgsData;->args:Landroid/content/Intent;
Landroid/app/ActivityThread$ServiceArgsData;->token:Landroid/os/IBinder;
Landroid/app/ActivityThread;->sPackageManager:Landroid/content/pm/IPackageManager;
+Landroid/app/ActivityThread;->startActivityNow(Landroid/app/Activity;Ljava/lang/String;Landroid/content/Intent;Landroid/content/pm/ActivityInfo;Landroid/os/IBinder;Landroid/os/Bundle;Landroid/app/Activity$NonConfigurationInstances;)Landroid/app/Activity;
Landroid/app/admin/DevicePolicyManager;->getDeviceOwnerComponentOnAnyUser()Landroid/content/ComponentName;
Landroid/app/admin/DevicePolicyManager;->getDeviceOwner()Ljava/lang/String;
Landroid/app/admin/DevicePolicyManager;->getProfileOwner()Landroid/content/ComponentName;
@@ -143,6 +152,7 @@
Landroid/app/ApplicationLoaders;->mLoaders:Landroid/util/ArrayMap;
Landroid/app/Application;->mComponentCallbacks:Ljava/util/ArrayList;
Landroid/app/Application;->mLoadedApk:Landroid/app/LoadedApk;
+Landroid/app/ApplicationPackageManager;->configurationChanged()V
Landroid/app/ApplicationPackageManager;->deletePackage(Ljava/lang/String;Landroid/content/pm/IPackageDeleteObserver;I)V
Landroid/app/ApplicationPackageManager;->getPackageSizeInfoAsUser(Ljava/lang/String;ILandroid/content/pm/IPackageStatsObserver;)V
Landroid/app/ApplicationPackageManager;-><init>(Landroid/app/ContextImpl;Landroid/content/pm/IPackageManager;)V
@@ -200,11 +210,15 @@
Landroid/app/backup/RestoreSession;->restoreAll(JLandroid/app/backup/RestoreObserver;)I
Landroid/app/backup/RestoreSet;-><init>(Ljava/lang/String;Ljava/lang/String;J)V
Landroid/app/backup/SelectBackupTransportCallback;-><init>()V
+Landroid/app/ContentProviderHolder;->info:Landroid/content/pm/ProviderInfo;
+Landroid/app/ContentProviderHolder;-><init>(Landroid/content/pm/ProviderInfo;)V
Landroid/app/ContentProviderHolder;->provider:Landroid/content/IContentProvider;
Landroid/app/ContextImpl;->createActivityContext(Landroid/app/ActivityThread;Landroid/app/LoadedApk;Landroid/content/pm/ActivityInfo;Landroid/os/IBinder;ILandroid/content/res/Configuration;)Landroid/app/ContextImpl;
Landroid/app/ContextImpl;->getActivityToken()Landroid/os/IBinder;
Landroid/app/ContextImpl;->getDisplay()Landroid/view/Display;
Landroid/app/ContextImpl;->getPreferencesDir()Ljava/io/File;
+Landroid/app/ContextImpl;->getReceiverRestrictedContext()Landroid/content/Context;
+Landroid/app/ContextImpl;->mBasePackageName:Ljava/lang/String;
Landroid/app/ContextImpl;->mContentResolver:Landroid/app/ContextImpl$ApplicationContentResolver;
Landroid/app/ContextImpl;->mMainThread:Landroid/app/ActivityThread;
Landroid/app/ContextImpl;->mOpPackageName:Ljava/lang/String;
@@ -216,6 +230,7 @@
Landroid/app/ContextImpl;->mTheme:Landroid/content/res/Resources$Theme;
Landroid/app/ContextImpl;->scheduleFinalCleanup(Ljava/lang/String;Ljava/lang/String;)V
Landroid/app/ContextImpl;->setOuterContext(Landroid/content/Context;)V
+Landroid/app/ContextImpl;->sSharedPrefsCache:Landroid/util/ArrayMap;
Landroid/app/DatePickerDialog;->mDatePicker:Landroid/widget/DatePicker;
Landroid/app/Dialog;->CANCEL:I
Landroid/app/Dialog;->dismissDialog()V
@@ -227,16 +242,23 @@
Landroid/app/DownloadManager$Request;->mUri:Landroid/net/Uri;
Landroid/app/FragmentManagerImpl;->mAdded:Ljava/util/ArrayList;
Landroid/app/Fragment;->mChildFragmentManager:Landroid/app/FragmentManagerImpl;
+Landroid/app/IActivityManager;->bindService(Landroid/app/IApplicationThread;Landroid/os/IBinder;Landroid/content/Intent;Ljava/lang/String;Landroid/app/IServiceConnection;ILjava/lang/String;I)I
+Landroid/app/IActivityManager;->finishActivity(Landroid/os/IBinder;ILandroid/content/Intent;I)Z
+Landroid/app/IActivityManager;->finishReceiver(Landroid/os/IBinder;ILjava/lang/String;Landroid/os/Bundle;ZI)V
Landroid/app/IActivityManager;->forceStopPackage(Ljava/lang/String;I)V
Landroid/app/IActivityManager;->getLaunchedFromPackage(Landroid/os/IBinder;)Ljava/lang/String;
Landroid/app/IActivityManager;->getTaskForActivity(Landroid/os/IBinder;Z)I
+Landroid/app/IActivityManager;->moveTaskToFront(IILandroid/os/Bundle;)V
+Landroid/app/IActivityManager;->publishContentProviders(Landroid/app/IApplicationThread;Ljava/util/List;)V
Landroid/app/IActivityManager;->resumeAppSwitches()V
Landroid/app/IActivityManager;->setRequestedOrientation(Landroid/os/IBinder;I)V
+Landroid/app/IActivityManager;->setTaskResizeable(II)V
Landroid/app/IActivityManager$Stub$Proxy;->getConfiguration()Landroid/content/res/Configuration;
Landroid/app/IActivityManager$Stub$Proxy;->getLaunchedFromUid(Landroid/os/IBinder;)I
Landroid/app/IActivityManager$Stub$Proxy;->getProcessPss([I)[J
Landroid/app/IActivityManager$Stub$Proxy;->isAppForeground(I)Z
Landroid/app/IActivityManager$Stub$Proxy;->mRemote:Landroid/os/IBinder;
+Landroid/app/IActivityManager;->unbindService(Landroid/app/IServiceConnection;)Z
Landroid/app/IAlarmManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/app/IAlarmManager$Stub;->TRANSACTION_remove:I
Landroid/app/IAlarmManager$Stub;->TRANSACTION_set:I
@@ -256,6 +278,8 @@
Landroid/app/IWallpaperManager;->getWallpaper(Ljava/lang/String;Landroid/app/IWallpaperManagerCallback;ILandroid/os/Bundle;I)Landroid/os/ParcelFileDescriptor;
Landroid/app/job/IJobScheduler$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/job/IJobScheduler;
Landroid/app/job/IJobScheduler$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Landroid/app/LoadedApk;->getClassLoader()Ljava/lang/ClassLoader;
+Landroid/app/LoadedApk;->getDataDirFile()Ljava/io/File;
Landroid/app/LoadedApk;->mActivityThread:Landroid/app/ActivityThread;
Landroid/app/LoadedApk;->makeApplication(ZLandroid/app/Instrumentation;)Landroid/app/Application;
Landroid/app/LoadedApk;->mAppDir:Ljava/lang/String;
@@ -263,7 +287,9 @@
Landroid/app/LoadedApk;->mApplication:Landroid/app/Application;
Landroid/app/LoadedApk;->mBaseClassLoader:Ljava/lang/ClassLoader;
Landroid/app/LoadedApk;->mClassLoader:Ljava/lang/ClassLoader;
+Landroid/app/LoadedApk;->mDataDirFile:Ljava/io/File;
Landroid/app/LoadedApk;->mDataDir:Ljava/lang/String;
+Landroid/app/LoadedApk;->mDisplayAdjustments:Landroid/view/DisplayAdjustments;
Landroid/app/LoadedApk;->mPackageName:Ljava/lang/String;
Landroid/app/LoadedApk;->mReceivers:Landroid/util/ArrayMap;
Landroid/app/LoadedApk;->mResDir:Ljava/lang/String;
@@ -276,6 +302,7 @@
Landroid/app/NativeActivity;->setWindowFormat(I)V
Landroid/app/NativeActivity;->showIme(I)V
Landroid/app/Notification$Builder;->mActions:Ljava/util/ArrayList;
+Landroid/app/Notification$Builder;->setChannel(Ljava/lang/String;)Landroid/app/Notification$Builder;
Landroid/app/Notification;->EXTRA_SUBSTITUTE_APP_NAME:Ljava/lang/String;
Landroid/app/Notification;->isGroupSummary()Z
Landroid/app/NotificationManager;->getService()Landroid/app/INotificationManager;
@@ -310,6 +337,7 @@
Landroid/app/StatusBarManager;->expandNotificationsPanel()V
Landroid/app/StatusBarManager;->expandSettingsPanel(Ljava/lang/String;)V
Landroid/app/StatusBarManager;->expandSettingsPanel()V
+Landroid/app/StatusBarManager;->getService()Lcom/android/internal/statusbar/IStatusBarService;
Landroid/app/TimePickerDialog;->mTimePicker:Landroid/widget/TimePicker;
Landroid/app/trust/ITrustManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/app/usage/UsageStatsManager;->getAppStandbyBuckets()Ljava/util/Map;
@@ -361,6 +389,8 @@
Landroid/content/AsyncTaskLoader;->mExecutor:Ljava/util/concurrent/Executor;
Landroid/content/BroadcastReceiver$PendingResult;-><init>(ILjava/lang/String;Landroid/os/Bundle;IZZLandroid/os/IBinder;II)V
Landroid/content/BroadcastReceiver;->setPendingResult(Landroid/content/BroadcastReceiver$PendingResult;)V
+Landroid/content/ContentProviderClient;->mContentProvider:Landroid/content/IContentProvider;
+Landroid/content/ContentProviderClient;->mPackageName:Ljava/lang/String;
Landroid/content/ContentProvider;->mContext:Landroid/content/Context;
Landroid/content/ContentProvider;->mPathPermissions:[Landroid/content/pm/PathPermission;
Landroid/content/ContentProvider;->mReadPermission:Ljava/lang/String;
@@ -394,9 +424,11 @@
Landroid/content/CursorLoader;->mCancellationSignal:Landroid/os/CancellationSignal;
Landroid/content/CursorLoader;->mObserver:Landroid/content/Loader$ForceLoadContentObserver;
Landroid/content/IClipboard$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IClipboard;
+Landroid/content/IContentProvider;->call(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/os/Bundle;)Landroid/os/Bundle;
Landroid/content/IContentService;->cancelSync(Landroid/accounts/Account;Ljava/lang/String;Landroid/content/ComponentName;)V
Landroid/content/IContentService;->getMasterSyncAutomatically()Z
Landroid/content/IContentService;->setMasterSyncAutomatically(Z)V
+Landroid/content/IContentService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IContentService;
Landroid/content/IContentService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/Intent;->ACTION_ALARM_CHANGED:Ljava/lang/String;
Landroid/content/IntentFilter;->mActions:Ljava/util/ArrayList;
@@ -429,6 +461,7 @@
Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackagesForUid(I)[Ljava/lang/String;
Landroid/content/pm/IPackageManager$Stub$Proxy;->getSystemSharedLibraryNames()[Ljava/lang/String;
Landroid/content/pm/IPackageStatsObserver$Stub;-><init>()V
+Landroid/content/pm/LauncherActivityInfo;->mActivityInfo:Landroid/content/pm/ActivityInfo;
Landroid/content/pm/LauncherApps;->mPm:Landroid/content/pm/PackageManager;
Landroid/content/pm/LauncherApps;->startShortcut(Ljava/lang/String;Ljava/lang/String;Landroid/graphics/Rect;Landroid/os/Bundle;I)V
Landroid/content/pm/PackageInstaller$SessionParams;->setAllocateAggressive(Z)V
@@ -570,6 +603,7 @@
Landroid/content/SyncStatusInfo;->lastSuccessTime:J
Landroid/database/AbstractCursor;->mExtras:Landroid/os/Bundle;
Landroid/database/AbstractCursor;->mNotifyUri:Landroid/net/Uri;
+Landroid/database/AbstractCursor;->mRowIdColumnIndex:I
Landroid/database/CursorWindow;->mWindowPtr:J
Landroid/database/CursorWindow;->sCursorWindowSize:I
Landroid/database/CursorWindow;->sWindowToPidMap:Landroid/util/LongSparseArray;
@@ -1100,6 +1134,7 @@
Landroid/net/wifi/WifiEnterpriseConfig;->getCaCertificateAlias()Ljava/lang/String;
Landroid/net/wifi/WifiEnterpriseConfig;->getClientCertificateAlias()Ljava/lang/String;
Landroid/net/wifi/WifiInfo;->getMeteredHint()Z
+Landroid/net/wifi/WifiInfo;->mMacAddress:Ljava/lang/String;
Landroid/net/wifi/WifiManager;->cancelLocalOnlyHotspotRequest()V
Landroid/net/wifi/WifiManager;->connect(ILandroid/net/wifi/WifiManager$ActionListener;)V
Landroid/net/wifi/WifiManager;->connect(Landroid/net/wifi/WifiConfiguration;Landroid/net/wifi/WifiManager$ActionListener;)V
@@ -1513,6 +1548,13 @@
Landroid/telephony/SignalStrength;->getLteRsrq()I
Landroid/telephony/SignalStrength;->getLteRssnr()I
Landroid/telephony/SignalStrength;->getLteSignalStrength()I
+Landroid/telephony/SignalStrength;->mGsmBitErrorRate:I
+Landroid/telephony/SignalStrength;->mGsmSignalStrength:I
+Landroid/telephony/SignalStrength;->mLteCqi:I
+Landroid/telephony/SignalStrength;->mLteRsrp:I
+Landroid/telephony/SignalStrength;->mLteRsrq:I
+Landroid/telephony/SignalStrength;->mLteRssnr:I
+Landroid/telephony/SignalStrength;->mLteSignalStrength:I
Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_GOOD:I
Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_GREAT:I
Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_MODERATE:I
@@ -1564,6 +1606,7 @@
Landroid/telephony/TelephonyManager;-><init>()V
Landroid/telephony/TelephonyManager;->isMultiSimEnabled()Z
Landroid/telephony/TelephonyManager;->isNetworkRoaming(I)Z
+Landroid/telephony/TelephonyManager;->isVolteAvailable()Z
Landroid/telephony/TelephonyManager;->setDataEnabled(IZ)V
Landroid/text/AndroidBidi;->bidi(I[C[B)I
Landroid/text/DynamicLayout;-><init>(Ljava/lang/CharSequence;Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout$Alignment;Landroid/text/TextDirectionHeuristic;FFZIIILandroid/text/TextUtils$TruncateAt;I)V
@@ -1650,6 +1693,7 @@
Landroid/view/Choreographer;->removeCallbacks(ILjava/lang/Runnable;Ljava/lang/Object;)V
Landroid/view/Choreographer;->scheduleVsyncLocked()V
Landroid/view/Choreographer;->USE_VSYNC:Z
+Landroid/view/ContextThemeWrapper;->getThemeResId()I
Landroid/view/ContextThemeWrapper;->mResources:Landroid/content/res/Resources;
Landroid/view/ContextThemeWrapper;->mTheme:Landroid/content/res/Resources$Theme;
Landroid/view/ContextThemeWrapper;->mThemeResource:I
@@ -1675,6 +1719,7 @@
Landroid/view/InputEventReceiver;->dispatchBatchedInputEventPending()V
Landroid/view/InputEventReceiver;->dispatchInputEvent(ILandroid/view/InputEvent;I)V
Landroid/view/InputEventSender;->dispatchInputEventFinished(IZ)V
+Landroid/view/inputmethod/InputMethodInfo;->mSubtypes:Landroid/view/inputmethod/InputMethodSubtypeArray;
Landroid/view/inputmethod/InputMethodManager;->finishInputLocked()V
Landroid/view/inputmethod/InputMethodManager;->focusIn(Landroid/view/View;)V
Landroid/view/inputmethod/InputMethodManager;->getInputMethodWindowVisibleHeight()I
@@ -1688,6 +1733,7 @@
Landroid/view/inputmethod/InputMethodManager;->showSoftInputUnchecked(ILandroid/os/ResultReceiver;)V
Landroid/view/inputmethod/InputMethodManager;->sInstance:Landroid/view/inputmethod/InputMethodManager;
Landroid/view/inputmethod/InputMethodManager;->windowDismissed(Landroid/os/IBinder;)V
+Landroid/view/inputmethod/InputMethodSubtypeArray;-><init>(Ljava/util/List;)V
Landroid/view/InputQueue;->finishInputEvent(JZ)V
Landroid/view/IWindowManager;->getAnimationScale(I)F
Landroid/view/IWindowManager;->hasNavigationBar()Z
@@ -1881,6 +1927,7 @@
Landroid/view/WindowManagerGlobal;->getRootView(Ljava/lang/String;)Landroid/view/View;
Landroid/view/WindowManagerGlobal;->getViewRootNames()[Ljava/lang/String;
Landroid/view/WindowManagerGlobal;->getWindowManagerService()Landroid/view/IWindowManager;
+Landroid/view/WindowManagerGlobal;->initialize()V
Landroid/view/WindowManagerGlobal;->mLock:Ljava/lang/Object;
Landroid/view/WindowManagerGlobal;->mParams:Ljava/util/ArrayList;
Landroid/view/WindowManagerGlobal;->mRoots:Ljava/util/ArrayList;
@@ -2087,6 +2134,7 @@
Landroid/widget/PopupWindow;->mLastWidth:I
Landroid/widget/PopupWindow;->mOnScrollChangedListener:Landroid/view/ViewTreeObserver$OnScrollChangedListener;
Landroid/widget/PopupWindow;->mOverlapAnchor:Z
+Landroid/widget/PopupWindow;->mTouchInterceptor:Landroid/view/View$OnTouchListener;
Landroid/widget/PopupWindow;->mWidthMode:I
Landroid/widget/PopupWindow;->mWindowLayoutType:I
Landroid/widget/PopupWindow;->preparePopup(Landroid/view/WindowManager$LayoutParams;)V
@@ -2109,10 +2157,14 @@
Landroid/widget/RemoteViews$Action;->mergeBehavior()I
Landroid/widget/RemoteViews$Action;->viewId:I
Landroid/widget/RemoteViews$BitmapCache;->mBitmaps:Ljava/util/ArrayList;
+Landroid/widget/RemoteViews$BitmapReflectionAction;->bitmap:Landroid/graphics/Bitmap;
+Landroid/widget/RemoteViews$BitmapReflectionAction;->methodName:Ljava/lang/String;
+Landroid/widget/RemoteViews;->estimateMemoryUsage()I
Landroid/widget/RemoteViews;->mActions:Ljava/util/ArrayList;
Landroid/widget/RemoteViews;->mApplication:Landroid/content/pm/ApplicationInfo;
Landroid/widget/RemoteViews;->mBitmapCache:Landroid/widget/RemoteViews$BitmapCache;
Landroid/widget/RemoteViews;->mergeRemoteViews(Landroid/widget/RemoteViews;)V
+Landroid/widget/RemoteViews;->mPortrait:Landroid/widget/RemoteViews;
Landroid/widget/RemoteViews$ReflectionAction;->methodName:Ljava/lang/String;
Landroid/widget/ScrollBarDrawable;->mVerticalThumb:Landroid/graphics/drawable/Drawable;
Landroid/widget/ScrollBarDrawable;->setHorizontalThumbDrawable(Landroid/graphics/drawable/Drawable;)V
@@ -2145,6 +2197,7 @@
Landroid/widget/TextView;->mMaximum:I
Landroid/widget/TextView;->mMaxMode:I
Landroid/widget/TextView;->mSingleLine:Z
+Landroid/widget/TextView;->mTextPaint:Landroid/text/TextPaint;
Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;Landroid/widget/TextView$BufferType;ZI)V
Landroid/widget/Toast;->getService()Landroid/app/INotificationManager;
Landroid/widget/Toast;->sService:Landroid/app/INotificationManager;
@@ -2154,6 +2207,7 @@
Landroid/widget/VideoView;->mUri:Landroid/net/Uri;
Landroid/widget/VideoView;->mVideoHeight:I
Landroid/widget/VideoView;->mVideoWidth:I
+Lcom/android/internal/app/IAppOpsService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IAppOpsService;
Lcom/android/internal/app/IAppOpsService$Stub$Proxy;->checkOperation(IILjava/lang/String;)I
Lcom/android/internal/app/IAppOpsService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/app/IBatteryStats;->getStatistics()[B
@@ -2244,6 +2298,13 @@
Lcom/android/internal/R$integer;->config_screenBrightnessDim:I
Lcom/android/internal/R$integer;->config_toastDefaultGravity:I
Lcom/android/internal/R$layout;->screen_title:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_accountPreferences:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_accountType:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_customTokens:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator:[I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_icon:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_label:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_smallIcon:I
Lcom/android/internal/R$styleable;->AndroidManifestApplication_enabled:I
Lcom/android/internal/R$styleable;->AndroidManifestApplication_hardwareAccelerated:I
Lcom/android/internal/R$styleable;->AndroidManifestApplication:[I
@@ -2274,6 +2335,14 @@
Lcom/android/internal/R$styleable;->ImageView_src:I
Lcom/android/internal/R$styleable;->ScrollView_fillViewport:I
Lcom/android/internal/R$styleable;->ScrollView:[I
+Lcom/android/internal/R$styleable;->SyncAdapter_accountType:I
+Lcom/android/internal/R$styleable;->SyncAdapter_allowParallelSyncs:I
+Lcom/android/internal/R$styleable;->SyncAdapter_contentAuthority:I
+Lcom/android/internal/R$styleable;->SyncAdapter:[I
+Lcom/android/internal/R$styleable;->SyncAdapter_isAlwaysSyncable:I
+Lcom/android/internal/R$styleable;->SyncAdapter_settingsActivity:I
+Lcom/android/internal/R$styleable;->SyncAdapter_supportsUploading:I
+Lcom/android/internal/R$styleable;->SyncAdapter_userVisible:I
Lcom/android/internal/R$styleable;->TabWidget:[I
Lcom/android/internal/R$styleable;->TextView_drawableBottom:I
Lcom/android/internal/R$styleable;->TextView_drawableLeft:I
@@ -2289,7 +2358,11 @@
Lcom/android/internal/R$styleable;->ViewStub:[I
Lcom/android/internal/R$styleable;->ViewStub_inflatedId:I
Lcom/android/internal/R$styleable;->ViewStub_layout:I
+Lcom/android/internal/R$styleable;->Window:[I
Lcom/android/internal/R$styleable;->Window_windowActionBarFullscreenDecorLayout:I
+Lcom/android/internal/R$styleable;->Window_windowIsFloating:I
+Lcom/android/internal/R$styleable;->Window_windowIsTranslucent:I
+Lcom/android/internal/R$styleable;->Window_windowShowWallpaper:I
Lcom/android/internal/R$style;->Theme:I
Lcom/android/internal/R$xml;->power_profile:I
Lcom/android/internal/telephony/IPhoneSubInfo$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IPhoneSubInfo;
@@ -2339,6 +2412,7 @@
Ldalvik/system/CloseGuard;->get()Ldalvik/system/CloseGuard;
Ldalvik/system/CloseGuard;->open(Ljava/lang/String;)V
Ldalvik/system/CloseGuard;->warnIfOpen()V
+Ldalvik/system/DexFile;->getClassNameList(Ljava/lang/Object;)[Ljava/lang/String;
Ldalvik/system/DexFile;->loadClassBinaryName(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/util/List;)Ljava/lang/Class;
Ldalvik/system/DexFile;->mCookie:Ljava/lang/Object;
Ldalvik/system/DexFile;->mFileName:Ljava/lang/String;
@@ -2350,10 +2424,12 @@
Ldalvik/system/DexPathList$Element;-><init>(Ljava/io/File;ZLjava/io/File;Ldalvik/system/DexFile;)V
Ldalvik/system/DexPathList;-><init>(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;Ljava/io/File;)V
Ldalvik/system/DexPathList;->makeDexElements(Ljava/util/List;Ljava/io/File;Ljava/util/List;Ljava/lang/ClassLoader;)[Ldalvik/system/DexPathList$Element;
+Ldalvik/system/DexPathList;->makeInMemoryDexElements([Ljava/nio/ByteBuffer;Ljava/util/List;)[Ldalvik/system/DexPathList$Element;
Ldalvik/system/DexPathList;->makePathElements(Ljava/util/List;)[Ldalvik/system/DexPathList$NativeLibraryElement;
Ldalvik/system/DexPathList;->makePathElements(Ljava/util/List;Ljava/io/File;Ljava/util/List;)[Ldalvik/system/DexPathList$Element;
Ldalvik/system/DexPathList;->nativeLibraryDirectories:Ljava/util/List;
Ldalvik/system/DexPathList$NativeLibraryElement;-><init>(Ljava/io/File;)V
+Ldalvik/system/DexPathList$NativeLibraryElement;->path:Ljava/io/File;
Ldalvik/system/DexPathList;->nativeLibraryPathElements:[Ldalvik/system/DexPathList$NativeLibraryElement;
Ldalvik/system/DexPathList;->splitPaths(Ljava/lang/String;Z)Ljava/util/List;
Ldalvik/system/DexPathList;->systemNativeLibraryDirectories:Ljava/util/List;
@@ -2369,6 +2445,7 @@
Ldalvik/system/VMRuntime;->runFinalization(J)V
Ldalvik/system/VMRuntime;->setMinimumHeapSize(J)J
Ldalvik/system/VMRuntime;->setTargetHeapUtilization(F)F
+Ldalvik/system/VMRuntime;->setTargetSdkVersion(I)V
Ldalvik/system/VMRuntime;->trackExternalAllocation(J)Z
Ldalvik/system/VMRuntime;->trackExternalFree(J)V
Ldalvik/system/VMRuntime;->vmInstructionSet()Ljava/lang/String;
@@ -2620,8 +2697,10 @@
Ljava/util/concurrent/ThreadLocalRandom;->writeObject(Ljava/io/ObjectOutputStream;)V
Ljava/util/Date;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/util/Date;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/EnumMap;->keyType:Ljava/lang/Class;
Ljava/util/EnumMap;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/util/EnumMap;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/EnumSet;->elementType:Ljava/lang/Class;
Ljava/util/EnumSet;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/util/GregorianCalendar;->readObject(Ljava/io/ObjectInputStream;)V
Ljava/util/HashMap$HashIterator;->hasNext()Z
diff --git a/core/java/android/annotation/OWNERS b/core/java/android/annotation/OWNERS
new file mode 100644
index 0000000..d6bb71b
--- /dev/null
+++ b/core/java/android/annotation/OWNERS
@@ -0,0 +1 @@
+tnorbye@google.com
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 6c3d248..8a9efe8 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -17,6 +17,7 @@
package android.app;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
+
import static java.lang.Character.MIN_VALUE;
import android.annotation.CallSuper;
@@ -135,6 +136,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -1898,7 +1900,7 @@
if (isFinishing()) {
if (mAutoFillResetNeeded) {
- getAutofillManager().onActivityFinished();
+ getAutofillManager().onActivityFinishing();
} else if (mIntent != null
&& mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)) {
// Activity was launched when user tapped a link in the Autofill Save UI - since
@@ -7689,6 +7691,9 @@
}
}
}
+ if (android.view.autofill.Helper.sVerbose) {
+ Log.v(TAG, "autofillClientGetViewVisibility(): " + Arrays.toString(visible));
+ }
return visible;
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 4c9fb74..1026550 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -543,7 +543,6 @@
OP_CAMERA,
// Body sensors
OP_BODY_SENSORS,
- OP_REQUEST_DELETE_PACKAGES,
// APPOP PERMISSIONS
OP_ACCESS_NOTIFICATIONS,
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index a788989..b072ee6 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1000,7 +1000,7 @@
*/
@Override
public boolean isAutofillCompatibilityEnabled() {
- return mBase.isAutofillCompatibilityEnabled();
+ return mBase != null && mBase.isAutofillCompatibilityEnabled();
}
/**
@@ -1008,6 +1008,8 @@
*/
@Override
public void setAutofillCompatibilityEnabled(boolean autofillCompatEnabled) {
- mBase.setAutofillCompatibilityEnabled(autofillCompatEnabled);
+ if (mBase != null) {
+ mBase.setAutofillCompatibilityEnabled(autofillCompatEnabled);
+ }
}
}
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index cf01451..424fa83 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -27,9 +27,11 @@
import android.annotation.StyleableRes;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo.Config;
+import android.content.res.AssetManager.AssetInputStream;
import android.content.res.Configuration.NativeConfig;
import android.content.res.Resources.NotFoundException;
import android.graphics.Bitmap;
+import android.graphics.ImageDecoder;
import android.graphics.Typeface;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -752,6 +754,26 @@
}
/**
+ * Loads a Drawable from an encoded image stream, or null.
+ *
+ * This call will handle closing ais.
+ */
+ private Drawable decodeImageDrawable(@NonNull AssetInputStream ais,
+ @NonNull Resources wrapper, @NonNull TypedValue value) {
+ ImageDecoder.Source src = new ImageDecoder.AssetInputStreamSource(ais,
+ wrapper, value);
+ try {
+ return ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
+ decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+ });
+ } catch (IOException ioe) {
+ // This is okay. This may be something that ImageDecoder does not
+ // support, like SVG.
+ return null;
+ }
+ }
+
+ /**
* Loads a drawable from XML or resources stream.
*/
@NonNull
@@ -811,8 +833,8 @@
} else {
final InputStream is = mAssets.openNonAsset(
value.assetCookie, file, AssetManager.ACCESS_STREAMING);
- dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
- is.close();
+ AssetInputStream ais = (AssetInputStream) is;
+ dr = decodeImageDrawable(ais, wrapper, value);
}
} finally {
stack.pop();
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 931b5c9..f08e1cc 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -242,6 +242,9 @@
/**
* Returns the number of physical cameras available on this device.
+ * The return value of this method might change dynamically if the device
+ * supports external cameras and an external camera is connected or
+ * disconnected.
*
* @return total number of accessible camera devices, or 0 if there are no
* cameras or an error was encountered enumerating them.
@@ -3542,8 +3545,8 @@
/**
* Gets the horizontal angle of view in degrees.
*
- * @return horizontal angle of view. This method will always return a
- * valid value.
+ * @return horizontal angle of view. Returns -1.0 when the device
+ * doesn't report view angle information.
*/
public float getHorizontalViewAngle() {
return Float.parseFloat(get(KEY_HORIZONTAL_VIEW_ANGLE));
@@ -3552,8 +3555,8 @@
/**
* Gets the vertical angle of view in degrees.
*
- * @return vertical angle of view. This method will always return a
- * valid value.
+ * @return vertical angle of view. Returns -1.0 when the device
+ * doesn't report view angle information.
*/
public float getVerticalViewAngle() {
return Float.parseFloat(get(KEY_VERTICAL_VIEW_ANGLE));
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 732f6a5..e558b7e 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -829,19 +829,24 @@
* <li>{@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}</li>
* </ul>
* </li>
+ * <li>The SENSOR_INFO_TIMESTAMP_SOURCE of the logical device and physical devices must be
+ * the same.</li>
* <li>The logical camera device must be LIMITED or higher device.</li>
* </ul>
* <p>Both the logical camera device and its underlying physical devices support the
* mandatory stream combinations required for their device levels.</p>
* <p>Additionally, for each guaranteed stream combination, the logical camera supports:</p>
* <ul>
- * <li>Replacing one logical {@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888}
+ * <li>For each guaranteed stream combination, the logical camera supports replacing one
+ * logical {@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888}
* or raw stream with two physical streams of the same size and format, each from a
* separate physical camera, given that the size and format are supported by both
* physical cameras.</li>
- * <li>Adding two raw streams, each from one physical camera, if the logical camera doesn't
- * advertise RAW capability, but the underlying physical cameras do. This is usually
- * the case when the physical cameras have different sensor sizes.</li>
+ * <li>If the logical camera doesn't advertise RAW capability, but the underlying physical
+ * cameras do, the logical camera will support guaranteed stream combinations for RAW
+ * capability, except that the RAW streams will be physical streams, each from a separate
+ * physical camera. This is usually the case when the physical cameras have different
+ * sensor sizes.</li>
* </ul>
* <p>Using physical streams in place of a logical stream of the same size and format will
* not slow down the frame rate of the capture, as long as the minimum frame duration
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index b205e2c..a040a09 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -82,11 +82,9 @@
*
* </ul>
*
- * <p>Please note that surface sharing is currently only enabled for outputs that use the
- * {@link ImageFormat#PRIVATE} format. This includes surface sources like
- * {@link android.view.SurfaceView}, {@link android.media.MediaRecorder},
- * {@link android.graphics.SurfaceTexture} and {@link android.media.ImageReader}, configured using
- * the aforementioned format.</p>
+ * <p> As of {@link android.os.Build.VERSION_CODES#P Android P}, all formats can be used for
+ * sharing, subject to device support. On prior API levels, only {@link ImageFormat#PRIVATE}
+ * format may be used.</p>
*
* @see CameraDevice#createCaptureSessionByOutputConfigurations
*
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index 5b15c0d..9e5174a 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -222,7 +222,10 @@
* @param endpoint the endpoint for this transaction
* @param buffer buffer for data to send or receive; can be {@code null} to wait for next
* transaction without reading data
- * @param length the length of the data to send or receive
+ * @param length the length of the data to send or receive. Before
+ * {@value Build.VERSION_CODES#P}, a value larger than 16384 bytes
+ * would be truncated down to 16384. In API {@value Build.VERSION_CODES#P}
+ * and after, any value of length is valid.
* @param timeout in milliseconds, 0 is infinite
* @return length of data transferred (or zero) for success,
* or negative value for failure
@@ -239,7 +242,10 @@
* @param endpoint the endpoint for this transaction
* @param buffer buffer for data to send or receive
* @param offset the index of the first byte in the buffer to send or receive
- * @param length the length of the data to send or receive
+ * @param length the length of the data to send or receive. Before
+ * {@value Build.VERSION_CODES#P}, a value larger than 16384 bytes
+ * would be truncated down to 16384. In API {@value Build.VERSION_CODES#P}
+ * and after, any value of length is valid.
* @param timeout in milliseconds, 0 is infinite
* @return length of data transferred (or zero) for success,
* or negative value for failure
@@ -247,6 +253,10 @@
public int bulkTransfer(UsbEndpoint endpoint,
byte[] buffer, int offset, int length, int timeout) {
checkBounds(buffer, offset, length);
+ if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P
+ && length > UsbRequest.MAX_USBFS_BUFFER_SIZE) {
+ length = UsbRequest.MAX_USBFS_BUFFER_SIZE;
+ }
return native_bulk_request(endpoint.getAddress(), buffer, offset, length, timeout);
}
diff --git a/core/java/android/hardware/usb/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java
index 2e8f8e1..f59c87e 100644
--- a/core/java/android/hardware/usb/UsbRequest.java
+++ b/core/java/android/hardware/usb/UsbRequest.java
@@ -17,6 +17,7 @@
package android.hardware.usb;
import android.annotation.Nullable;
+import android.os.Build;
import android.util.Log;
import com.android.internal.util.Preconditions;
@@ -43,7 +44,7 @@
private static final String TAG = "UsbRequest";
// From drivers/usb/core/devio.c
- private static final int MAX_USBFS_BUFFER_SIZE = 16384;
+ static final int MAX_USBFS_BUFFER_SIZE = 16384;
// used by the JNI code
private long mNativeContext;
@@ -175,7 +176,9 @@
* capacity will be ignored. Once the request
* {@link UsbDeviceConnection#requestWait() is processed} the position will be set
* to the number of bytes read/written.
- * @param length number of bytes to read or write.
+ * @param length number of bytes to read or write. Before {@value Build.VERSION_CODES#P}, a
+ * value larger than 16384 bytes would be truncated down to 16384. In API
+ * {@value Build.VERSION_CODES#P} and after, any value of length is valid.
*
* @return true if the queueing operation succeeded
*
@@ -186,6 +189,11 @@
boolean out = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
boolean result;
+ if (mConnection.getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P
+ && length > MAX_USBFS_BUFFER_SIZE) {
+ length = MAX_USBFS_BUFFER_SIZE;
+ }
+
synchronized (mLock) {
// save our buffer for when the request has completed
mBuffer = buffer;
@@ -222,7 +230,10 @@
* of the buffer is undefined until the request is returned by
* {@link UsbDeviceConnection#requestWait}. If the request failed the buffer
* will be unchanged; if the request succeeded the position of the buffer is
- * incremented by the number of bytes sent/received.
+ * incremented by the number of bytes sent/received. Before
+ * {@value Build.VERSION_CODES#P}, a buffer of length larger than 16384 bytes
+ * would throw IllegalArgumentException. In API {@value Build.VERSION_CODES#P}
+ * and after, any size buffer is valid.
*
* @return true if the queueing operation succeeded
*/
@@ -244,9 +255,12 @@
mIsUsingNewQueue = true;
wasQueued = native_queue(null, 0, 0);
} else {
- // Can only send/receive MAX_USBFS_BUFFER_SIZE bytes at once
- Preconditions.checkArgumentInRange(buffer.remaining(), 0, MAX_USBFS_BUFFER_SIZE,
- "number of remaining bytes");
+ if (mConnection.getContext().getApplicationInfo().targetSdkVersion
+ < Build.VERSION_CODES.P) {
+ // Can only send/receive MAX_USBFS_BUFFER_SIZE bytes at once
+ Preconditions.checkArgumentInRange(buffer.remaining(), 0, MAX_USBFS_BUFFER_SIZE,
+ "number of remaining bytes");
+ }
// Can not receive into read-only buffers.
Preconditions.checkArgument(!(buffer.isReadOnly() && !isSend), "buffer can not be "
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 7dde2ed..91c99be 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2662,7 +2662,7 @@
* A {@code NetworkCallback} is registered by calling
* {@link #requestNetwork(NetworkRequest, NetworkCallback)},
* {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)},
- * or {@link #registerDefaultNetworkCallback(NetworkCallback). A {@code NetworkCallback} is
+ * or {@link #registerDefaultNetworkCallback(NetworkCallback)}. A {@code NetworkCallback} is
* unregistered by calling {@link #unregisterNetworkCallback(NetworkCallback)}.
* A {@code NetworkCallback} should be registered at most once at any time.
* A {@code NetworkCallback} that has been unregistered can be registered again.
diff --git a/core/java/android/os/storage/StorageResultCode.java b/core/java/android/os/storage/StorageResultCode.java
deleted file mode 100644
index c843887..0000000
--- a/core/java/android/os/storage/StorageResultCode.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2007 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.storage;
-
-/**
- * Class that provides access to constants returned from StorageManager
- * and lower level StorageManagerService APIs.
- *
- * @hide
- */
-public class StorageResultCode
-{
- /**
- * Operation succeeded.
- * @see android.os.storage.StorageManager
- */
- public static final int OperationSucceeded = 0;
-
- /**
- * Operation failed: Internal error.
- * @see android.os.storage.StorageManager
- */
- public static final int OperationFailedInternalError = -1;
-
- /**
- * Operation failed: Missing media.
- * @see android.os.storage.StorageManager
- */
- public static final int OperationFailedNoMedia = -2;
-
- /**
- * Operation failed: Media is blank.
- * @see android.os.storage.StorageManager
- */
- public static final int OperationFailedMediaBlank = -3;
-
- /**
- * Operation failed: Media is corrupt.
- * @see android.os.storage.StorageManager
- */
- public static final int OperationFailedMediaCorrupt = -4;
-
- /**
- * Operation failed: Storage not mounted.
- * @see android.os.storage.StorageManager
- */
- public static final int OperationFailedStorageNotMounted = -5;
-
- /**
- * Operation failed: Storage is mounted.
- * @see android.os.storage.StorageManager
- */
- public static final int OperationFailedStorageMounted = -6;
-
- /**
- * Operation failed: Storage is busy.
- * @see android.os.storage.StorageManager
- */
- public static final int OperationFailedStorageBusy = -7;
-
-}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 05ab486..598eeef 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3692,18 +3692,15 @@
new SettingsValidators.InclusiveIntegerRangeValidator(0, 3);
/**
- * User-selected RTT mode
+ * User-selected RTT mode. When on, outgoing and incoming calls will be answered as RTT
+ * calls when supported by the device and carrier. Boolean value.
* 0 = OFF
- * 1 = FULL
- * 2 = VCO
- * 3 = HCO
- * Uses the same constants as TTY (e.g. {@link android.telecom.TelecomManager#TTY_MODE_OFF})
- * @hide
+ * 1 = ON
*/
public static final String RTT_CALLING_MODE = "rtt_calling_mode";
/** @hide */
- public static final Validator RTT_CALLING_MODE_VALIDATOR = TTY_MODE_VALIDATOR;
+ public static final Validator RTT_CALLING_MODE_VALIDATOR = BOOLEAN_VALIDATOR;
/**
* Whether the sounds effects (key clicks, lid open ...) are enabled. The value is
@@ -10460,6 +10457,9 @@
* <pre>
* smart_selection_dark_launch (boolean)
* smart_selection_enabled_for_edit_text (boolean)
+ * suggest_selection_max_range_length (int)
+ * classify_text_max_range_length (int)
+ * generate_links_max_text_length (int)
* </pre>
*
* <p>
diff --git a/core/java/android/provider/SettingsSlicesContract.java b/core/java/android/provider/SettingsSlicesContract.java
index f79d852..7dc9488 100644
--- a/core/java/android/provider/SettingsSlicesContract.java
+++ b/core/java/android/provider/SettingsSlicesContract.java
@@ -31,12 +31,12 @@
* <p>
* {@link Uri} builder example:
* <pre>
- * Uri wifiActionUri = AUTHORITY_URI
+ * Uri wifiActionUri = BASE_URI
* .buildUpon()
* .appendPath(PATH_SETTING_ACTION)
* .appendPath(KEY_WIFI)
* .build();
- * Uri bluetoothIntentUri = AUTHORITY_URI
+ * Uri bluetoothIntentUri = BASE_URI
* .buildUpon()
* .appendPath(PATH_SETTING_INTENT)
* .appendPath(KEY_BLUETOOTH)
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index 1d13335..f4dcce1 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -75,6 +75,7 @@
public static final int KM_TAG_ALLOW_WHILE_ON_BODY = KM_BOOL | 506;
public static final int KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED = KM_BOOL | 507;
public static final int KM_TAG_TRUSTED_CONFIRMATION_REQUIRED = KM_BOOL | 508;
+ public static final int KM_TAG_UNLOCKED_DEVICE_REQUIRED = KM_BOOL | 509;
public static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600;
public static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601;
@@ -216,6 +217,7 @@
public static final int KM_ERROR_MISSING_MIN_MAC_LENGTH = -58;
public static final int KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH = -59;
public static final int KM_ERROR_CANNOT_ATTEST_IDS = -66;
+ public static final int KM_ERROR_DEVICE_LOCKED = -72;
public static final int KM_ERROR_UNIMPLEMENTED = -100;
public static final int KM_ERROR_VERSION_MISMATCH = -101;
public static final int KM_ERROR_UNKNOWN_ERROR = -1000;
@@ -262,6 +264,7 @@
sErrorCodeToString.put(KM_ERROR_INVALID_MAC_LENGTH,
"Invalid MAC or authentication tag length");
sErrorCodeToString.put(KM_ERROR_CANNOT_ATTEST_IDS, "Unable to attest device ids");
+ sErrorCodeToString.put(KM_ERROR_DEVICE_LOCKED, "Device locked");
sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented");
sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error");
}
diff --git a/core/java/android/text/OWNERS b/core/java/android/text/OWNERS
index 9f2182e..e561371 100644
--- a/core/java/android/text/OWNERS
+++ b/core/java/android/text/OWNERS
@@ -1,3 +1,5 @@
+set noparent
+
siyamed@google.com
nona@google.com
clarabayarri@google.com
diff --git a/core/java/android/text/style/TypefaceSpan.java b/core/java/android/text/style/TypefaceSpan.java
index 1622812..908de29 100644
--- a/core/java/android/text/style/TypefaceSpan.java
+++ b/core/java/android/text/style/TypefaceSpan.java
@@ -17,6 +17,8 @@
package android.text.style;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.LeakyTypefaceStorage;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.os.Parcel;
@@ -25,33 +27,69 @@
import android.text.TextUtils;
/**
- * Changes the typeface family of the text to which the span is attached. Examples of typeface
- * family include "monospace", "serif", and "sans-serif".
+ * Span that updates the typeface of the text it's attached to. The <code>TypefaceSpan</code> can
+ * be constructed either based on a font family or based on a <code>Typeface</code>. When
+ * {@link #TypefaceSpan(String)} is used, the previous style of the <code>TextView</code> is kept.
+ * When {@link #TypefaceSpan(Typeface)} is used, the <code>Typeface</code> style replaces the
+ * <code>TextView</code>'s style.
* <p>
- * For example, change the typeface of a text to "monospace" like this:
+ * For example, let's consider a <code>TextView</code> with
+ * <code>android:textStyle="italic"</code> and a typeface created based on a font from resources,
+ * with a bold style. When applying a <code>TypefaceSpan</code> based the typeface, the text will
+ * only keep the bold style, overriding the <code>TextView</code>'s textStyle. When applying a
+ * <code>TypefaceSpan</code> based on a font family: "monospace", the resulted text will keep the
+ * italic style.
* <pre>
- * SpannableString string = new SpannableString("Text with typeface span");
- * string.setSpan(new TypefaceSpan("monospace"), 10, 18, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ * Typeface myTypeface = Typeface.create(ResourcesCompat.getFont(context, R.font.acme),
+ * Typeface.BOLD);
+ * SpannableString string = new SpannableString("Text with typeface span.");
+ * string.setSpan(new TypefaceSpan(myTypeface), 10, 18, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ * string.setSpan(new TypefaceSpan("monospace"), 19, 22, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
* </pre>
* <img src="{@docRoot}reference/android/images/text/style/typefacespan.png" />
- * <figcaption>Text with "monospace" typeface family.</figcaption>
+ * <figcaption>Text with <code>TypefaceSpan</code>s constructed based on a font from resource and
+ * from a font family.</figcaption>
*/
public class TypefaceSpan extends MetricAffectingSpan implements ParcelableSpan {
+ @Nullable
private final String mFamily;
+ @Nullable
+ private final Typeface mTypeface;
+
/**
- * Constructs a {@link TypefaceSpan} based on a font family.
+ * Constructs a {@link TypefaceSpan} based on the font family. The previous style of the
+ * TextPaint is kept. If the font family is null, the text paint is not modified.
*
- * @param family The font family for this typeface. Examples include
- * "monospace", "serif", and "sans-serif".
+ * @param family The font family for this typeface. Examples include
+ * "monospace", "serif", and "sans-serif"
*/
- public TypefaceSpan(String family) {
- mFamily = family;
+ public TypefaceSpan(@Nullable String family) {
+ this(family, null);
}
+ /**
+ * Constructs a {@link TypefaceSpan} from a {@link Typeface}. The previous style of the
+ * TextPaint is overridden and the style of the typeface is used.
+ *
+ * @param typeface the typeface
+ */
+ public TypefaceSpan(@NonNull Typeface typeface) {
+ this(null, typeface);
+ }
+
+ /**
+ * Constructs a {@link TypefaceSpan} from a parcel.
+ */
public TypefaceSpan(@NonNull Parcel src) {
mFamily = src.readString();
+ mTypeface = LeakyTypefaceStorage.readTypefaceFromParcel(src);
+ }
+
+ private TypefaceSpan(@Nullable String family, @Nullable Typeface typeface) {
+ mFamily = family;
+ mTypeface = typeface;
}
@Override
@@ -79,37 +117,59 @@
@Override
public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
dest.writeString(mFamily);
+ LeakyTypefaceStorage.writeTypefaceToParcel(mTypeface, dest);
}
/**
- * Returns the font family name.
+ * Returns the font family name set in the span.
+ *
+ * @return the font family name
+ * @see #TypefaceSpan(String)
*/
+ @Nullable
public String getFamily() {
return mFamily;
}
- @Override
- public void updateDrawState(@NonNull TextPaint textPaint) {
- apply(textPaint, mFamily);
+ /**
+ * Returns the typeface set in the span.
+ *
+ * @return the typeface set
+ * @see #TypefaceSpan(Typeface)
+ */
+ @Nullable
+ public Typeface getTypeface() {
+ return mTypeface;
}
@Override
- public void updateMeasureState(@NonNull TextPaint textPaint) {
- apply(textPaint, mFamily);
+ public void updateDrawState(@NonNull TextPaint ds) {
+ updateTypeface(ds);
}
- private static void apply(@NonNull Paint paint, String family) {
- int oldStyle;
+ @Override
+ public void updateMeasureState(@NonNull TextPaint paint) {
+ updateTypeface(paint);
+ }
+ private void updateTypeface(@NonNull Paint paint) {
+ if (mTypeface != null) {
+ paint.setTypeface(mTypeface);
+ } else if (mFamily != null) {
+ applyFontFamily(paint, mFamily);
+ }
+ }
+
+ private void applyFontFamily(@NonNull Paint paint, @NonNull String family) {
+ int style;
Typeface old = paint.getTypeface();
if (old == null) {
- oldStyle = 0;
+ style = Typeface.NORMAL;
} else {
- oldStyle = old.getStyle();
+ style = old.getStyle();
}
-
- Typeface tf = Typeface.create(family, oldStyle);
- int fake = oldStyle & ~tf.getStyle();
+ final Typeface styledTypeface = Typeface.create(family, style);
+ int fake = style & ~styledTypeface.getStyle();
if ((fake & Typeface.BOLD) != 0) {
paint.setFakeBoldText(true);
@@ -118,7 +178,6 @@
if ((fake & Typeface.ITALIC) != 0) {
paint.setTextSkewX(-0.25f);
}
-
- paint.setTypeface(tf);
+ paint.setTypeface(styledTypeface);
}
}
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index d973d4a..3a22db2 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -644,7 +644,13 @@
@Nullable Runnable modifyTextView) {
Preconditions.checkNotNull(text);
Preconditions.checkNotNull(classifier);
- final Supplier<TextLinks> supplier = () -> classifier.generateLinks(text, options);
+
+ // The input text may exceed the maximum length the text classifier can handle. In such
+ // cases, we process the text up to the maximum length.
+ final CharSequence truncatedText = text.subSequence(
+ 0, Math.min(text.length(), classifier.getMaxGenerateLinksTextLength()));
+
+ final Supplier<TextLinks> supplier = () -> classifier.generateLinks(truncatedText, options);
final Consumer<TextLinks> consumer = links -> {
if (links.getLinks().isEmpty()) {
if (callback != null) {
@@ -653,7 +659,8 @@
return;
}
- final TextLinkSpan[] old = text.getSpans(0, text.length(), TextLinkSpan.class);
+ // Remove spans only for the part of the text we generated links for.
+ final TextLinkSpan[] old = text.getSpans(0, truncatedText.length(), TextLinkSpan.class);
for (int i = old.length - 1; i >= 0; i--) {
text.removeSpan(old[i]);
}
@@ -662,7 +669,8 @@
? null : options.getSpanFactory();
final @TextLinks.ApplyStrategy int applyStrategy = (options == null)
? TextLinks.APPLY_STRATEGY_IGNORE : options.getApplyStrategy();
- final @TextLinks.Status int result = links.apply(text, applyStrategy, spanFactory);
+ final @TextLinks.Status int result = links.apply(text, applyStrategy, spanFactory,
+ true /*allowPrefix*/);
if (result == TextLinks.STATUS_LINKS_APPLIED) {
if (modifyTextView != null) {
modifyTextView.run();
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 3fd4696..8cb46b7 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -23,6 +23,10 @@
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
@@ -396,6 +400,33 @@
return true;
}
+ /**
+ * Get the Bitmap from the Drawable.
+ *
+ * If the Bitmap needed to be scaled up to account for density, BitmapDrawable
+ * handles this at draw time. But this class doesn't actually draw the Bitmap;
+ * it is just a holder for native code to access its SkBitmap. So this needs to
+ * get a version that is scaled to account for density.
+ */
+ private Bitmap getBitmapFromDrawable(BitmapDrawable bitmapDrawable) {
+ Bitmap bitmap = bitmapDrawable.getBitmap();
+ final int scaledWidth = bitmapDrawable.getIntrinsicWidth();
+ final int scaledHeight = bitmapDrawable.getIntrinsicHeight();
+ if (scaledWidth == bitmap.getWidth() && scaledHeight == bitmap.getHeight()) {
+ return bitmap;
+ }
+
+ Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
+ RectF dst = new RectF(0, 0, scaledWidth, scaledHeight);
+
+ Bitmap scaled = Bitmap.createBitmap(scaledWidth, scaledHeight, bitmap.getConfig());
+ Canvas canvas = new Canvas(scaled);
+ Paint paint = new Paint();
+ paint.setFilterBitmap(true);
+ canvas.drawBitmap(bitmap, src, dst, paint);
+ return scaled;
+ }
+
private void loadResource(Context context, Resources resources, @XmlRes int resourceId) {
final XmlResourceParser parser = resources.getXml(resourceId);
final int bitmapRes;
@@ -452,7 +483,8 @@
+ "is different. All frames should have the exact same size and "
+ "share the same hotspot.");
}
- mBitmapFrames[i - 1] = ((BitmapDrawable)drawableFrame).getBitmap();
+ BitmapDrawable bitmapDrawableFrame = (BitmapDrawable) drawableFrame;
+ mBitmapFrames[i - 1] = getBitmapFromDrawable(bitmapDrawableFrame);
}
}
}
@@ -461,7 +493,8 @@
+ "refer to a bitmap drawable.");
}
- final Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
+ BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
+ final Bitmap bitmap = getBitmapFromDrawable(bitmapDrawable);
validateHotSpot(bitmap, hotSpotX, hotSpotY);
// Set the properties now that we have successfully loaded the icon.
mBitmap = bitmap;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index fc78211..bd7f8e5 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -152,7 +152,6 @@
private static native void nativeSeverChildren(long transactionObj, long nativeObject);
private static native void nativeSetOverrideScalingMode(long transactionObj, long nativeObject,
int scalingMode);
- private static native void nativeDestroy(long transactionObj, long nativeObject);
private static native IBinder nativeGetHandle(long nativeObject);
private static native boolean nativeGetTransformToDisplayInverse(long nativeObject);
@@ -1571,16 +1570,6 @@
return this;
}
- /**
- * Same as {@link #destroy()} except this is invoked in a transaction instead of
- * immediately.
- */
- public Transaction destroy(SurfaceControl sc) {
- sc.checkNotReleased();
- nativeDestroy(mNativeObject, sc.mNativeObject);
- return this;
- }
-
public Transaction setDisplaySurface(IBinder displayToken, Surface surface) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2d85a58..3ff3c97 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8010,6 +8010,9 @@
* <li>Call {@link
* android.view.autofill.AutofillManager#notifyViewVisibilityChanged(View, int, boolean)}
* when the visibility of a virtual child changed.
+ * <li>Call
+ * {@link android.view.autofill.AutofillManager#notifyViewClicked(View, int)} when a virtual
+ * child is clicked.
* <li>Call {@link AutofillManager#commit()} when the autofill context of the view structure
* changed and the current context should be committed (for example, when the user tapped
* a {@code SUBMIT} button in an HTML page).
@@ -8807,6 +8810,9 @@
/**
* Computes whether this virtual autofill view is visible to the user.
*
+ * <p><b>Note: </b>By default it returns {@code true}, but views providing a virtual hierarchy
+ * view must override it.
+ *
* @return Whether the view is visible on the screen.
*/
public boolean isVisibleToUserForAutofill(int virtualId) {
@@ -8819,7 +8825,7 @@
}
}
}
- return false;
+ return true;
}
/**
diff --git a/core/java/android/view/autofill/AutofillId.java b/core/java/android/view/autofill/AutofillId.java
index 5ce2421..cb1d89c 100644
--- a/core/java/android/view/autofill/AutofillId.java
+++ b/core/java/android/view/autofill/AutofillId.java
@@ -38,6 +38,7 @@
}
/** @hide */
+ @TestApi
public AutofillId(AutofillId parent, int virtualChildId) {
mVirtual = true;
mViewId = parent.mViewId;
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index b0e8a3e..7792fa6 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -72,10 +72,9 @@
import java.util.List;
import java.util.Objects;
+//TODO: use java.lang.ref.Cleaner once Android supports Java 9
import sun.misc.Cleaner;
-// TODO: use java.lang.ref.Cleaner once Android supports Java 9
-
/**
* The {@link AutofillManager} provides ways for apps and custom views to integrate with the
* Autofill Framework lifecycle.
@@ -1067,16 +1066,34 @@
}
/**
- * Called when a {@link View} is clicked. Currently only used by views that should trigger save.
+ * Called to indicate a {@link View} is clicked.
*
- * @hide
+ * @param view view that has been clicked.
*/
- public void notifyViewClicked(View view) {
- final AutofillId id = view.getAutofillId();
+ public void notifyViewClicked(@NonNull View view) {
+ notifyViewClicked(view.getAutofillId());
+ }
+ /**
+ * Called to indicate a virtual view has been clicked.
+ *
+ * @param view the virtual view parent.
+ * @param virtualId id identifying the virtual child inside the parent view.
+ */
+ public void notifyViewClicked(@NonNull View view, int virtualId) {
+ notifyViewClicked(getAutofillId(view, virtualId));
+ }
+
+ private void notifyViewClicked(AutofillId id) {
+ if (!hasAutofillFeature()) {
+ return;
+ }
if (sVerbose) Log.v(TAG, "notifyViewClicked(): id=" + id + ", trigger=" + mSaveTriggerId);
synchronized (mLock) {
+ if (!mEnabled || !isActiveLocked()) {
+ return;
+ }
if (mSaveTriggerId != null && mSaveTriggerId.equals(id)) {
if (sDebug) Log.d(TAG, "triggering commit by click of " + id);
commitLocked();
@@ -1091,16 +1108,16 @@
*
* @hide
*/
- public void onActivityFinished() {
+ public void onActivityFinishing() {
if (!hasAutofillFeature()) {
return;
}
synchronized (mLock) {
if (mSaveOnFinish) {
- if (sDebug) Log.d(TAG, "Committing session on finish() as requested by service");
+ if (sDebug) Log.d(TAG, "onActivityFinishing(): calling commitLocked()");
commitLocked();
} else {
- if (sDebug) Log.d(TAG, "Cancelling session on finish() as requested by service");
+ if (sDebug) Log.d(TAG, "onActivityFinishing(): calling cancelLocked()");
cancelLocked();
}
}
@@ -1121,6 +1138,7 @@
if (!hasAutofillFeature()) {
return;
}
+ if (sVerbose) Log.v(TAG, "commit() called by app");
synchronized (mLock) {
commitLocked();
}
@@ -2334,6 +2352,7 @@
final boolean[] isVisible;
if (client.autofillClientIsVisibleForAutofill()) {
+ if (sVerbose) Log.v(TAG, "client is visible, check tracked ids");
isVisible = client.autofillClientGetViewVisibility(trackedIds);
} else {
// All false
@@ -2353,7 +2372,7 @@
}
if (sVerbose) {
- Log.v(TAG, "TrackedViews(trackedIds=" + trackedIds + "): "
+ Log.v(TAG, "TrackedViews(trackedIds=" + Arrays.toString(trackedIds) + "): "
+ " mVisibleTrackedIds=" + mVisibleTrackedIds
+ " mInvisibleTrackedIds=" + mInvisibleTrackedIds);
}
@@ -2459,6 +2478,9 @@
}
if (mVisibleTrackedIds == null) {
+ if (sVerbose) {
+ Log.v(TAG, "onVisibleForAutofillChangedLocked(): no more visible ids");
+ }
finishSessionLocked();
}
}
diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java
index af55dcd..cbc3828 100644
--- a/core/java/android/view/textclassifier/SystemTextClassifier.java
+++ b/core/java/android/view/textclassifier/SystemTextClassifier.java
@@ -121,6 +121,15 @@
return mFallback.generateLinks(text, options);
}
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public int getMaxGenerateLinksTextLength() {
+ // TODO: retrieve this from the bound service.
+ return mFallback.getMaxGenerateLinksTextLength();
+ }
+
private static final class TextSelectionCallback extends ITextSelectionCallback.Stub {
final ResponseReceiver<TextSelection> mReceiver = new ResponseReceiver<>();
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index 9f75c4a..2a62f23 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -276,9 +276,11 @@
* @param text the text to generate annotations for
* @param options configuration for link generation
*
- * @throws IllegalArgumentException if text is null
+ * @throws IllegalArgumentException if text is null or the text is too long for the
+ * TextClassifier implementation.
*
* @see #generateLinks(CharSequence)
+ * @see #getMaxGenerateLinksTextLength()
*/
@WorkerThread
default TextLinks generateLinks(
@@ -299,9 +301,11 @@
*
* @param text the text to generate annotations for
*
- * @throws IllegalArgumentException if text is null
+ * @throws IllegalArgumentException if text is null or the text is too long for the
+ * TextClassifier implementation.
*
* @see #generateLinks(CharSequence, TextLinks.Options)
+ * @see #getMaxGenerateLinksTextLength()
*/
@WorkerThread
default TextLinks generateLinks(@NonNull CharSequence text) {
@@ -309,6 +313,16 @@
}
/**
+ * Returns the maximal length of text that can be processed by generateLinks.
+ *
+ * @see #generateLinks(CharSequence)
+ * @see #generateLinks(CharSequence, TextLinks.Options)
+ */
+ default int getMaxGenerateLinksTextLength() {
+ return Integer.MAX_VALUE;
+ }
+
+ /**
* Returns a {@link Collection} of the entity types in the specified preset.
*
* @see #ENTITY_PRESET_ALL
@@ -461,6 +475,15 @@
checkMainThread(allowInMainThread);
}
+ /**
+ * @throws IllegalArgumentException if text is null; the text is too long or options is null
+ */
+ public static void validate(@NonNull CharSequence text, int maxLength,
+ boolean allowInMainThread) {
+ validate(text, allowInMainThread);
+ Preconditions.checkArgumentInRange(text.length(), 0, maxLength, "text.length()");
+ }
+
private static void checkMainThread(boolean allowInMainThread) {
if (!allowInMainThread && Looper.myLooper() == Looper.getMainLooper()) {
Slog.w(DEFAULT_LOG_TAG, "TextClassifier called on main thread");
diff --git a/core/java/android/view/textclassifier/TextClassifierConstants.java b/core/java/android/view/textclassifier/TextClassifierConstants.java
index 00695b7..efa6948 100644
--- a/core/java/android/view/textclassifier/TextClassifierConstants.java
+++ b/core/java/android/view/textclassifier/TextClassifierConstants.java
@@ -47,10 +47,19 @@
"smart_selection_enabled_for_edit_text";
private static final String SMART_LINKIFY_ENABLED =
"smart_linkify_enabled";
+ private static final String SUGGEST_SELECTION_MAX_RANGE_LENGTH =
+ "suggest_selection_max_range_length";
+ private static final String CLASSIFY_TEXT_MAX_RANGE_LENGTH =
+ "classify_text_max_range_length";
+ private static final String GENERATE_LINKS_MAX_TEXT_LENGTH =
+ "generate_links_max_text_length";
private static final boolean SMART_SELECTION_DARK_LAUNCH_DEFAULT = false;
private static final boolean SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT = true;
private static final boolean SMART_LINKIFY_ENABLED_DEFAULT = true;
+ private static final int SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT = 10 * 1000;
+ private static final int CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT = 10 * 1000;
+ private static final int GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT = 100 * 1000;
/** Default settings. */
static final TextClassifierConstants DEFAULT = new TextClassifierConstants();
@@ -58,11 +67,17 @@
private final boolean mDarkLaunch;
private final boolean mSuggestSelectionEnabledForEditableText;
private final boolean mSmartLinkifyEnabled;
+ private final int mSuggestSelectionMaxRangeLength;
+ private final int mClassifyTextMaxRangeLength;
+ private final int mGenerateLinksMaxTextLength;
private TextClassifierConstants() {
mDarkLaunch = SMART_SELECTION_DARK_LAUNCH_DEFAULT;
mSuggestSelectionEnabledForEditableText = SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT;
mSmartLinkifyEnabled = SMART_LINKIFY_ENABLED_DEFAULT;
+ mSuggestSelectionMaxRangeLength = SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT;
+ mClassifyTextMaxRangeLength = CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT;
+ mGenerateLinksMaxTextLength = GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT;
}
private TextClassifierConstants(@Nullable String settings) {
@@ -82,6 +97,15 @@
mSmartLinkifyEnabled = parser.getBoolean(
SMART_LINKIFY_ENABLED,
SMART_LINKIFY_ENABLED_DEFAULT);
+ mSuggestSelectionMaxRangeLength = parser.getInt(
+ SUGGEST_SELECTION_MAX_RANGE_LENGTH,
+ SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT);
+ mClassifyTextMaxRangeLength = parser.getInt(
+ CLASSIFY_TEXT_MAX_RANGE_LENGTH,
+ CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT);
+ mGenerateLinksMaxTextLength = parser.getInt(
+ GENERATE_LINKS_MAX_TEXT_LENGTH,
+ GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT);
}
static TextClassifierConstants loadFromString(String settings) {
@@ -99,4 +123,16 @@
public boolean isSmartLinkifyEnabled() {
return mSmartLinkifyEnabled;
}
+
+ public int getSuggestSelectionMaxRangeLength() {
+ return mSuggestSelectionMaxRangeLength;
+ }
+
+ public int getClassifyTextMaxRangeLength() {
+ return mClassifyTextMaxRangeLength;
+ }
+
+ public int getGenerateLinksMaxTextLength() {
+ return mGenerateLinksMaxTextLength;
+ }
}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index fc03493..795caff 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -128,7 +128,9 @@
@Nullable TextSelection.Options options) {
Utils.validate(text, selectionStartIndex, selectionEndIndex, false /* allowInMainThread */);
try {
- if (text.length() > 0) {
+ final int rangeLength = selectionEndIndex - selectionStartIndex;
+ if (text.length() > 0
+ && rangeLength <= getSettings().getSuggestSelectionMaxRangeLength()) {
final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
final boolean darkLaunchAllowed = options != null && options.isDarkLaunchAllowed();
final SmartSelection smartSelection = getSmartSelection(locales);
@@ -183,7 +185,8 @@
@Nullable TextClassification.Options options) {
Utils.validate(text, startIndex, endIndex, false /* allowInMainThread */);
try {
- if (text.length() > 0) {
+ final int rangeLength = endIndex - startIndex;
+ if (text.length() > 0 && rangeLength <= getSettings().getClassifyTextMaxRangeLength()) {
final String string = text.toString();
final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
final Calendar refTime = (options == null) ? null : options.getReferenceTime();
@@ -207,7 +210,7 @@
@Override
public TextLinks generateLinks(
@NonNull CharSequence text, @Nullable TextLinks.Options options) {
- Utils.validate(text, false /* allowInMainThread */);
+ Utils.validate(text, getMaxGenerateLinksTextLength(), false /* allowInMainThread */);
final String textString = text.toString();
final TextLinks.Builder builder = new TextLinks.Builder(textString);
@@ -241,6 +244,12 @@
return mFallback.generateLinks(text, options);
}
+ /** @inheritDoc */
+ @Override
+ public int getMaxGenerateLinksTextLength() {
+ return getSettings().getGenerateLinksMaxTextLength();
+ }
+
@Override
public Collection<String> getEntitiesForPreset(@TextClassifier.EntityPreset int entityPreset) {
switch (entityPreset) {
diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java
index d866d13..3d252f2 100644
--- a/core/java/android/view/textclassifier/TextLinks.java
+++ b/core/java/android/view/textclassifier/TextLinks.java
@@ -108,6 +108,7 @@
* @param text the text to apply the links to. Must match the original text
* @param applyStrategy strategy for resolving link conflicts
* @param spanFactory a factory to generate spans from TextLinks. Will use a default if null
+ * @param allowPrefix whether to allow applying links only to a prefix of the text.
*
* @return a status code indicating whether or not the links were successfully applied
*
@@ -117,10 +118,12 @@
public int apply(
@NonNull Spannable text,
@ApplyStrategy int applyStrategy,
- @Nullable Function<TextLink, TextLinkSpan> spanFactory) {
+ @Nullable Function<TextLink, TextLinkSpan> spanFactory,
+ boolean allowPrefix) {
Preconditions.checkNotNull(text);
checkValidApplyStrategy(applyStrategy);
- if (!mFullText.equals(text.toString())) {
+ final String textString = text.toString();
+ if (!mFullText.equals(textString) && !(allowPrefix && textString.startsWith(mFullText))) {
return STATUS_DIFFERENT_TEXT;
}
if (mLinks.isEmpty()) {
diff --git a/core/java/android/webkit/TracingConfig.java b/core/java/android/webkit/TracingConfig.java
index 75e2bf7..68badec 100644
--- a/core/java/android/webkit/TracingConfig.java
+++ b/core/java/android/webkit/TracingConfig.java
@@ -21,61 +21,76 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
/**
* Holds tracing configuration information and predefined settings.
*/
public class TracingConfig {
- private final String mCustomCategoryPattern;
- private final @PresetCategories int mPresetCategories;
+ private @PredefinedCategories int mPredefinedCategories;
+ private final List<String> mCustomIncludedCategories = new ArrayList<String>();
private @TracingMode int mTracingMode;
/** @hide */
- @IntDef({CATEGORIES_NONE, CATEGORIES_WEB_DEVELOPER, CATEGORIES_INPUT_LATENCY,
- CATEGORIES_RENDERING, CATEGORIES_JAVASCRIPT_AND_RENDERING, CATEGORIES_FRAME_VIEWER})
+ @IntDef(flag = true, value = {CATEGORIES_NONE, CATEGORIES_WEB_DEVELOPER,
+ CATEGORIES_INPUT_LATENCY, CATEGORIES_RENDERING, CATEGORIES_JAVASCRIPT_AND_RENDERING,
+ CATEGORIES_FRAME_VIEWER})
@Retention(RetentionPolicy.SOURCE)
- public @interface PresetCategories {}
+ public @interface PredefinedCategories {}
/**
- * Indicates that there are no preset categories.
+ * Indicates that there are no predefined categories.
*/
- public static final int CATEGORIES_NONE = -1;
+ public static final int CATEGORIES_NONE = 0;
/**
- * Predefined categories typically useful for web developers.
+ * Predefined set of categories, includes all categories enabled by default in chromium.
+ * Use with caution: this setting may produce large trace output.
+ */
+ public static final int CATEGORIES_ALL = 1 << 0;
+
+ /**
+ * Predefined set of categories typically useful for analyzing WebViews.
+ * Typically includes android_webview and Java.
+ */
+ public static final int CATEGORIES_ANDROID_WEBVIEW = 1 << 1;
+
+ /**
+ * Predefined set of categories typically useful for web developers.
* Typically includes blink, compositor, renderer.scheduler and v8 categories.
*/
- public static final int CATEGORIES_WEB_DEVELOPER = 0;
+ public static final int CATEGORIES_WEB_DEVELOPER = 1 << 2;
/**
- * Predefined categories for analyzing input latency issues.
+ * Predefined set of categories for analyzing input latency issues.
* Typically includes input, renderer.scheduler categories.
*/
- public static final int CATEGORIES_INPUT_LATENCY = 1;
+ public static final int CATEGORIES_INPUT_LATENCY = 1 << 3;
/**
- * Predefined categories for analyzing rendering issues.
+ * Predefined set of categories for analyzing rendering issues.
* Typically includes blink, compositor and gpu categories.
*/
- public static final int CATEGORIES_RENDERING = 2;
+ public static final int CATEGORIES_RENDERING = 1 << 4;
/**
- * Predefined categories for analyzing javascript and rendering issues.
- * Typically includes blink, compositor, gpu, renderer.schduler and v8 categories.
+ * Predefined set of categories for analyzing javascript and rendering issues.
+ * Typically includes blink, compositor, gpu, renderer.scheduler and v8 categories.
*/
- public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 3;
+ public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 1 << 5;
/**
- * Predefined categories for studying difficult rendering performance problems.
+ * Predefined set of categories for studying difficult rendering performance problems.
* Typically includes blink, compositor, gpu, renderer.scheduler, v8 and
* some other compositor categories which are disabled by default.
*/
- public static final int CATEGORIES_FRAME_VIEWER = 4;
+ public static final int CATEGORIES_FRAME_VIEWER = 1 << 6;
/** @hide */
- @IntDef({RECORD_UNTIL_FULL, RECORD_CONTINUOUSLY, RECORD_UNTIL_FULL_LARGE_BUFFER,
- RECORD_TO_CONSOLE})
+ @IntDef({RECORD_UNTIL_FULL, RECORD_CONTINUOUSLY, RECORD_UNTIL_FULL_LARGE_BUFFER})
@Retention(RetentionPolicy.SOURCE)
public @interface TracingMode {}
@@ -97,99 +112,38 @@
/**
* Record trace events using a larger internal tracing buffer until it is full.
- * Uses more memory than the other modes and may not be suitable on devices
- * with smaller RAM. Depending on the implementation typically allows up to
- * 512 million events to be stored.
+ * Uses significantly more memory than {@link #RECORD_UNTIL_FULL} and may not be
+ * suitable on devices with smaller RAM.
*/
public static final int RECORD_UNTIL_FULL_LARGE_BUFFER = 2;
/**
- * Record trace events to console (logcat). The events are discarded and nothing
- * is sent back to the caller. Uses the least memory as compared to the other modes.
+ * @hide
*/
- public static final int RECORD_TO_CONSOLE = 3;
-
- /**
- * Create config with the preset categories.
- * <p>
- * Example:
- * TracingConfig(CATEGORIES_WEB_DEVELOPER) -- records trace events from the "web developer"
- * preset categories.
- *
- * @param presetCategories preset categories to use, one of {@link #CATEGORIES_WEB_DEVELOPER},
- * {@link #CATEGORIES_INPUT_LATENCY}, {@link #CATEGORIES_RENDERING},
- * {@link #CATEGORIES_JAVASCRIPT_AND_RENDERING} or
- * {@link #CATEGORIES_FRAME_VIEWER}.
- *
- * Note: for specifying custom categories without presets use
- * {@link #TracingConfig(int, String, int)}.
- *
- */
- public TracingConfig(@PresetCategories int presetCategories) {
- this(presetCategories, "", RECORD_UNTIL_FULL);
+ public TracingConfig(@PredefinedCategories int predefinedCategories,
+ @NonNull List<String> customIncludedCategories,
+ @TracingMode int tracingMode) {
+ mPredefinedCategories = predefinedCategories;
+ mCustomIncludedCategories.addAll(customIncludedCategories);
+ mTracingMode = tracingMode;
}
/**
- * Create a configuration with both preset categories and custom categories.
- * Also allows to specify the tracing mode.
- *
- * Note that the categories are defined by the currently-in-use version of WebView. They live
- * in chromium code and are not part of the Android API. See
- * See <a href="https://www.chromium.org/developers/how-tos/trace-event-profiling-tool">
- * chromium documentation on tracing</a> for more details.
- *
- * <p>
- * Examples:
- *
- * Preset category with a specified trace mode:
- * TracingConfig(CATEGORIES_WEB_DEVELOPER, "", RECORD_UNTIL_FULL_LARGE_BUFFER);
- * Custom categories:
- * TracingConfig(CATEGORIES_NONE, "browser", RECORD_UNTIL_FULL)
- * -- records only the trace events from the "browser" category.
- * TraceConfig(CATEGORIES_NONE, "-input,-gpu", RECORD_UNTIL_FULL)
- * -- records all trace events excluding the events from the "input" and 'gpu' categories.
- * TracingConfig(CATEGORIES_NONE, "blink*,devtools*", RECORD_UNTIL_FULL)
- * -- records only the trace events matching the "blink*" and "devtools*" patterns
- * (e.g. "blink_gc" and "devtools.timeline" categories).
- *
- * Combination of preset and additional custom categories:
- * TracingConfig(CATEGORIES_WEB_DEVELOPER, "memory-infra", RECORD_CONTINUOUSLY)
- * -- records events from the "web developer" categories and events from the "memory-infra"
- * category to understand where memory is being used.
- *
- * @param presetCategories preset categories to use, one of {@link #CATEGORIES_WEB_DEVELOPER},
- * {@link #CATEGORIES_INPUT_LATENCY}, {@link #CATEGORIES_RENDERING},
- * {@link #CATEGORIES_JAVASCRIPT_AND_RENDERING} or
- * {@link #CATEGORIES_FRAME_VIEWER}.
- * @param customCategories a comma-delimited list of category wildcards. A category can
- * have an optional '-' prefix to make it an excluded category.
- * @param tracingMode tracing mode to use, one of {@link #RECORD_UNTIL_FULL},
- * {@link #RECORD_CONTINUOUSLY}, {@link #RECORD_UNTIL_FULL_LARGE_BUFFER}
- * or {@link #RECORD_TO_CONSOLE}.
+ * Returns a bitmask of the predefined categories values of this configuration.
*/
- public TracingConfig(@PresetCategories int presetCategories,
- @NonNull String customCategories, @TracingMode int tracingMode) {
- mPresetCategories = presetCategories;
- mCustomCategoryPattern = customCategories;
- mTracingMode = RECORD_UNTIL_FULL;
+ @PredefinedCategories
+ public int getPredefinedCategories() {
+ return mPredefinedCategories;
}
/**
- * Returns the custom category pattern for this configuration.
+ * Returns the list of included custom category patterns for this configuration.
*
- * @return empty string if no custom category pattern is specified.
+ * @return empty list if no custom category patterns are specified.
*/
@NonNull
- public String getCustomCategoryPattern() {
- return mCustomCategoryPattern;
- }
-
- /**
- * Returns the preset categories value of this configuration.
- */
- @PresetCategories
- public int getPresetCategories() {
- return mPresetCategories;
+ public List<String> getCustomIncludedCategories() {
+ return mCustomIncludedCategories;
}
/**
@@ -200,4 +154,111 @@
return mTracingMode;
}
+ /**
+ * Builder used to create {@link TracingConfig} objects.
+ *
+ * Examples:
+ * new TracingConfig.Builder().build()
+ * -- creates a configuration with default options: {@link #CATEGORIES_NONE},
+ * {@link #RECORD_UNTIL_FULL}.
+ * new TracingConfig.Builder().addCategories(CATEGORIES_WEB_DEVELOPER).build()
+ * -- records trace events from the "web developer" predefined category sets.
+ * new TracingConfig.Builder().addCategories(CATEGORIES_RENDERING,
+ * CATEGORIES_INPUT_LATENCY).build()
+ * -- records trace events from the "rendering" and "input latency" predefined
+ * category sets.
+ * new TracingConfig.Builder().addCategories("browser").build()
+ * -- records only the trace events from the "browser" category.
+ * new TracingConfig.Builder().addCategories("blink*","renderer*").build()
+ * -- records only the trace events matching the "blink*" and "renderer*" patterns
+ * (e.g. "blink.animations", "renderer_host" and "renderer.scheduler" categories).
+ * new TracingConfig.Builder().addCategories(CATEGORIES_WEB_DEVELOPER)
+ * .addCategories("disabled-by-default-v8.gc")
+ * .setTracingMode(RECORD_CONTINUOUSLY).build()
+ * -- records events from the "web developer" predefined category set and events from
+ * the "disabled-by-default-v8.gc" category to understand where garbage collection
+ * is being triggered. Uses a ring buffer for internal storage during tracing.
+ */
+ public static class Builder {
+ private @PredefinedCategories int mPredefinedCategories = CATEGORIES_NONE;
+ private final List<String> mCustomIncludedCategories = new ArrayList<String>();
+ private @TracingMode int mTracingMode = RECORD_UNTIL_FULL;
+
+ /**
+ * Default constructor for Builder.
+ */
+ public Builder() {}
+
+ /**
+ * Build {@link TracingConfig} using the current settings.
+ */
+ public TracingConfig build() {
+ return new TracingConfig(mPredefinedCategories, mCustomIncludedCategories,
+ mTracingMode);
+ }
+
+ /**
+ * Adds categories from a predefined set of categories to be included in the trace output.
+ *
+ * @param predefinedCategories list or bitmask of predefined category sets to use:
+ * {@link #CATEGORIES_NONE}, {@link #CATEGORIES_ALL},
+ * {@link #CATEGORIES_WEB_DEVELOPER}, {@link #CATEGORIES_INPUT_LATENCY},
+ * {@link #CATEGORIES_RENDERING},
+ * {@link #CATEGORIES_JAVASCRIPT_AND_RENDERING} or
+ * {@link #CATEGORIES_FRAME_VIEWER}.
+ * @return The builder to facilitate chaining.
+ */
+ public Builder addCategories(@PredefinedCategories int... predefinedCategories) {
+ for (int categorySet : predefinedCategories) {
+ mPredefinedCategories |= categorySet;
+ }
+ return this;
+ }
+
+ /**
+ * Adds custom categories to be included in trace output.
+ *
+ * Note that the categories are defined by the currently-in-use version of WebView. They
+ * live in chromium code and are not part of the Android API. See
+ * See <a href="https://www.chromium.org/developers/how-tos/trace-event-profiling-tool">
+ * chromium documentation on tracing</a> for more details.
+ *
+ * @param categories a list of category patterns. A category pattern can contain wilcards,
+ * e.g. "blink*" or full category name e.g. "renderer.scheduler".
+ * @return The builder to facilitate chaining.
+ */
+ public Builder addCategories(String... categories) {
+ for (String category: categories) {
+ mCustomIncludedCategories.add(category);
+ }
+ return this;
+ }
+
+ /**
+ * Adds custom categories to be included in trace output.
+ *
+ * Same as {@link #addCategories(String...)} but allows to pass a Collection as a parameter.
+ *
+ * @param categories a list of category patters.
+ * @return The builder to facilitate chaining.
+ */
+ public Builder addCategories(Collection<String> categories) {
+ mCustomIncludedCategories.addAll(categories);
+ return this;
+ }
+
+ /**
+ * Sets the tracing mode for this configuration.
+ *
+ * @param tracingMode tracing mode to use, one of {@link #RECORD_UNTIL_FULL},
+ * {@link #RECORD_CONTINUOUSLY} or
+ * {@link #RECORD_UNTIL_FULL_LARGE_BUFFER}.
+ * @return The builder to facilitate chaining.
+ */
+ public Builder setTracingMode(@TracingMode int tracingMode) {
+ mTracingMode = tracingMode;
+ return this;
+ }
+ }
+
}
diff --git a/core/java/android/webkit/TracingController.java b/core/java/android/webkit/TracingController.java
index cadb8a1..7871021 100644
--- a/core/java/android/webkit/TracingController.java
+++ b/core/java/android/webkit/TracingController.java
@@ -16,9 +16,12 @@
package android.webkit;
+import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.os.Handler;
+
+import java.io.OutputStream;
+import java.util.concurrent.Executor;
/**
* Manages tracing of WebViews. In particular provides functionality for the app
@@ -29,40 +32,22 @@
* The resulting trace data is sent back as a byte sequence in json format. This
* file can be loaded in "chrome://tracing" for further analysis.
* <p>
- * Note: All methods in this class must be called on the UI thread. All callbacks
- * are also called on the UI thread.
- * <p>
* Example usage:
* <pre class="prettyprint">
* TracingController tracingController = TracingController.getInstance();
- * tracingController.start(new TraceConfig(CATEGORIES_WEB_DEVELOPER));
+ * tracingController.start(new TraceConfig.Builder()
+ * .addCategories(CATEGORIES_WEB_DEVELOPER).build());
* [..]
- * tracingController.stopAndFlush(new TraceFileOutput("trace.json"), null);
+ * tracingController.stop(new FileOutputStream("trace.json"),
+ * Executors.newSingleThreadExecutor());
* </pre></p>
*/
public abstract class TracingController {
/**
- * Interface for capturing tracing data.
- */
- public interface TracingOutputStream {
- /**
- * Will be called to return tracing data in chunks.
- * Tracing data is returned in json format an array of bytes.
- */
- void write(byte[] chunk);
-
- /**
- * Called when tracing is finished and the data collection is over.
- * There will be no calls to #write after #complete is called.
- */
- void complete();
- }
-
- /**
* Returns the default TracingController instance. At present there is
* only one TracingController instance for all WebView instances,
- * however this restriction may be relaxed in the future.
+ * however this restriction may be relaxed in a future Android release.
*
* @return the default TracingController instance
*/
@@ -72,55 +57,38 @@
}
/**
- * Starts tracing all webviews. Depeding on the trace mode in traceConfig
+ * Starts tracing all webviews. Depending on the trace mode in traceConfig
* specifies how the trace events are recorded.
*
* For tracing modes {@link TracingConfig#RECORD_UNTIL_FULL},
* {@link TracingConfig#RECORD_CONTINUOUSLY} and
* {@link TracingConfig#RECORD_UNTIL_FULL_LARGE_BUFFER} the events are recorded
* using an internal buffer and flushed to the outputStream when
- * {@link #stopAndFlush(TracingOutputStream, Handler)} is called.
+ * {@link #stop(OutputStream, Executor)} is called.
*
* @param tracingConfig configuration options to use for tracing
- * @return false if the system is already tracing, true otherwise.
+ * @throws IllegalStateException if the system is already tracing.
*/
- public abstract boolean start(TracingConfig tracingConfig);
+ public abstract void start(@NonNull TracingConfig tracingConfig);
/**
- * Stops tracing and discards all tracing data.
+ * Stops tracing and flushes tracing data to the specified outputStream.
*
- * This method is particularly useful in conjunction with the
- * {@link TracingConfig#RECORD_TO_CONSOLE} tracing mode because tracing data is logged to
- * console and not sent to an outputStream as with
- * {@link #stopAndFlush(TracingOutputStream, Handler)}.
+ * The data is sent to the specified output stream in json format typically
+ * in chunks by invoking {@link java.io.OutputStream#write(byte[])}. On completion
+ * the {@link java.io.OutputStream#close()} method is called.
*
+ * @param outputStream the output steam the tracing data will be sent to. If null
+ * the tracing data will be discarded.
+ * @param executor the {@link java.util.concurrent.Executor} on which the
+ * outputStream #write and #close methods will be invoked.
* @return false if the system was not tracing at the time of the call, true
* otherwise.
*/
- public abstract boolean stop();
-
- /**
- * Stops tracing and flushes tracing data to the specifid outputStream.
- *
- * Note that if the {@link TracingConfig#RECORD_TO_CONSOLE} tracing mode is used
- * nothing will be sent to the outputStream and no TracingOuputStream methods will be
- * called. In that case it is more convenient to just use {@link #stop()} instead.
- *
- * @param outputStream the output steam the tracing data will be sent to.
- * @param handler the {@link android.os.Handler} on which the outputStream callbacks
- * will be invoked. If the handler is null the current thread's Looper
- * will be used.
- * @return false if the system was not tracing at the time of the call, true
- * otherwise.
- */
- public abstract boolean stopAndFlush(TracingOutputStream outputStream,
- @Nullable Handler handler);
+ public abstract boolean stop(@Nullable OutputStream outputStream,
+ @NonNull @CallbackExecutor Executor executor);
/** True if the system is tracing */
public abstract boolean isTracing();
- // TODO: consider adding getTraceBufferUsage, percentage and approx event count.
- // TODO: consider adding String getCategories(), for obtaining the actual list
- // of categories used (given that presets are ints).
-
}
diff --git a/core/java/android/webkit/TracingFileOutputStream.java b/core/java/android/webkit/TracingFileOutputStream.java
deleted file mode 100644
index 8a5fa36..0000000
--- a/core/java/android/webkit/TracingFileOutputStream.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2017 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.webkit;
-
-import android.annotation.NonNull;
-
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-/**
- * Simple TracingOutputStream implementation which writes the trace data from
- * {@link TracingController} to a new file.
- *
- */
-public class TracingFileOutputStream implements TracingController.TracingOutputStream {
-
- private FileOutputStream mFileOutput;
-
- public TracingFileOutputStream(@NonNull String filename) throws FileNotFoundException {
- mFileOutput = new FileOutputStream(filename);
- }
-
- /**
- * Writes bytes chunk to the file.
- */
- public void write(byte[] chunk) {
- try {
- mFileOutput.write(chunk);
- } catch (IOException e) {
- onIOException(e);
- }
- }
-
- /**
- * Closes the file.
- */
- public void complete() {
- try {
- mFileOutput.close();
- } catch (IOException e) {
- onIOException(e);
- }
- }
-
- private void onIOException(IOException e) {
- throw new RuntimeException(e);
- }
-}
diff --git a/core/java/android/widget/OWNERS b/core/java/android/widget/OWNERS
index 2789bae..e4b2930 100644
--- a/core/java/android/widget/OWNERS
+++ b/core/java/android/widget/OWNERS
@@ -1,9 +1,11 @@
per-file TextView.java = siyamed@google.com
per-file TextView.java = nona@google.com
per-file TextView.java = clarabayarri@google.com
+
per-file EditText.java = siyamed@google.com
per-file EditText.java = nona@google.com
per-file EditText.java = clarabayarri@google.com
+
per-file Editor.java = siyamed@google.com
per-file Editor.java = nona@google.com
per-file Editor.java = clarabayarri@google.com
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index 5c4d4d2..c987147 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -183,13 +183,17 @@
}
private void setCheckedId(@IdRes int id) {
+ boolean changed = id != mCheckedId;
mCheckedId = id;
+
if (mOnCheckedChangeListener != null) {
mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId);
}
- final AutofillManager afm = mContext.getSystemService(AutofillManager.class);
- if (afm != null) {
- afm.notifyValueChanged(this);
+ if (changed) {
+ final AutofillManager afm = mContext.getSystemService(AutofillManager.class);
+ if (afm != null) {
+ afm.notifyValueChanged(this);
+ }
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5710db3..1e02c30 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -791,11 +791,18 @@
// mAutoSizeStepGranularityInPx.
private boolean mHasPresetAutoSizeValues = false;
+ // Autofill-related attributes
+ //
// Indicates whether the text was set statically or dynamically, so it can be used to
// sanitize autofill requests.
private boolean mTextSetFromXmlOrResourceId = false;
- // Resource id used to set the text - used for autofill purposes.
+ // Resource id used to set the text.
private @StringRes int mTextId = ResourceId.ID_NULL;
+ // Last value used on AFM.notifyValueChanged(), used to optimize autofill workflow by avoiding
+ // calls when the value did not change
+ private CharSequence mLastValueSentToAutofillManager;
+ //
+ // End of autofill-related attributes
/**
* Kick-start the font cache for the zygote process (to pay the cost of
@@ -5665,7 +5672,6 @@
if (needEditableForNotification) {
sendAfterTextChanged((Editable) text);
} else {
- // Always notify AutoFillManager - it will return right away if autofill is disabled.
notifyAutoFillManagerAfterTextChangedIfNeeded();
}
@@ -9697,11 +9703,21 @@
return;
}
final AutofillManager afm = mContext.getSystemService(AutofillManager.class);
- if (afm != null) {
+ if (afm == null) {
+ return;
+ }
+
+ if (mLastValueSentToAutofillManager == null
+ || !mLastValueSentToAutofillManager.equals(mText)) {
if (android.view.autofill.Helper.sVerbose) {
- Log.v(LOG_TAG, "sendAfterTextChanged(): notify AFM for text=" + mText);
+ Log.v(LOG_TAG, "notifying AFM after text changed");
}
afm.notifyValueChanged(TextView.this);
+ mLastValueSentToAutofillManager = mText;
+ } else {
+ if (android.view.autofill.Helper.sVerbose) {
+ Log.v(LOG_TAG, "not notifying AFM on unchanged text");
+ }
}
}
diff --git a/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java b/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java
index 500c028..bf151c3 100644
--- a/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java
+++ b/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java
@@ -57,6 +57,8 @@
private int mMainColor;
private int mSecondaryColor;
private ValueAnimator mColorAnimation;
+ private int mMainColorTo;
+ private int mSecondaryColorTo;
public GradientDrawable(@NonNull Context context) {
mDensity = context.getResources().getDisplayMetrics().density;
@@ -76,7 +78,7 @@
}
public void setColors(int mainColor, int secondaryColor, boolean animated) {
- if (mainColor == mMainColor && secondaryColor == mSecondaryColor) {
+ if (mainColor == mMainColorTo && secondaryColor == mSecondaryColorTo) {
return;
}
@@ -84,6 +86,9 @@
mColorAnimation.cancel();
}
+ mMainColorTo = mainColor;
+ mSecondaryColorTo = mainColor;
+
if (animated) {
final int mainFrom = mMainColor;
final int secFrom = mSecondaryColor;
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index d6f8dc4..61d5031 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -604,6 +604,7 @@
CameraInfo cameraInfo;
status_t rc = Camera::getCameraInfo(cameraId, &cameraInfo);
if (rc != NO_ERROR) {
+ ALOGE("%s: getCameraInfo error: %d", __FUNCTION__, rc);
return rc;
}
int defaultOrientation = 0;
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 8ca5062..0ef5445 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -846,14 +846,6 @@
transaction->setOverrideScalingMode(ctrl, scalingMode);
}
-static void nativeDestroyInTransaction(JNIEnv* env, jclass clazz,
- jlong transactionObj,
- jlong nativeObject) {
- auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
- auto ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
- transaction->destroySurface(ctrl);
-}
-
static jobject nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) {
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
return javaObjectForIBinder(env, ctrl->getHandle());
@@ -1005,8 +997,6 @@
(void*)nativeSeverChildren } ,
{"nativeSetOverrideScalingMode", "(JJI)V",
(void*)nativeSetOverrideScalingMode },
- {"nativeDestroy", "(JJ)V",
- (void*)nativeDestroyInTransaction },
{"nativeGetHandle", "(J)Landroid/os/IBinder;",
(void*)nativeGetHandle },
{"nativeScreenshotToBuffer",
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index e994d37..0911298 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -999,7 +999,7 @@
<integer name="config_shortPressOnSleepBehavior">0</integer>
<!-- Time to wait while a button is pressed before triggering a very long press. -->
- <integer name="config_veryLongPressTimeout">6000</integer>
+ <integer name="config_veryLongPressTimeout">3500</integer>
<!-- Package name for default keyguard appwidget [DO NOT TRANSLATE] -->
<string name="widget_default_package_name" translatable="false"></string>
diff --git a/core/tests/coretests/src/android/text/OWNERS b/core/tests/coretests/src/android/text/OWNERS
index 9f2182e..a35c604 100644
--- a/core/tests/coretests/src/android/text/OWNERS
+++ b/core/tests/coretests/src/android/text/OWNERS
@@ -1,3 +1,5 @@
+set noparent
+
siyamed@google.com
nona@google.com
-clarabayarri@google.com
+clarabayarri@google.com
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index a8de374..430b30f 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -19,6 +19,7 @@
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import android.os.LocaleList;
@@ -33,6 +34,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TextClassificationManagerTest {
@@ -183,6 +186,7 @@
@Test
public void testGenerateLinks_none_config() {
if (isTextClassifierDisabled()) return;
+
String text = "The number is +12122537077. See you tonight!";
assertThat(mClassifier.generateLinks(text, mLinksOptions.setEntityConfig(
new TextClassifier.EntityConfig(TextClassifier.ENTITY_PRESET_NONE))),
@@ -210,6 +214,25 @@
}
@Test
+ public void testGenerateLinks_maxLength() {
+ if (isTextClassifierDisabled()) return;
+ char[] manySpaces = new char[mClassifier.getMaxGenerateLinksTextLength()];
+ Arrays.fill(manySpaces, ' ');
+ TextLinks links = mClassifier.generateLinks(new String(manySpaces), null);
+ assertTrue(links.getLinks().isEmpty());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testGenerateLinks_tooLong() {
+ if (isTextClassifierDisabled()) {
+ throw new IllegalArgumentException("pass if disabled");
+ }
+ char[] manySpaces = new char[mClassifier.getMaxGenerateLinksTextLength() + 1];
+ Arrays.fill(manySpaces, ' ');
+ mClassifier.generateLinks(new String(manySpaces), null);
+ }
+
+ @Test
public void testSetTextClassifier() {
TextClassifier classifier = mock(TextClassifier.class);
mTcm.setTextClassifier(classifier);
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 7f4f9f7..79433ac 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -382,7 +382,7 @@
TextClassifier textClassifier = textClassificationManager.getTextClassifier();
Spannable content = new SpannableString("Call me at +19148277737");
TextLinks links = textClassifier.generateLinks(content);
- links.apply(content, TextLinks.APPLY_STRATEGY_REPLACE, null);
+ links.apply(content, TextLinks.APPLY_STRATEGY_REPLACE, null, false /* allowPrefix */);
mActivityRule.runOnUiThread(() -> {
textView.setText(content);
diff --git a/docs/html/reference/images/text/style/typefacespan.png b/docs/html/reference/images/text/style/typefacespan.png
index 67e2cf9..1651c39 100644
--- a/docs/html/reference/images/text/style/typefacespan.png
+++ b/docs/html/reference/images/text/style/typefacespan.png
Binary files differ
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index ee7abc5..3cca47b 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -25,7 +25,7 @@
import android.annotation.RawRes;
import android.content.ContentResolver;
import android.content.res.AssetFileDescriptor;
-import android.content.res.AssetManager;
+import android.content.res.AssetManager.AssetInputStream;
import android.content.res.Resources;
import android.graphics.drawable.AnimatedImageDrawable;
import android.graphics.drawable.Drawable;
@@ -263,6 +263,63 @@
}
}
+ /**
+ * Takes ownership of the AssetInputStream.
+ *
+ * @hide
+ */
+ public static class AssetInputStreamSource extends Source {
+ public AssetInputStreamSource(@NonNull AssetInputStream ais,
+ @NonNull Resources res, @NonNull TypedValue value) {
+ mAssetInputStream = ais;
+ mResources = res;
+
+ if (value.density == TypedValue.DENSITY_DEFAULT) {
+ mDensity = DisplayMetrics.DENSITY_DEFAULT;
+ } else if (value.density != TypedValue.DENSITY_NONE) {
+ mDensity = value.density;
+ } else {
+ mDensity = Bitmap.DENSITY_NONE;
+ }
+ }
+
+ private AssetInputStream mAssetInputStream;
+ private final Resources mResources;
+ private final int mDensity;
+
+ @Override
+ public Resources getResources() { return mResources; }
+
+ @Override
+ public int getDensity() {
+ return mDensity;
+ }
+
+ @Override
+ public ImageDecoder createImageDecoder() throws IOException {
+ ImageDecoder decoder = null;
+ synchronized (this) {
+ if (mAssetInputStream == null) {
+ throw new IOException("Cannot reuse AssetInputStreamSource");
+ }
+ AssetInputStream ais = mAssetInputStream;
+ mAssetInputStream = null;
+ try {
+ long asset = ais.getNativeAsset();
+ decoder = nCreate(asset);
+ } finally {
+ if (decoder == null) {
+ IoUtils.closeQuietly(ais);
+ } else {
+ decoder.mInputStream = ais;
+ decoder.mOwnsInputStream = true;
+ }
+ }
+ return decoder;
+ }
+ }
+ }
+
private static class ResourceSource extends Source {
ResourceSource(@NonNull Resources res, int resId) {
mResources = res;
@@ -296,11 +353,7 @@
mResDensity = value.density;
}
- if (!(is instanceof AssetManager.AssetInputStream)) {
- // This should never happen.
- throw new RuntimeException("Resource is not an asset?");
- }
- long asset = ((AssetManager.AssetInputStream) is).getNativeAsset();
+ long asset = ((AssetInputStream) is).getNativeAsset();
decoder = nCreate(asset);
} finally {
if (decoder == null) {
@@ -444,6 +497,7 @@
private boolean mPreferRamOverQuality = false;
private boolean mAsAlphaMask = false;
private Rect mCropRect;
+ private Rect mOutPaddingRect;
private Source mSource;
private PostProcessor mPostProcessor;
@@ -782,6 +836,18 @@
}
/**
+ * Set a Rect for retrieving nine patch padding.
+ *
+ * If the image is a nine patch, this Rect will be set to the padding
+ * rectangle during decode. Otherwise it will not be modified.
+ *
+ * @hide
+ */
+ public void setOutPaddingRect(@NonNull Rect outPadding) {
+ mOutPaddingRect = outPadding;
+ }
+
+ /**
* Specify whether the {@link Bitmap} should be mutable.
*
* <p>By default, a {@link Bitmap} created will be immutable, but that can
@@ -892,7 +958,6 @@
postProcessPtr, mDesiredWidth, mDesiredHeight, mCropRect,
mMutable, mAllocator, mRequireUnpremultiplied,
mPreferRamOverQuality, mAsAlphaMask);
-
}
private void callHeaderDecoded(@Nullable OnHeaderDecodedListener listener,
@@ -965,7 +1030,10 @@
if (np != null && NinePatch.isNinePatchChunk(np)) {
Rect opticalInsets = new Rect();
bm.getOpticalInsets(opticalInsets);
- Rect padding = new Rect();
+ Rect padding = decoder.mOutPaddingRect;
+ if (padding == null) {
+ padding = new Rect();
+ }
nGetPadding(decoder.mNativePtr, padding);
return new NinePatchDrawable(res, bm, np, padding,
opticalInsets, null);
@@ -1008,6 +1076,15 @@
final int srcDensity = computeDensity(src, decoder);
Bitmap bm = decoder.decodeBitmap();
bm.setDensity(srcDensity);
+
+ Rect padding = decoder.mOutPaddingRect;
+ if (padding != null) {
+ byte[] np = bm.getNinePatchChunk();
+ if (np != null && NinePatch.isNinePatchChunk(np)) {
+ nGetPadding(decoder.mNativePtr, padding);
+ }
+ }
+
return bm;
}
}
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 7ad062a..44b783b 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -27,6 +27,7 @@
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
+import android.graphics.ImageDecoder;
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Outline;
@@ -49,6 +50,7 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -111,7 +113,7 @@
*/
@Deprecated
public BitmapDrawable() {
- mBitmapState = new BitmapState((Bitmap) null);
+ init(new BitmapState((Bitmap) null), null);
}
/**
@@ -124,8 +126,7 @@
@SuppressWarnings("unused")
@Deprecated
public BitmapDrawable(Resources res) {
- mBitmapState = new BitmapState((Bitmap) null);
- mBitmapState.mTargetDensity = mTargetDensity;
+ init(new BitmapState((Bitmap) null), res);
}
/**
@@ -135,7 +136,7 @@
*/
@Deprecated
public BitmapDrawable(Bitmap bitmap) {
- this(new BitmapState(bitmap), null);
+ init(new BitmapState(bitmap), null);
}
/**
@@ -143,8 +144,7 @@
* the display metrics of the resources.
*/
public BitmapDrawable(Resources res, Bitmap bitmap) {
- this(new BitmapState(bitmap), res);
- mBitmapState.mTargetDensity = mTargetDensity;
+ init(new BitmapState(bitmap), res);
}
/**
@@ -154,10 +154,7 @@
*/
@Deprecated
public BitmapDrawable(String filepath) {
- this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
- if (mBitmapState.mBitmap == null) {
- android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
- }
+ this(null, filepath);
}
/**
@@ -165,10 +162,21 @@
*/
@SuppressWarnings({ "unused", "ChainingConstructorIgnoresParameter" })
public BitmapDrawable(Resources res, String filepath) {
- this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
- mBitmapState.mTargetDensity = mTargetDensity;
- if (mBitmapState.mBitmap == null) {
- android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
+ Bitmap bitmap = null;
+ try (FileInputStream stream = new FileInputStream(filepath)) {
+ bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(res, stream),
+ (decoder, info, src) -> {
+ decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+ });
+ } catch (Exception e) {
+ /* do nothing. This matches the behavior of BitmapFactory.decodeFile()
+ If the exception happened on decode, mBitmapState.mBitmap will be null.
+ */
+ } finally {
+ init(new BitmapState(bitmap), res);
+ if (mBitmapState.mBitmap == null) {
+ android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
+ }
}
}
@@ -179,10 +187,7 @@
*/
@Deprecated
public BitmapDrawable(java.io.InputStream is) {
- this(new BitmapState(BitmapFactory.decodeStream(is)), null);
- if (mBitmapState.mBitmap == null) {
- android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
- }
+ this(null, is);
}
/**
@@ -190,10 +195,21 @@
*/
@SuppressWarnings({ "unused", "ChainingConstructorIgnoresParameter" })
public BitmapDrawable(Resources res, java.io.InputStream is) {
- this(new BitmapState(BitmapFactory.decodeStream(is)), null);
- mBitmapState.mTargetDensity = mTargetDensity;
- if (mBitmapState.mBitmap == null) {
- android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
+ Bitmap bitmap = null;
+ try {
+ bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(res, is),
+ (decoder, info, src) -> {
+ decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+ });
+ } catch (Exception e) {
+ /* do nothing. This matches the behavior of BitmapFactory.decodeStream()
+ If the exception happened on decode, mBitmapState.mBitmap will be null.
+ */
+ } finally {
+ init(new BitmapState(bitmap), res);
+ if (mBitmapState.mBitmap == null) {
+ android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
+ }
}
}
@@ -812,9 +828,19 @@
}
}
+ int density = Bitmap.DENSITY_NONE;
+ if (value.density == TypedValue.DENSITY_DEFAULT) {
+ density = DisplayMetrics.DENSITY_DEFAULT;
+ } else if (value.density != TypedValue.DENSITY_NONE) {
+ density = value.density;
+ }
+
Bitmap bitmap = null;
try (InputStream is = r.openRawResource(srcResId, value)) {
- bitmap = BitmapFactory.decodeResourceStream(r, value, is, null, null);
+ ImageDecoder.Source source = ImageDecoder.createSource(r, is, density);
+ bitmap = ImageDecoder.decodeBitmap(source, (decoder, info, src) -> {
+ decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+ });
} catch (Exception e) {
// Do nothing and pick up the error below.
}
@@ -1013,14 +1039,21 @@
}
}
+ private BitmapDrawable(BitmapState state, Resources res) {
+ init(state, res);
+ }
+
/**
- * The one constructor to rule them all. This is called by all public
+ * The one helper to rule them all. This is called by all public & private
* constructors to set the state and initialize local properties.
*/
- private BitmapDrawable(BitmapState state, Resources res) {
+ private void init(BitmapState state, Resources res) {
mBitmapState = state;
-
updateLocalState(res);
+
+ if (mBitmapState != null && res != null) {
+ mBitmapState.mTargetDensity = mTargetDensity;
+ }
}
/**
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 05533d7..8af2fd8 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -37,6 +37,7 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
+import android.graphics.ImageDecoder;
import android.graphics.Insets;
import android.graphics.NinePatch;
import android.graphics.Outline;
@@ -50,11 +51,13 @@
import android.os.Trace;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.StateSet;
import android.util.TypedValue;
import android.util.Xml;
import android.view.View;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
@@ -1179,6 +1182,10 @@
return null;
}
+ if (opts == null) {
+ return getBitmapDrawable(res, value, is);
+ }
+
/* ugh. The decodeStream contract is that we have already allocated
the pad rect, but if the bitmap does not had a ninepatch chunk,
then the pad will be ignored. If we could change this to lazily
@@ -1194,7 +1201,6 @@
// an application in compatibility mode, without scaling those down
// to the compatibility density only to have them scaled back up when
// drawn to the screen.
- if (opts == null) opts = new BitmapFactory.Options();
opts.inScreenDensity = Drawable.resolveDensity(res, 0);
Bitmap bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts);
if (bm != null) {
@@ -1211,6 +1217,33 @@
return null;
}
+ private static Drawable getBitmapDrawable(Resources res, TypedValue value, InputStream is) {
+ try {
+ ImageDecoder.Source source = null;
+ if (value != null) {
+ int density = Bitmap.DENSITY_NONE;
+ if (value.density == TypedValue.DENSITY_DEFAULT) {
+ density = DisplayMetrics.DENSITY_DEFAULT;
+ } else if (value.density != TypedValue.DENSITY_NONE) {
+ density = value.density;
+ }
+ source = ImageDecoder.createSource(res, is, density);
+ } else {
+ source = ImageDecoder.createSource(res, is);
+ }
+
+ return ImageDecoder.decodeDrawable(source, (decoder, info, src) -> {
+ decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+ });
+ } catch (IOException e) {
+ /* do nothing.
+ If the exception happened on decode, the drawable will be null.
+ */
+ Log.e("Drawable", "Unable to decode stream: " + e);
+ }
+ return null;
+ }
+
/**
* Create a drawable from an XML document. For more information on how to
* create resources in XML, see
@@ -1310,11 +1343,10 @@
}
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, pathName);
- try {
- Bitmap bm = BitmapFactory.decodeFile(pathName);
- if (bm != null) {
- return drawableFromBitmap(null, bm, null, null, null, pathName);
- }
+ try (FileInputStream stream = new FileInputStream(pathName)) {
+ return getBitmapDrawable(null, null, stream);
+ } catch(IOException e) {
+ // Do nothing; we will just return null if the FileInputStream had an error
} finally {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 1790020..66f2a31 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -24,9 +24,9 @@
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
+import android.graphics.ImageDecoder;
import android.graphics.Insets;
import android.graphics.NinePatch;
import android.graphics.Outline;
@@ -211,7 +211,8 @@
restoreAlpha = -1;
}
- final boolean needsDensityScaling = canvas.getDensity() == 0;
+ final boolean needsDensityScaling = canvas.getDensity() == 0
+ && Bitmap.DENSITY_NONE != state.mNinePatch.getDensity();
if (needsDensityScaling) {
restoreToCount = restoreToCount >= 0 ? restoreToCount : canvas.save();
@@ -421,10 +422,6 @@
final int srcResId = a.getResourceId(R.styleable.NinePatchDrawable_src, 0);
if (srcResId != 0) {
- final BitmapFactory.Options options = new BitmapFactory.Options();
- options.inDither = !state.mDither;
- options.inScreenDensity = r.getDisplayMetrics().noncompatDensityDpi;
-
final Rect padding = new Rect();
final Rect opticalInsets = new Rect();
Bitmap bitmap = null;
@@ -433,7 +430,17 @@
final TypedValue value = new TypedValue();
final InputStream is = r.openRawResource(srcResId, value);
- bitmap = BitmapFactory.decodeResourceStream(r, value, is, padding, options);
+ int density = Bitmap.DENSITY_NONE;
+ if (value.density == TypedValue.DENSITY_DEFAULT) {
+ density = DisplayMetrics.DENSITY_DEFAULT;
+ } else if (value.density != TypedValue.DENSITY_NONE) {
+ density = value.density;
+ }
+ ImageDecoder.Source source = ImageDecoder.createSource(r, is, density);
+ bitmap = ImageDecoder.decodeBitmap(source, (decoder, info, src) -> {
+ decoder.setOutPaddingRect(padding);
+ decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+ });
is.close();
} catch (IOException e) {
@@ -660,8 +667,9 @@
return;
}
- final int sourceDensity = ninePatch.getDensity();
final int targetDensity = mTargetDensity;
+ final int sourceDensity = ninePatch.getDensity() == Bitmap.DENSITY_NONE ?
+ targetDensity : ninePatch.getDensity();
final Insets sourceOpticalInsets = mNinePatchState.mOpticalInsets;
if (sourceOpticalInsets != Insets.NONE) {
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index ded427e..e2aba04 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -545,7 +545,9 @@
try {
args = args != null ? args : new KeymasterArguments();
entropy = entropy != null ? entropy : new byte[0];
- return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid);
+ OperationResult res = mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid);
+ // This result is -26 (KEY_USER_NOT_AUTHENTICATED) but why??
+ return res;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return null;
@@ -563,7 +565,8 @@
try {
arguments = arguments != null ? arguments : new KeymasterArguments();
input = input != null ? input : new byte[0];
- return mBinder.update(token, arguments, input);
+ OperationResult res = mBinder.update(token, arguments, input);
+ return res;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return null;
@@ -618,9 +621,9 @@
* @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to
* a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
*/
- public int addAuthToken(byte[] authToken) {
+ public int addAuthToken(byte[] authToken, int userId) {
try {
- return mBinder.addAuthToken(authToken);
+ return mBinder.addAuthToken(authToken, userId);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
@@ -832,14 +835,14 @@
public InvalidKeyException getInvalidKeyException(
String keystoreKeyAlias, int uid, KeyStoreException e) {
switch (e.getErrorCode()) {
- case LOCKED:
+ case LOCKED: // 2
return new UserNotAuthenticatedException();
- case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
+ case KeymasterDefs.KM_ERROR_KEY_EXPIRED: // -25
return new KeyExpiredException();
- case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
+ case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID: // -2
return new KeyNotYetValidException();
- case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
- case OP_AUTH_NEEDED:
+ case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED: // -26
+ case OP_AUTH_NEEDED: // 15
{
// We now need to determine whether the key/operation can become usable if user
// authentication is performed, or whether it can never become usable again.
@@ -879,7 +882,7 @@
// None of the key's SIDs can ever be authenticated
return new KeyPermanentlyInvalidatedException();
}
- case UNINITIALIZED:
+ case UNINITIALIZED: // 3
return new KeyPermanentlyInvalidatedException();
default:
return new InvalidKeyException("Keystore operation failed", e);
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index 09b3b9b..419eb24 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -243,13 +243,7 @@
// Check that user authentication related parameters are acceptable. This method
// will throw an IllegalStateException if there are issues (e.g., secure lock screen
// not set up).
- KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
- spec.isUserAuthenticationRequired(),
- spec.getUserAuthenticationValidityDurationSeconds(),
- spec.isUserAuthenticationValidWhileOnBody(),
- spec.isInvalidatedByBiometricEnrollment(),
- GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
- spec.isUserConfirmationRequired());
+ KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), spec);
} catch (IllegalStateException | IllegalArgumentException e) {
throw new InvalidAlgorithmParameterException(e);
}
@@ -285,16 +279,7 @@
args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes);
args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterPaddings);
args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
- KeymasterUtils.addUserAuthArgs(args,
- spec.isUserAuthenticationRequired(),
- spec.getUserAuthenticationValidityDurationSeconds(),
- spec.isUserAuthenticationValidWhileOnBody(),
- spec.isInvalidatedByBiometricEnrollment(),
- GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
- spec.isUserConfirmationRequired());
- if (spec.isTrustedUserPresenceRequired()) {
- args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
- }
+ KeymasterUtils.addUserAuthArgs(args, spec);
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
args,
mKeymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index e33e3cd..d68a33d 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -344,13 +344,7 @@
// Check that user authentication related parameters are acceptable. This method
// will throw an IllegalStateException if there are issues (e.g., secure lock screen
// not set up).
- KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
- mSpec.isUserAuthenticationRequired(),
- mSpec.getUserAuthenticationValidityDurationSeconds(),
- mSpec.isUserAuthenticationValidWhileOnBody(),
- mSpec.isInvalidatedByBiometricEnrollment(),
- GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
- mSpec.isUserConfirmationRequired());
+ KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), mSpec);
} catch (IllegalArgumentException | IllegalStateException e) {
throw new InvalidAlgorithmParameterException(e);
}
@@ -541,13 +535,7 @@
args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterSignaturePaddings);
args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
- KeymasterUtils.addUserAuthArgs(args,
- mSpec.isUserAuthenticationRequired(),
- mSpec.getUserAuthenticationValidityDurationSeconds(),
- mSpec.isUserAuthenticationValidWhileOnBody(),
- mSpec.isInvalidatedByBiometricEnrollment(),
- GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
- mSpec.isUserConfirmationRequired());
+ KeymasterUtils.addUserAuthArgs(args, mSpec);
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
mSpec.getKeyValidityForOriginationEnd());
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index 05cc74a..fc86ca0 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -497,13 +497,7 @@
importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterEncryptionPaddings);
importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING,
KeyProperties.SignaturePadding.allToKeymaster(spec.getSignaturePaddings()));
- KeymasterUtils.addUserAuthArgs(importArgs,
- spec.isUserAuthenticationRequired(),
- spec.getUserAuthenticationValidityDurationSeconds(),
- spec.isUserAuthenticationValidWhileOnBody(),
- spec.isInvalidatedByBiometricEnrollment(),
- spec.getBoundToSpecificSecureUserId(),
- spec.isUserConfirmationRequired());
+ KeymasterUtils.addUserAuthArgs(importArgs, spec);
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
spec.getKeyValidityStart());
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
@@ -700,13 +694,7 @@
int[] keymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
params.getEncryptionPaddings());
args.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
- KeymasterUtils.addUserAuthArgs(args,
- params.isUserAuthenticationRequired(),
- params.getUserAuthenticationValidityDurationSeconds(),
- params.isUserAuthenticationValidWhileOnBody(),
- params.isInvalidatedByBiometricEnrollment(),
- params.getBoundToSpecificSecureUserId(),
- params.isUserConfirmationRequired());
+ KeymasterUtils.addUserAuthArgs(args, params);
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
args,
keymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index da23c70..d0814c6 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -21,6 +21,7 @@
import android.annotation.Nullable;
import android.app.KeyguardManager;
import android.hardware.fingerprint.FingerprintManager;
+import android.security.GateKeeper;
import android.security.KeyStore;
import android.text.TextUtils;
@@ -232,7 +233,7 @@
* key = (SecretKey) keyStore.getKey("key2", null);
* }</pre>
*/
-public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
+public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAuthArgs {
private static final X500Principal DEFAULT_CERT_SUBJECT = new X500Principal("CN=fake");
private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1");
@@ -265,6 +266,7 @@
private final boolean mInvalidatedByBiometricEnrollment;
private final boolean mIsStrongBoxBacked;
private final boolean mUserConfirmationRequired;
+ private final boolean mUnlockedDeviceRequired;
/**
* @hide should be built with Builder
@@ -295,7 +297,8 @@
boolean userAuthenticationValidWhileOnBody,
boolean invalidatedByBiometricEnrollment,
boolean isStrongBoxBacked,
- boolean userConfirmationRequired) {
+ boolean userConfirmationRequired,
+ boolean unlockedDeviceRequired) {
if (TextUtils.isEmpty(keyStoreAlias)) {
throw new IllegalArgumentException("keyStoreAlias must not be empty");
}
@@ -344,6 +347,7 @@
mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
mIsStrongBoxBacked = isStrongBoxBacked;
mUserConfirmationRequired = userConfirmationRequired;
+ mUnlockedDeviceRequired = unlockedDeviceRequired;
}
/**
@@ -669,6 +673,22 @@
}
/**
+ * Returns {@code true} if the key cannot be used unless the device screen is unlocked.
+ *
+ * @see Builder#SetUnlockedDeviceRequired(boolean)
+ */
+ public boolean isUnlockedDeviceRequired() {
+ return mUnlockedDeviceRequired;
+ }
+
+ /**
+ * @hide
+ */
+ public long getBoundToSpecificSecureUserId() {
+ return GateKeeper.INVALID_SECURE_USER_ID;
+ }
+
+ /**
* Builder of {@link KeyGenParameterSpec} instances.
*/
public final static class Builder {
@@ -699,6 +719,7 @@
private boolean mInvalidatedByBiometricEnrollment = true;
private boolean mIsStrongBoxBacked = false;
private boolean mUserConfirmationRequired;
+ private boolean mUnlockedDeviceRequired = false;
/**
* Creates a new instance of the {@code Builder}.
@@ -1267,6 +1288,18 @@
}
/**
+ * Sets whether the keystore requires the screen to be unlocked before allowing decryption
+ * using this key. If this is set to {@code true}, any attempt to decrypt using this key
+ * while the screen is locked will fail. A locked device requires a PIN, password,
+ * fingerprint, or other trusted factor to access.
+ */
+ @NonNull
+ public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) {
+ mUnlockedDeviceRequired = unlockedDeviceRequired;
+ return this;
+ }
+
+ /**
* Builds an instance of {@code KeyGenParameterSpec}.
*/
@NonNull
@@ -1297,7 +1330,8 @@
mUserAuthenticationValidWhileOnBody,
mInvalidatedByBiometricEnrollment,
mIsStrongBoxBacked,
- mUserConfirmationRequired);
+ mUserConfirmationRequired,
+ mUnlockedDeviceRequired);
}
}
}
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index b5b3281..7f8259b 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -212,7 +212,7 @@
* ...
* }</pre>
*/
-public final class KeyProtection implements ProtectionParameter {
+public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
private final Date mKeyValidityStart;
private final Date mKeyValidityForOriginationEnd;
private final Date mKeyValidityForConsumptionEnd;
@@ -229,6 +229,8 @@
private final long mBoundToSecureUserId;
private final boolean mCriticalToDeviceEncryption;
private final boolean mUserConfirmationRequired;
+ private final boolean mTrustedUserPresenceRequired;
+ private final boolean mUnlockedDeviceRequired;
private KeyProtection(
Date keyValidityStart,
@@ -242,11 +244,13 @@
boolean randomizedEncryptionRequired,
boolean userAuthenticationRequired,
int userAuthenticationValidityDurationSeconds,
+ boolean trustedUserPresenceRequired,
boolean userAuthenticationValidWhileOnBody,
boolean invalidatedByBiometricEnrollment,
long boundToSecureUserId,
boolean criticalToDeviceEncryption,
- boolean userConfirmationRequired) {
+ boolean userConfirmationRequired,
+ boolean unlockedDeviceRequired) {
mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
@@ -265,6 +269,8 @@
mBoundToSecureUserId = boundToSecureUserId;
mCriticalToDeviceEncryption = criticalToDeviceEncryption;
mUserConfirmationRequired = userConfirmationRequired;
+ mTrustedUserPresenceRequired = trustedUserPresenceRequired;
+ mUnlockedDeviceRequired = unlockedDeviceRequired;
}
/**
@@ -437,6 +443,14 @@
}
/**
+ * Returns {@code true} if the key is authorized to be used only if a test of user presence has
+ * been performed between the {@code Signature.initSign()} and {@code Signature.sign()} calls.
+ */
+ public boolean isTrustedUserPresenceRequired() {
+ return mTrustedUserPresenceRequired;
+ }
+
+ /**
* Returns {@code true} if the key will be de-authorized when the device is removed from the
* user's body. This option has no effect on keys that don't have an authentication validity
* duration, and has no effect if the device lacks an on-body sensor.
@@ -494,6 +508,15 @@
}
/**
+ * Returns {@code true} if the key cannot be used unless the device screen is unlocked.
+ *
+ * @see Builder#SetRequireDeviceUnlocked(boolean)
+ */
+ public boolean isUnlockedDeviceRequired() {
+ return mUnlockedDeviceRequired;
+ }
+
+ /**
* Builder of {@link KeyProtection} instances.
*/
public final static class Builder {
@@ -512,6 +535,9 @@
private boolean mUserAuthenticationValidWhileOnBody;
private boolean mInvalidatedByBiometricEnrollment = true;
private boolean mUserConfirmationRequired;
+ private boolean mTrustedUserPresenceRequired = false;
+ private boolean mUnlockedDeviceRequired = false;
+
private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID;
private boolean mCriticalToDeviceEncryption = false;
@@ -811,6 +837,16 @@
}
/**
+ * Sets whether a test of user presence is required to be performed between the
+ * {@code Signature.initSign()} and {@code Signature.sign()} method calls.
+ */
+ @NonNull
+ public Builder setTrustedUserPresenceRequired(boolean required) {
+ mTrustedUserPresenceRequired = required;
+ return this;
+ }
+
+ /**
* Sets whether the key will remain authorized only until the device is removed from the
* user's body up to the limit of the authentication validity period (see
* {@link #setUserAuthenticationValidityDurationSeconds} and
@@ -892,6 +928,18 @@
}
/**
+ * Sets whether the keystore requires the screen to be unlocked before allowing decryption
+ * using this key. If this is set to {@code true}, any attempt to decrypt using this key
+ * while the screen is locked will fail. A locked device requires a PIN, password,
+ * fingerprint, or other trusted factor to access.
+ */
+ @NonNull
+ public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) {
+ mUnlockedDeviceRequired = unlockedDeviceRequired;
+ return this;
+ }
+
+ /**
* Builds an instance of {@link KeyProtection}.
*
* @throws IllegalArgumentException if a required field is missing
@@ -910,11 +958,13 @@
mRandomizedEncryptionRequired,
mUserAuthenticationRequired,
mUserAuthenticationValidityDurationSeconds,
+ mTrustedUserPresenceRequired,
mUserAuthenticationValidWhileOnBody,
mInvalidatedByBiometricEnrollment,
mBoundToSecureUserId,
mCriticalToDeviceEncryption,
- mUserConfirmationRequired);
+ mUserConfirmationRequired,
+ mUnlockedDeviceRequired);
}
}
}
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index 4e28601..5bd0e74 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -18,6 +18,7 @@
import android.util.Log;
import android.hardware.fingerprint.FingerprintManager;
+import android.os.UserHandle;
import android.security.GateKeeper;
import android.security.KeyStore;
import android.security.keymaster.KeymasterArguments;
@@ -101,22 +102,27 @@
* require user authentication.
*/
public static void addUserAuthArgs(KeymasterArguments args,
- boolean userAuthenticationRequired,
- int userAuthenticationValidityDurationSeconds,
- boolean userAuthenticationValidWhileOnBody,
- boolean invalidatedByBiometricEnrollment,
- long boundToSpecificSecureUserId,
- boolean userConfirmationRequired) {
- if (userConfirmationRequired) {
+ UserAuthArgs spec) {
+ if (spec.isTrustedUserPresenceRequired()) {
+ args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
+ }
+
+ if (spec.isUserConfirmationRequired()) {
args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED);
}
- if (!userAuthenticationRequired) {
+ if (spec.isUnlockedDeviceRequired()) {
+ args.addBoolean(KeymasterDefs.KM_TAG_UNLOCKED_DEVICE_REQUIRED);
+ // Once keymaster is properly ignoring this tag, it should be added to every auth list
+ args.addUnsignedInt(KeymasterDefs.KM_TAG_USER_ID, UserHandle.getCallingUserId());
+ }
+
+ if (!spec.isUserAuthenticationRequired()) {
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
return;
}
- if (userAuthenticationValidityDurationSeconds == -1) {
+ if (spec.getUserAuthenticationValidityDurationSeconds() == -1) {
// Every use of this key needs to be authorized by the user. This currently means
// fingerprint-only auth.
FingerprintManager fingerprintManager =
@@ -132,9 +138,9 @@
}
long sid;
- if (boundToSpecificSecureUserId != GateKeeper.INVALID_SECURE_USER_ID) {
- sid = boundToSpecificSecureUserId;
- } else if (invalidatedByBiometricEnrollment) {
+ if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
+ sid = spec.getBoundToSpecificSecureUserId();
+ } else if (spec.isInvalidatedByBiometricEnrollment()) {
// The fingerprint-only SID will change on fingerprint enrollment or removal of all,
// enrolled fingerprints, invalidating the key.
sid = fingerprintOnlySid;
@@ -147,14 +153,14 @@
args.addUnsignedLong(
KeymasterDefs.KM_TAG_USER_SECURE_ID, KeymasterArguments.toUint64(sid));
args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, KeymasterDefs.HW_AUTH_FINGERPRINT);
- if (userAuthenticationValidWhileOnBody) {
+ if (spec.isUserAuthenticationValidWhileOnBody()) {
throw new ProviderException("Key validity extension while device is on-body is not "
+ "supported for keys requiring fingerprint authentication");
}
} else {
long sid;
- if (boundToSpecificSecureUserId != GateKeeper.INVALID_SECURE_USER_ID) {
- sid = boundToSpecificSecureUserId;
+ if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
+ sid = spec.getBoundToSpecificSecureUserId();
} else {
// The key is authorized for use for the specified amount of time after the user has
// authenticated. Whatever unlocks the secure lock screen should authorize this key.
@@ -165,8 +171,8 @@
args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
KeymasterDefs.HW_AUTH_PASSWORD | KeymasterDefs.HW_AUTH_FINGERPRINT);
args.addUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
- userAuthenticationValidityDurationSeconds);
- if (userAuthenticationValidWhileOnBody) {
+ spec.getUserAuthenticationValidityDurationSeconds());
+ if (spec.isUserAuthenticationValidWhileOnBody()) {
args.addBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
}
}
diff --git a/keystore/java/android/security/keystore/UserAuthArgs.java b/keystore/java/android/security/keystore/UserAuthArgs.java
new file mode 100644
index 0000000..3a7017e
--- /dev/null
+++ b/keystore/java/android/security/keystore/UserAuthArgs.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 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.security.keystore;
+
+/**
+ * @hide
+ *
+ * This is an interface to encapsulate the user authentication arguments that
+ * are passed to KeymasterUtils.addUserAuthArgs. Classes that represent
+ * authorization characteristics for new or imported keys can implement this
+ * interface to be passed to that method.
+ */
+public interface UserAuthArgs {
+
+ boolean isUserAuthenticationRequired();
+ int getUserAuthenticationValidityDurationSeconds();
+ boolean isUserAuthenticationValidWhileOnBody();
+ boolean isInvalidatedByBiometricEnrollment();
+ boolean isTrustedUserPresenceRequired();
+ boolean isUnlockedDeviceRequired();
+ boolean isUserConfirmationRequired();
+ long getBoundToSpecificSecureUserId();
+
+}
diff --git a/media/java/android/media/DataSourceDesc.java b/media/java/android/media/DataSourceDesc.java
index 73fad7a..6dff07f 100644
--- a/media/java/android/media/DataSourceDesc.java
+++ b/media/java/android/media/DataSourceDesc.java
@@ -30,6 +30,8 @@
import java.io.FileDescriptor;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.net.CookieHandler;
+import java.net.CookieManager;
import java.net.HttpCookie;
import java.util.ArrayList;
@@ -433,10 +435,22 @@
* @param cookies the cookies to be sent together with the request
* @return the same Builder instance.
* @throws NullPointerException if context or uri is null.
+ * @throws IllegalArgumentException if the cookie handler is not of CookieManager type
+ * when cookies are provided.
*/
public Builder setDataSource(@NonNull Context context, @NonNull Uri uri,
@Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies) {
+ Preconditions.checkNotNull(context, "context cannot be null");
Preconditions.checkNotNull(uri);
+ if (cookies != null) {
+ CookieHandler cookieHandler = CookieHandler.getDefault();
+ if (cookieHandler != null && !(cookieHandler instanceof CookieManager)) {
+ throw new IllegalArgumentException(
+ "The cookie handler has to be of CookieManager type "
+ + "when cookies are provided.");
+ }
+ }
+
resetDataSource();
mType = TYPE_URI;
mUri = uri;
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index e331b2c..2f3d972 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -804,19 +804,6 @@
public abstract DataSourceDesc editPlaylistItem(int index, DataSourceDesc dsd);
/**
- * Prepares the player for playback, synchronously.
- *
- * After setting the datasource and the display surface, you need to either
- * call prepare() or prepareAsync(). For files, it is OK to call prepare(),
- * which blocks until MediaPlayer2 is ready for playback.
- *
- * @throws IOException if source can not be accessed
- * @throws IllegalStateException if it is called in an invalid state
- * @hide
- */
- public void prepare() throws IOException { }
-
- /**
* Prepares the player for playback, asynchronously.
*
* After setting the datasource and the display surface, you need to
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index b805eb4..1b21b5b 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -137,7 +137,7 @@
* {@link #getVideoWidth()}, {@link #setAudioAttributes(AudioAttributes)},
* {@link #setLooping(boolean)},
* {@link #setVolume(float, float)}, {@link #pause()}, {@link #play()},
- * {@link #seekTo(long, int)}, {@link #prepare()} or
+ * {@link #seekTo(long, int)} or
* {@link #prepareAsync()} in the <em>Idle</em> state for both cases. If any of these
* methods is called right after a MediaPlayer2 object is constructed,
* the user supplied callback method OnErrorListener.onError() won't be
@@ -184,7 +184,7 @@
* register a OnErrorListener to look out for error notifications from
* the internal player engine.</li>
* <li>IllegalStateException is
- * thrown to prevent programming errors such as calling {@link #prepare()},
+ * thrown to prevent programming errors such as calling
* {@link #prepareAsync()}, {@link #setDataSource(DataSourceDesc)}, or
* {@code setPlaylist} methods in an invalid state. </li>
* </ul>
@@ -206,15 +206,11 @@
* <li>A MediaPlayer2 object must first enter the <em>Prepared</em> state
* before playback can be started.
* <ul>
- * <li>There are two ways (synchronous vs.
- * asynchronous) that the <em>Prepared</em> state can be reached:
- * either a call to {@link #prepare()} (synchronous) which
- * transfers the object to the <em>Prepared</em> state once the method call
- * returns, or a call to {@link #prepareAsync()} (asynchronous) which
- * first transfers the object to the <em>Preparing</em> state after the
+ * <li>{@link #prepareAsync()} first transfers the object to the
+ * <em>Preparing</em> state after the
* call returns (which occurs almost right way) while the internal
* player engine continues working on the rest of preparation work
- * until the preparation work completes. When the preparation completes or when {@link #prepare()} call returns,
+ * until the preparation work completes. When the preparation completes,
* the internal player engine then calls a user supplied callback method,
* onPrepared() of the EventCallback interface, if an
* EventCallback is registered beforehand via {@link
@@ -224,7 +220,7 @@
* of calling any method with side effect while a MediaPlayer2 object is
* in the <em>Preparing</em> state is undefined.</li>
* <li>An IllegalStateException is
- * thrown if {@link #prepare()} or {@link #prepareAsync()} is called in
+ * thrown if {@link #prepareAsync()} is called in
* any other state.</li>
* <li>While in the <em>Prepared</em> state, properties
* such as audio/sound volume, screenOnWhilePlaying, looping can be
@@ -395,7 +391,7 @@
* <td>{Error}</p></td>
* <td>Successful invoke of this method does not change the state. In order for the
* target audio attributes type to become effective, this method must be called before
- * prepare() or prepareAsync().</p></td></tr>
+ * prepareAsync().</p></td></tr>
* <tr><td>setAudioSessionId </p></td>
* <td>{Idle} </p></td>
* <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted,
@@ -409,7 +405,7 @@
* <td>{Error}</p></td>
* <td>Successful invoke of this method does not change the state. In order for the
* target audio stream type to become effective, this method must be called before
- * prepare() or prepareAsync().</p></td></tr>
+ * prepareAsync().</p></td></tr>
* <tr><td>setAuxEffectSendLevel </p></td>
* <td>any</p></td>
* <td>{} </p></td>
@@ -561,9 +557,12 @@
private boolean mBypassInterruptionPolicy;
private final CloseGuard mGuard = CloseGuard.get();
+ private final Object mPlLock = new Object();
private List<DataSourceDesc> mPlaylist;
- private int mPLCurrentIndex = 0;
- private int mPLNextIndex = -1;
+ private int mPlCurrentIndex = 0;
+ private int mPlNextIndex = -1;
+ private int mPlNextSourceState = NEXT_SOURCE_STATE_INIT;
+ private boolean mPlNextSourcePlayPending = false;
private int mLoopingMode = LOOPING_MODE_NONE;
// Modular DRM
@@ -605,6 +604,11 @@
native_setup(new WeakReference<MediaPlayer2Impl>(this));
}
+ private static final int NEXT_SOURCE_STATE_ERROR = -1;
+ private static final int NEXT_SOURCE_STATE_INIT = 0;
+ private static final int NEXT_SOURCE_STATE_PREPARING = 1;
+ private static final int NEXT_SOURCE_STATE_PREPARED = 2;
+
/*
* Update the MediaPlayer2Impl SurfaceTexture.
* Call after setting a new display surface.
@@ -774,10 +778,13 @@
@Override
public void setDataSource(@NonNull DataSourceDesc dsd) throws IOException {
Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
- mPlaylist = Collections.synchronizedList(new ArrayList<DataSourceDesc>(1));
- mPlaylist.add(dsd);
- mPLCurrentIndex = 0;
- setDataSourcePriv(dsd);
+ synchronized (mPlLock) {
+ mPlaylist = Collections.synchronizedList(new ArrayList<DataSourceDesc>(1));
+ mPlaylist.add(dsd);
+ mPlCurrentIndex = 0;
+ mPlNextIndex = -1;
+ handleDataSource(true /* isCurrent */, dsd);
+ }
}
/**
@@ -787,10 +794,12 @@
*/
@Override
public DataSourceDesc getCurrentDataSource() {
- if (mPlaylist == null) {
- return null;
+ synchronized (mPlLock) {
+ if (mPlaylist == null) {
+ return null;
+ }
+ return mPlaylist.get(mPlCurrentIndex);
}
- return mPlaylist.get(mPLCurrentIndex);
}
/**
@@ -826,11 +835,14 @@
startIndex = pl.size() - 1;
}
- mPlaylist = Collections.synchronizedList(new ArrayList(pl));
- mPLCurrentIndex = startIndex;
- setDataSourcePriv(mPlaylist.get(startIndex));
- // TODO: handle the preparation of next source in the play list.
- // It should be processed after current source is prepared.
+ synchronized (mPlLock) {
+ mPlaylist = Collections.synchronizedList(new ArrayList(pl));
+ mPlCurrentIndex = startIndex;
+ handleDataSource(true /* isCurrent */, mPlaylist.get(startIndex));
+ // TODO: handle the preparation of next source in the play list.
+ // It should be processed after current source is prepared.
+ mPlNextIndex = getNextIndex_l();
+ }
}
/**
@@ -840,10 +852,12 @@
*/
@Override
public List<DataSourceDesc> getPlaylist() {
- if (mPlaylist == null) {
- return null;
+ synchronized (mPlLock) {
+ if (mPlaylist == null) {
+ return null;
+ }
+ return new ArrayList(mPlaylist);
}
- return new ArrayList(mPlaylist);
}
/**
@@ -855,19 +869,21 @@
*/
@Override
public void setCurrentPlaylistItem(int index) {
- if (mPlaylist == null) {
- throw new IllegalArgumentException("play list has not been set yet.");
- }
- if (index < 0 || index >= mPlaylist.size()) {
- throw new IndexOutOfBoundsException("index is out of play list range.");
- }
+ synchronized (mPlLock) {
+ if (mPlaylist == null) {
+ throw new IllegalArgumentException("play list has not been set yet.");
+ }
+ if (index < 0 || index >= mPlaylist.size()) {
+ throw new IndexOutOfBoundsException("index is out of play list range.");
+ }
- if (index == mPLCurrentIndex) {
- return;
- }
+ if (index == mPlCurrentIndex) {
+ return;
+ }
- // TODO: in playing state, stop current source and start to play source of index.
- mPLCurrentIndex = index;
+ // TODO: in playing state, stop current source and start to play source of index.
+ mPlCurrentIndex = index;
+ }
}
/**
@@ -879,19 +895,21 @@
*/
@Override
public void setNextPlaylistItem(int index) {
- if (mPlaylist == null) {
- throw new IllegalArgumentException("play list has not been set yet.");
- }
- if (index < 0 || index >= mPlaylist.size()) {
- throw new IndexOutOfBoundsException("index is out of play list range.");
- }
+ synchronized (mPlLock) {
+ if (mPlaylist == null) {
+ throw new IllegalArgumentException("play list has not been set yet.");
+ }
+ if (index < 0 || index >= mPlaylist.size()) {
+ throw new IndexOutOfBoundsException("index is out of play list range.");
+ }
- if (index == mPLNextIndex) {
- return;
- }
+ if (index == mPlNextIndex) {
+ return;
+ }
- // TODO: prepare the new next-to-be-played DataSourceDesc
- mPLNextIndex = index;
+ // TODO: prepare the new next-to-be-played DataSourceDesc
+ mPlNextIndex = index;
+ }
}
/**
@@ -901,7 +919,9 @@
*/
@Override
public int getCurrentPlaylistItemIndex() {
- return mPLCurrentIndex;
+ synchronized (mPlLock) {
+ return mPlCurrentIndex;
+ }
}
/**
@@ -920,12 +940,15 @@
&& mode != LOOPING_MODE_SHUFFLE) {
throw new IllegalArgumentException("mode is not supported.");
}
- mLoopingMode = mode;
- if (mPlaylist == null) {
- return;
- }
- // TODO: handle the new mode if necessary.
+ synchronized (mPlLock) {
+ mLoopingMode = mode;
+ if (mPlaylist == null) {
+ return;
+ }
+
+ // TODO: handle the new mode if necessary.
+ }
}
/**
@@ -935,7 +958,9 @@
*/
@Override
public int getLoopingMode() {
- return mPLCurrentIndex;
+ synchronized (mPlLock) {
+ return mPlCurrentIndex;
+ }
}
/**
@@ -946,10 +971,12 @@
*/
@Override
public void movePlaylistItem(int indexFrom, int indexTo) {
- if (mPlaylist == null) {
- throw new IllegalArgumentException("play list has not been set yet.");
+ synchronized (mPlLock) {
+ if (mPlaylist == null) {
+ throw new IllegalArgumentException("play list has not been set yet.");
+ }
+ // TODO: move the DataSourceDesc from indexFrom to indexTo.
}
- // TODO: move the DataSourceDesc from indexFrom to indexTo.
}
/**
@@ -964,14 +991,16 @@
*/
@Override
public DataSourceDesc removePlaylistItem(int index) {
- if (mPlaylist == null) {
- throw new IllegalArgumentException("play list has not been set yet.");
- }
+ synchronized (mPlLock) {
+ if (mPlaylist == null) {
+ throw new IllegalArgumentException("play list has not been set yet.");
+ }
- DataSourceDesc oldDsd = mPlaylist.remove(index);
- // TODO: if index == mPLCurrentIndex, stop current source and move to next one.
- // if index == mPLNextIndex, prepare the new next-to-be-played source.
- return oldDsd;
+ DataSourceDesc oldDsd = mPlaylist.remove(index);
+ // TODO: if index == mPlCurrentIndex, stop current source and move to next one.
+ // if index == mPlNextIndex, prepare the new next-to-be-played source.
+ return oldDsd;
+ }
}
/**
@@ -990,26 +1019,28 @@
public void addPlaylistItem(int index, DataSourceDesc dsd) {
Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
- if (mPlaylist == null) {
- if (index == 0) {
- mPlaylist = Collections.synchronizedList(new ArrayList<DataSourceDesc>());
- mPlaylist.add(dsd);
- mPLCurrentIndex = 0;
- return;
+ synchronized (mPlLock) {
+ if (mPlaylist == null) {
+ if (index == 0) {
+ mPlaylist = Collections.synchronizedList(new ArrayList<DataSourceDesc>());
+ mPlaylist.add(dsd);
+ mPlCurrentIndex = 0;
+ return;
+ }
+ throw new IllegalArgumentException("index should be 0 for first DataSourceDesc.");
}
- throw new IllegalArgumentException("index should be 0 for first DataSourceDesc.");
- }
- long id = dsd.getId();
- for (DataSourceDesc pldsd : mPlaylist) {
- if (id == pldsd.getId()) {
- throw new IllegalArgumentException("Id of dsd already exists in the play list.");
+ long id = dsd.getId();
+ for (DataSourceDesc pldsd : mPlaylist) {
+ if (id == pldsd.getId()) {
+ throw new IllegalArgumentException("Id of dsd already exists in the play list.");
+ }
}
- }
- mPlaylist.add(index, dsd);
- if (index <= mPLCurrentIndex) {
- ++mPLCurrentIndex;
+ mPlaylist.add(index, dsd);
+ if (index <= mPlCurrentIndex) {
+ ++mPlCurrentIndex;
+ }
}
}
@@ -1036,42 +1067,62 @@
Preconditions.checkNotNull(mPlaylist, "the play list cannot be null");
long id = dsd.getId();
- for (int i = 0; i < mPlaylist.size(); ++i) {
- if (i == index) {
- continue;
+ synchronized (mPlLock) {
+ for (int i = 0; i < mPlaylist.size(); ++i) {
+ if (i == index) {
+ continue;
+ }
+ if (id == mPlaylist.get(i).getId()) {
+ throw new IllegalArgumentException(
+ "Id of dsd already exists in the play list.");
+ }
}
- if (id == mPlaylist.get(i).getId()) {
- throw new IllegalArgumentException("Id of dsd already exists in the play list.");
- }
- }
- // TODO: if needed, stop playback of current source, and start new dsd.
- DataSourceDesc oldDsd = mPlaylist.set(index, dsd);
- return mPlaylist.set(index, dsd);
+ // TODO: if needed, stop playback of current source, and start new dsd.
+ DataSourceDesc oldDsd = mPlaylist.set(index, dsd);
+ return mPlaylist.set(index, dsd);
+ }
}
- private void setDataSourcePriv(@NonNull DataSourceDesc dsd) throws IOException {
+ // Called with mPlLock acquired.
+ // TODO: support all looping modes
+ private int getNextIndex_l() {
+ if (mPlaylist.size() <= 1) {
+ return -1;
+ }
+ int index = mPlCurrentIndex + 1;
+ if (index >= mPlaylist.size()) {
+ index = 0;
+ }
+ return index;
+ }
+
+ private void handleDataSource(boolean isCurrent, @NonNull DataSourceDesc dsd)
+ throws IOException {
Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
switch (dsd.getType()) {
case DataSourceDesc.TYPE_CALLBACK:
- setDataSourcePriv(dsd.getId(),
- dsd.getMedia2DataSource());
+ handleDataSource(isCurrent,
+ dsd.getId(),
+ dsd.getMedia2DataSource());
break;
case DataSourceDesc.TYPE_FD:
- setDataSourcePriv(dsd.getId(),
- dsd.getFileDescriptor(),
- dsd.getFileDescriptorOffset(),
- dsd.getFileDescriptorLength());
+ handleDataSource(isCurrent,
+ dsd.getId(),
+ dsd.getFileDescriptor(),
+ dsd.getFileDescriptorOffset(),
+ dsd.getFileDescriptorLength());
break;
case DataSourceDesc.TYPE_URI:
- setDataSourcePriv(dsd.getId(),
- dsd.getUriContext(),
- dsd.getUri(),
- dsd.getUriHeaders(),
- dsd.getUriCookies());
+ handleDataSource(isCurrent,
+ dsd.getId(),
+ dsd.getUriContext(),
+ dsd.getUri(),
+ dsd.getUriHeaders(),
+ dsd.getUriCookies());
break;
default:
@@ -1098,66 +1149,59 @@
* @throws NullPointerException if context or uri is null
* @throws IOException if uri has a file scheme and an I/O error occurs
*/
- private void setDataSourcePriv(long srcId, @NonNull Context context, @NonNull Uri uri,
+ private void handleDataSource(
+ boolean isCurrent, long srcId,
+ @NonNull Context context, @NonNull Uri uri,
@Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies)
throws IOException {
- if (context == null) {
- throw new NullPointerException("context param can not be null.");
- }
-
- if (uri == null) {
- throw new NullPointerException("uri param can not be null.");
- }
-
- if (cookies != null) {
- CookieHandler cookieHandler = CookieHandler.getDefault();
- if (cookieHandler != null && !(cookieHandler instanceof CookieManager)) {
- throw new IllegalArgumentException("The cookie handler has to be of CookieManager "
- + "type when cookies are provided.");
- }
- }
-
// The context and URI usually belong to the calling user. Get a resolver for that user
// and strip out the userId from the URI if present.
final ContentResolver resolver = context.getContentResolver();
final String scheme = uri.getScheme();
final String authority = ContentProvider.getAuthorityWithoutUserId(uri.getAuthority());
if (ContentResolver.SCHEME_FILE.equals(scheme)) {
- setDataSourcePriv(srcId, uri.getPath(), null, null);
+ handleDataSource(isCurrent, srcId, uri.getPath(), null, null);
return;
- } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
+ }
+
+ if (ContentResolver.SCHEME_CONTENT.equals(scheme)
&& Settings.AUTHORITY.equals(authority)) {
// Try cached ringtone first since the actual provider may not be
// encryption aware, or it may be stored on CE media storage
final int type = RingtoneManager.getDefaultType(uri);
final Uri cacheUri = RingtoneManager.getCacheForType(type, context.getUserId());
final Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(context, type);
- if (attemptDataSource(srcId, resolver, cacheUri)) {
+ if (attemptDataSource(isCurrent, srcId, resolver, cacheUri)) {
return;
- } else if (attemptDataSource(srcId, resolver, actualUri)) {
- return;
- } else {
- setDataSourcePriv(srcId, uri.toString(), headers, cookies);
}
+ if (attemptDataSource(isCurrent, srcId, resolver, actualUri)) {
+ return;
+ }
+ handleDataSource(isCurrent, srcId, uri.toString(), headers, cookies);
} else {
// Try requested Uri locally first, or fallback to media server
- if (attemptDataSource(srcId, resolver, uri)) {
+ if (attemptDataSource(isCurrent, srcId, resolver, uri)) {
return;
- } else {
- setDataSourcePriv(srcId, uri.toString(), headers, cookies);
}
+ handleDataSource(isCurrent, srcId, uri.toString(), headers, cookies);
}
}
- private boolean attemptDataSource(long srcId, ContentResolver resolver, Uri uri) {
+ private boolean attemptDataSource(
+ boolean isCurrent, long srcId, ContentResolver resolver, Uri uri) {
try (AssetFileDescriptor afd = resolver.openAssetFileDescriptor(uri, "r")) {
if (afd.getDeclaredLength() < 0) {
- setDataSourcePriv(srcId, afd.getFileDescriptor(), 0, DataSourceDesc.LONG_MAX);
+ handleDataSource(isCurrent,
+ srcId,
+ afd.getFileDescriptor(),
+ 0,
+ DataSourceDesc.LONG_MAX);
} else {
- setDataSourcePriv(srcId,
- afd.getFileDescriptor(),
- afd.getStartOffset(),
- afd.getDeclaredLength());
+ handleDataSource(isCurrent,
+ srcId,
+ afd.getFileDescriptor(),
+ afd.getStartOffset(),
+ afd.getDeclaredLength());
}
return true;
} catch (NullPointerException | SecurityException | IOException ex) {
@@ -1166,10 +1210,10 @@
}
}
- private void setDataSourcePriv(
- long srcId, String path, Map<String, String> headers, List<HttpCookie> cookies)
- throws IOException, IllegalArgumentException, SecurityException, IllegalStateException
- {
+ private void handleDataSource(
+ boolean isCurrent, long srcId,
+ String path, Map<String, String> headers, List<HttpCookie> cookies)
+ throws IOException {
String[] keys = null;
String[] values = null;
@@ -1184,19 +1228,20 @@
++i;
}
}
- setDataSourcePriv(srcId, path, keys, values, cookies);
+ handleDataSource(isCurrent, srcId, path, keys, values, cookies);
}
- private void setDataSourcePriv(long srcId, String path, String[] keys, String[] values,
- List<HttpCookie> cookies)
- throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
+ private void handleDataSource(boolean isCurrent, long srcId,
+ String path, String[] keys, String[] values, List<HttpCookie> cookies)
+ throws IOException {
final Uri uri = Uri.parse(path);
final String scheme = uri.getScheme();
if ("file".equals(scheme)) {
path = uri.getPath();
} else if (scheme != null) {
// handle non-file sources
- nativeSetDataSource(
+ nativeHandleDataSourceUrl(
+ isCurrent,
srcId,
Media2HTTPService.createHTTPService(path, cookies),
path,
@@ -1209,16 +1254,17 @@
if (file.exists()) {
FileInputStream is = new FileInputStream(file);
FileDescriptor fd = is.getFD();
- setDataSourcePriv(srcId, fd, 0, DataSourceDesc.LONG_MAX);
+ handleDataSource(isCurrent, srcId, fd, 0, DataSourceDesc.LONG_MAX);
is.close();
} else {
- throw new IOException("setDataSourcePriv failed.");
+ throw new IOException("handleDataSource failed.");
}
}
- private native void nativeSetDataSource(
- long srcId, Media2HTTPService httpService, String path, String[] keys, String[] values)
- throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
+ private native void nativeHandleDataSourceUrl(
+ boolean isCurrent, long srcId,
+ Media2HTTPService httpService, String path, String[] keys, String[] values)
+ throws IOException;
/**
* Sets the data source (FileDescriptor) to use. The FileDescriptor must be
@@ -1229,53 +1275,92 @@
* @throws IllegalArgumentException if fd is not a valid FileDescriptor
* @throws IOException if fd can not be read
*/
- private void setDataSourcePriv(long srcId, FileDescriptor fd, long offset, long length)
- throws IOException {
- _setDataSource(srcId, fd, offset, length);
+ private void handleDataSource(
+ boolean isCurrent, long srcId,
+ FileDescriptor fd, long offset, long length) throws IOException {
+ nativeHandleDataSourceFD(isCurrent, srcId, fd, offset, length);
}
- private native void _setDataSource(long srcId, FileDescriptor fd, long offset, long length)
- throws IOException;
+ private native void nativeHandleDataSourceFD(boolean isCurrent, long srcId,
+ FileDescriptor fd, long offset, long length) throws IOException;
/**
* @throws IllegalStateException if it is called in an invalid state
* @throws IllegalArgumentException if dataSource is not a valid Media2DataSource
*/
- private void setDataSourcePriv(long srcId, Media2DataSource dataSource) {
- _setDataSource(srcId, dataSource);
+ private void handleDataSource(boolean isCurrent, long srcId, Media2DataSource dataSource) {
+ nativeHandleDataSourceCallback(isCurrent, srcId, dataSource);
}
- private native void _setDataSource(long srcId, Media2DataSource dataSource);
+ private native void nativeHandleDataSourceCallback(
+ boolean isCurrent, long srcId, Media2DataSource dataSource);
- /**
- * Prepares the player for playback, synchronously.
- *
- * After setting the datasource and the display surface, you need to either
- * call prepare() or prepareAsync(). For files, it is OK to call prepare(),
- * which blocks until MediaPlayer2 is ready for playback.
- *
- * @throws IOException if source can not be accessed
- * @throws IllegalStateException if it is called in an invalid state
- * @hide
- */
- @Override
- public void prepare() throws IOException {
- _prepare();
- scanInternalSubtitleTracks();
+ // This function shall be called with |mPlLock| acquired.
+ private void prepareNextDataSource_l() {
+ if (mPlNextIndex < 0 || mPlNextSourceState != NEXT_SOURCE_STATE_INIT) {
+ // There is no next source or it's in preparing or prepared state.
+ return;
+ }
- // DrmInfo, if any, has been resolved by now.
- synchronized (mDrmLock) {
- mDrmInfoResolved = true;
+ try {
+ mPlNextSourceState = NEXT_SOURCE_STATE_PREPARING;
+ handleDataSource(false /* isCurrent */, mPlaylist.get(mPlNextIndex));
+ } catch (Exception e) {
+ Message msg2 = mEventHandler.obtainMessage(
+ MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
+ final long nextSrcId = mPlaylist.get(mPlNextIndex).getId();
+ mEventHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mEventHandler.handleMessage(msg2, nextSrcId);
+ }
+ });
}
}
- private native void _prepare() throws IOException, IllegalStateException;
+ // This function shall be called with |mPlLock| acquired.
+ private void playNextDataSource_l() {
+ if (mPlNextIndex < 0) {
+ return;
+ }
+
+ if (mPlNextSourceState == NEXT_SOURCE_STATE_PREPARED) {
+ // Switch to next source only when it's in prepared state.
+ mPlCurrentIndex = mPlNextIndex;
+ mPlNextIndex = getNextIndex_l();
+ mPlNextSourceState = NEXT_SOURCE_STATE_INIT;
+ mPlNextSourcePlayPending = false;
+
+ long srcId = mPlaylist.get(mPlCurrentIndex).getId();
+ try {
+ nativePlayNextDataSource(srcId);
+ } catch (Exception e) {
+ Message msg2 = mEventHandler.obtainMessage(
+ MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
+ mEventHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mEventHandler.handleMessage(msg2, srcId);
+ }
+ });
+ }
+
+ // Wait for MEDIA2_INFO_STARTED_AS_NEXT to prepare next source.
+ } else {
+ if (mPlNextSourceState == NEXT_SOURCE_STATE_INIT) {
+ prepareNextDataSource_l();
+ }
+ mPlNextSourcePlayPending = true;
+ }
+ }
+
+ private native void nativePlayNextDataSource(long srcId);
/**
* Prepares the player for playback, asynchronously.
*
* After setting the datasource and the display surface, you need to either
- * call prepare() or prepareAsync(). For streams, you should call prepareAsync(),
+ * call prepareAsync(). For streams, you should call prepareAsync(),
* which returns immediately, rather than blocking until enough data has been
* buffered.
*
@@ -1925,7 +2010,7 @@
/**
* Resets the MediaPlayer2 to its uninitialized state. After calling
* this method, you will have to initialize it again by setting the
- * data source and calling prepare().
+ * data source and calling prepareAsync().
*/
@Override
public void reset() {
@@ -2000,7 +2085,7 @@
/**
* Sets the audio attributes for this MediaPlayer2.
* See {@link AudioAttributes} for how to build and configure an instance of this class.
- * You must call this method before {@link #prepare()} or {@link #prepareAsync()} in order
+ * You must call this method before {@link #prepareAsync()} in order
* for the audio attributes to become effective thereafter.
* @param attributes a non-null set of audio attributes
* @throws IllegalArgumentException if the attributes are null or invalid.
@@ -3089,6 +3174,19 @@
sendMessage(msg2);
}
+ synchronized (mPlLock) {
+ Log.i(TAG, "MEDIA_PREPARED: srcId=" + srcId
+ + ", currentIndex=" + mPlCurrentIndex + ", nextIndex=" + mPlNextIndex);
+ if (mPlCurrentIndex >= 0 && srcId == mPlaylist.get(mPlCurrentIndex).getId()) {
+ prepareNextDataSource_l();
+ } else if (mPlNextIndex >= 0 && srcId == mPlaylist.get(mPlNextIndex).getId()) {
+ mPlNextSourceState = NEXT_SOURCE_STATE_PREPARED;
+ if (mPlNextSourcePlayPending) {
+ playNextDataSource_l();
+ }
+ }
+ }
+
synchronized (mEventCbLock) {
for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onInfo(
@@ -3127,6 +3225,14 @@
return;
case MEDIA_PLAYBACK_COMPLETE:
+ synchronized (mPlLock) {
+ if (mPlCurrentIndex >= 0 && srcId == mPlaylist.get(mPlCurrentIndex).getId()) {
+ Log.i(TAG, "MEDIA_PLAYBACK_COMPLETE: srcId=" + srcId
+ + ", currentIndex=" + mPlCurrentIndex + ", nextIndex=" + mPlNextIndex);
+ playNextDataSource_l();
+ }
+ }
+
synchronized (mEventCbLock) {
for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
cb.first.execute(() -> cb.second.onInfo(
@@ -3209,6 +3315,12 @@
case MEDIA_INFO:
switch (msg.arg1) {
+ case MEDIA_INFO_STARTED_AS_NEXT:
+ if (mPlCurrentIndex >= 0 && srcId == mPlaylist.get(mPlCurrentIndex).getId()) {
+ prepareNextDataSource_l();
+ }
+ break;
+
case MEDIA_INFO_VIDEO_TRACK_LAGGING:
Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")");
break;
@@ -3517,7 +3629,7 @@
/**
* Retrieves the DRM Info associated with the current source
*
- * @throws IllegalStateException if called before prepare()
+ * @throws IllegalStateException if called before prepareAsync()
*/
@Override
public DrmInfo getDrmInfo() {
@@ -3568,7 +3680,7 @@
* @param uuid The UUID of the crypto scheme. If not known beforehand, it can be retrieved
* from the source through {@code getDrmInfo} or registering a {@code onDrmInfoListener}.
*
- * @throws IllegalStateException if called before prepare(), or the DRM was
+ * @throws IllegalStateException if called before prepareAsync(), or the DRM was
* prepared already
* @throws UnsupportedSchemeException if the crypto scheme is not supported
* @throws ResourceBusyException if required DRM resources are in use
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 823410f..9ad5cd9 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -17,6 +17,7 @@
package android.media;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.app.ActivityThread;
import android.hardware.Camera;
@@ -278,6 +279,7 @@
* third-party applications.
* </p>
*/
+ @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT)
public static final int REMOTE_SUBMIX = 8;
/** Microphone audio source tuned for unprocessed (raw) sound if available, behaves like
@@ -303,6 +305,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_HOTWORD)
public static final int HOTWORD = 1999;
}
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 2190635..343bbda 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -400,6 +400,7 @@
new AudioAttributes.Builder()
.setInternalCapturePreset(MediaRecorder.AudioSource.REMOTE_SUBMIX)
.addTag(addressForTag(mix))
+ .addTag(AudioRecord.SUBMIX_FIXED_VOLUME)
.build(),
mixFormat,
AudioRecord.getMinBufferSize(mix.getFormat().getSampleRate(),
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 51bc330..5a0081a 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -273,9 +273,9 @@
}
static void
-android_media_MediaPlayer2_setDataSourceAndHeaders(
- JNIEnv *env, jobject thiz, jlong srcId, jobject httpServiceObj, jstring path,
- jobjectArray keys, jobjectArray values) {
+android_media_MediaPlayer2_handleDataSourceUrl(
+ JNIEnv *env, jobject thiz, jboolean isCurrent, jlong srcId,
+ jobject httpServiceObj, jstring path, jobjectArray keys, jobjectArray values) {
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL) {
@@ -292,10 +292,10 @@
if (tmp == NULL) { // Out of memory
return;
}
- ALOGV("setDataSourceAndHeaders: path %s, srcId %lld", tmp, (long long)srcId);
+ ALOGV("handleDataSourceUrl: path %s, srcId %lld", tmp, (long long)srcId);
if (strncmp(tmp, "content://", 10) == 0) {
- ALOGE("setDataSourceAndHeaders: content scheme is not supported in native code");
+ ALOGE("handleDataSourceUrl: content scheme is not supported in native code");
jniThrowException(env, "java/io/IOException",
"content scheme is not supported in native code");
return;
@@ -321,14 +321,20 @@
}
dsd->mHttpService = httpService;
- process_media_player_call(
- env, thiz, mp->setDataSource(dsd), "java/io/IOException",
- "setDataSourceAndHeaders failed." );
+ status_t err;
+ if (isCurrent) {
+ err = mp->setDataSource(dsd);
+ } else {
+ err = mp->prepareNextDataSource(dsd);
+ }
+ process_media_player_call(env, thiz, err,
+ "java/io/IOException", "handleDataSourceUrl failed." );
}
static void
-android_media_MediaPlayer2_setDataSourceFD(
- JNIEnv *env, jobject thiz, jlong srcId, jobject fileDescriptor, jlong offset, jlong length)
+android_media_MediaPlayer2_handleDataSourceFD(
+ JNIEnv *env, jobject thiz, jboolean isCurrent, jlong srcId,
+ jobject fileDescriptor, jlong offset, jlong length)
{
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
@@ -341,14 +347,14 @@
return;
}
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- ALOGV("setDataSourceFD: srcId=%lld, fd=%d (%s), offset=%lld, length=%lld",
+ ALOGV("handleDataSourceFD: srcId=%lld, fd=%d (%s), offset=%lld, length=%lld",
(long long)srcId, fd, nameForFd(fd).c_str(), (long long)offset, (long long)length);
struct stat sb;
int ret = fstat(fd, &sb);
if (ret != 0) {
- ALOGE("setDataSourceFD: fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
- jniThrowException(env, "java/io/IOException", "setDataSourceFD failed fstat");
+ ALOGE("handleDataSourceFD: fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
+ jniThrowException(env, "java/io/IOException", "handleDataSourceFD failed fstat");
return;
}
@@ -359,14 +365,14 @@
ALOGV("st_size = %llu", static_cast<unsigned long long>(sb.st_size));
if (offset >= sb.st_size) {
- ALOGE("setDataSourceFD: offset is out of range");
+ ALOGE("handleDataSourceFD: offset is out of range");
jniThrowException(env, "java/lang/IllegalArgumentException",
- "setDataSourceFD failed, offset is out of range.");
+ "handleDataSourceFD failed, offset is out of range.");
return;
}
if (offset + length > sb.st_size) {
length = sb.st_size - offset;
- ALOGV("setDataSourceFD: adjusted length = %lld", (long long)length);
+ ALOGV("handleDataSourceFD: adjusted length = %lld", (long long)length);
}
sp<DataSourceDesc> dsd = new DataSourceDesc();
@@ -375,13 +381,20 @@
dsd->mFD = fd;
dsd->mFDOffset = offset;
dsd->mFDLength = length;
- process_media_player_call(env, thiz, mp->setDataSource(dsd),
- "java/io/IOException", "setDataSourceFD failed." );
+
+ status_t err;
+ if (isCurrent) {
+ err = mp->setDataSource(dsd);
+ } else {
+ err = mp->prepareNextDataSource(dsd);
+ }
+ process_media_player_call(env, thiz, err,
+ "java/io/IOException", "handleDataSourceFD failed." );
}
static void
-android_media_MediaPlayer2_setDataSourceCallback(
- JNIEnv *env, jobject thiz, jlong srcId, jobject dataSource)
+android_media_MediaPlayer2_handleDataSourceCallback(
+ JNIEnv *env, jobject thiz, jboolean isCurrent, jlong srcId, jobject dataSource)
{
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
@@ -398,8 +411,15 @@
dsd->mId = srcId;
dsd->mType = DataSourceDesc::TYPE_CALLBACK;
dsd->mCallbackSource = callbackDataSource;
- process_media_player_call(env, thiz, mp->setDataSource(dsd),
- "java/lang/RuntimeException", "setDataSourceCallback failed." );
+
+ status_t err;
+ if (isCurrent) {
+ err = mp->setDataSource(dsd);
+ } else {
+ err = mp->prepareNextDataSource(dsd);
+ }
+ process_media_player_call(env, thiz, err,
+ "java/lang/RuntimeException", "handleDataSourceCallback failed." );
}
static sp<ANativeWindowWrapper>
@@ -503,20 +523,16 @@
}
static void
-android_media_MediaPlayer2_prepare(JNIEnv *env, jobject thiz)
+android_media_MediaPlayer2_playNextDataSource(JNIEnv *env, jobject thiz, jlong srcId)
{
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
- if (mp == NULL ) {
+ if (mp == NULL) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return;
}
- // Handle the case where the display surface was set before the mp was
- // initialized. We try again to make it stick.
- sp<ANativeWindowWrapper> st = getVideoSurfaceTexture(env, thiz);
- mp->setVideoSurfaceTexture(st);
-
- process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
+ process_media_player_call(env, thiz, mp->playNextDataSource((int64_t)srcId),
+ "java/io/IOException", "playNextDataSource failed." );
}
static void
@@ -1449,18 +1465,25 @@
static const JNINativeMethod gMethods[] = {
{
- "nativeSetDataSource",
- "(JLandroid/media/Media2HTTPService;Ljava/lang/String;[Ljava/lang/String;"
+ "nativeHandleDataSourceUrl",
+ "(ZJLandroid/media/Media2HTTPService;Ljava/lang/String;[Ljava/lang/String;"
"[Ljava/lang/String;)V",
- (void *)android_media_MediaPlayer2_setDataSourceAndHeaders
+ (void *)android_media_MediaPlayer2_handleDataSourceUrl
},
-
- {"_setDataSource", "(JLjava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer2_setDataSourceFD},
- {"_setDataSource", "(JLandroid/media/Media2DataSource;)V",(void *)android_media_MediaPlayer2_setDataSourceCallback },
+ {
+ "nativeHandleDataSourceFD",
+ "(ZJLjava/io/FileDescriptor;JJ)V",
+ (void *)android_media_MediaPlayer2_handleDataSourceFD
+ },
+ {
+ "nativeHandleDataSourceCallback",
+ "(ZJLandroid/media/Media2DataSource;)V",
+ (void *)android_media_MediaPlayer2_handleDataSourceCallback
+ },
+ {"nativePlayNextDataSource", "(J)V", (void *)android_media_MediaPlayer2_playNextDataSource},
{"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer2_setVideoSurface},
{"getBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer2_getBufferingParams},
{"setBufferingParams", "(Landroid/media/BufferingParams;)V", (void *)android_media_MediaPlayer2_setBufferingParams},
- {"_prepare", "()V", (void *)android_media_MediaPlayer2_prepare},
{"prepareAsync", "()V", (void *)android_media_MediaPlayer2_prepareAsync},
{"_start", "()V", (void *)android_media_MediaPlayer2_start},
{"_stop", "()V", (void *)android_media_MediaPlayer2_stop},
diff --git a/telephony/java/android/telephony/OWNERS b/packages/CarrierDefaultApp/OWNERS
similarity index 92%
rename from telephony/java/android/telephony/OWNERS
rename to packages/CarrierDefaultApp/OWNERS
index 68dedce..7057ce6 100644
--- a/telephony/java/android/telephony/OWNERS
+++ b/packages/CarrierDefaultApp/OWNERS
@@ -1,14 +1,12 @@
-set noparent
-
-amitmahajan@google.com
+tgunn@google.com
breadley@google.com
-fionaxu@google.com
-jackyu@google.com
hallliu@google.com
rgreenwalt@google.com
-tgunn@google.com
-jminjie@google.com
mpq@google.com
+amitmahajan@google.com
+fionaxu@google.com
+jackyu@google.com
+jminjie@google.com
+satk@google.com
shuoq@google.com
-refuhoo@google.com
-
+refuhoo@google.com
\ No newline at end of file
diff --git a/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml
index e399fb1..9f54652 100644
--- a/packages/DefaultContainerService/AndroidManifest.xml
+++ b/packages/DefaultContainerService/AndroidManifest.xml
@@ -6,9 +6,6 @@
<uses-permission android:name="android.permission.ASEC_DESTROY"/>
<uses-permission android:name="android.permission.ASEC_MOUNT_UNMOUNT"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <!-- Used to improve MeasureUtils performance on emulated storage, and to
- view storage for all users -->
- <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step.png
new file mode 100644
index 0000000..d7f9449
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step_dark.png
new file mode 100644
index 0000000..7c65703
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 0000000..eea819a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 0000000..504ceb7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 0000000..8e7d8cb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 0000000..456a68f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 0000000..fb854ec
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 0000000..75d184a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 0000000..9e0af28
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 0000000..7c00bd5d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 0000000..81b4466
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 0000000..724aa9e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 0000000..7ba0d1b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 0000000..a175ccb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 0000000..45ce1d4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 0000000..6da0c9e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 0000000..71e8959
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 0000000..bb7ae26
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 0000000..32b9ded
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 0000000..ed1949c7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step.png
new file mode 100644
index 0000000..d888869
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step_dark.png
new file mode 100644
index 0000000..dc3b25c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 0000000..d4e5a94
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 0000000..0e693f7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 0000000..0757799
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 0000000..4f07ec1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step.png
new file mode 100644
index 0000000..ba5b457
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step_dark.png
new file mode 100644
index 0000000..a55ea1d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 0000000..407ef28
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 0000000..39cfbf2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 0000000..a7fd3a6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 0000000..f2a1255
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step.png
new file mode 100644
index 0000000..5a7eec6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step_dark.png
new file mode 100644
index 0000000..f7abb54
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 0000000..a1f44dc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 0000000..175a9ae
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 0000000..0fb93ca
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 0000000..1052940
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/quick_settings_header.xml b/packages/SystemUI/res/layout/quick_settings_header.xml
deleted file mode 100644
index 43197c4..0000000
--- a/packages/SystemUI/res/layout/quick_settings_header.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 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
- -->
-<com.android.systemui.qs.QSTooltipView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="@dimen/qs_header_tooltip_height"
- android:alpha="0"
- android:gravity="center_horizontal|bottom"
- android:visibility="invisible">
-
- <TextView
- android:id="@+id/header_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/quick_settings_header_onboarding_text"
- android:textAppearance="@style/TextAppearance.QS.TileLabel"
- android:textColor="?android:attr/colorAccent" />
-
-</com.android.systemui.qs.QSTooltipView>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 13ca114..a5e37d5 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -40,7 +40,7 @@
<dimen name="battery_detail_graph_space_top">27dp</dimen>
<dimen name="battery_detail_graph_space_bottom">27dp</dimen>
- <dimen name="qs_tile_margin_top">32dp</dimen>
+ <dimen name="qs_tile_margin_top">16dp</dimen>
<dimen name="qs_brightness_padding_top">6dp</dimen>
<dimen name="qs_detail_margin_top">28dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/arrays_tv.xml b/packages/SystemUI/res/values/arrays_tv.xml
index 7541b0e..9197bb5 100644
--- a/packages/SystemUI/res/values/arrays_tv.xml
+++ b/packages/SystemUI/res/values/arrays_tv.xml
@@ -30,7 +30,7 @@
<item>com.google.android.apps.mediashell/.settings.CastSettingsActivity</item>
<item>com.google.android.katniss.setting/.SpeechSettingsActivity</item>
<item>com.google.android.katniss.setting/.SearchSettingsActivity</item>
- <item>com.google.android.gsf.notouch/.UsageDiagnosticsSettingActivity</item>
+ <item>com.google.android.tungsten.setupwraith/.settings.usage.UsageDiagnosticsSettingActivity</item>
<item>com.google.android.tvlauncher/.notifications.NotificationsSidePanelActivity</item>
</string-array>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index bc828ff..d17cd21 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -290,7 +290,7 @@
<dimen name="qs_tile_height">106dp</dimen>
<dimen name="qs_tile_margin">19dp</dimen>
- <dimen name="qs_tile_margin_top">32dp</dimen>
+ <dimen name="qs_tile_margin_top">16dp</dimen>
<dimen name="qs_quick_tile_size">48dp</dimen>
<dimen name="qs_quick_tile_padding">12dp</dimen>
<dimen name="qs_header_gear_translation">16dp</dimen>
@@ -309,7 +309,6 @@
<dimen name="qs_tile_padding_bottom">16dp</dimen>
<dimen name="qs_tile_spacing">4dp</dimen>
<dimen name="qs_panel_padding_bottom">0dp</dimen>
- <dimen name="qs_panel_padding_top">32dp</dimen>
<dimen name="qs_detail_header_height">56dp</dimen>
<dimen name="qs_detail_header_padding">0dp</dimen>
<dimen name="qs_detail_image_width">56dp</dimen>
@@ -334,9 +333,6 @@
<dimen name="qs_detail_item_icon_width">32dp</dimen>
<dimen name="qs_detail_item_icon_marginStart">0dp</dimen>
<dimen name="qs_detail_item_icon_marginEnd">20dp</dimen>
- <dimen name="qs_header_padding_start">16dp</dimen>
- <dimen name="qs_header_padding_end">24dp</dimen>
- <dimen name="qs_header_tooltip_height">32dp</dimen>
<dimen name="qs_footer_padding_start">16dp</dimen>
<dimen name="qs_footer_padding_end">24dp</dimen>
<dimen name="qs_footer_icon_size">16dp</dimen>
@@ -924,15 +920,16 @@
<integer name="wireless_charging_fade_duration">200</integer>
<!-- Wired charging on AOD, text animation duration -->
- <integer name="wired_charging_aod_text_animation_duration_down">500</integer>
+ <integer name="wired_charging_keyguard_text_animation_duration_down">500</integer>
<!-- Wired charging on AOD, text animation duration -->
- <integer name="wired_charging_aod_text_animation_duration_up">300</integer>
+ <integer name="wired_charging_keyguard_text_animation_duration_up">300</integer>
<!-- Wired charging on AOD, text animation distance -->
- <integer name="wired_charging_aod_text_animation_distance">-30</integer>
+ <integer name="wired_charging_keyguard_text_animation_distance">-30</integer>
<!-- Logout button -->
<dimen name="logout_button_layout_height">32dp</dimen>
<dimen name="logout_button_padding_horizontal">16dp</dimen>
<dimen name="logout_button_margin_bottom">12dp</dimen>
<dimen name="logout_button_corner_radius">2dp</dimen>
+
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 86cab22..8c59e75 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -666,8 +666,6 @@
<!-- Textual description of Ethernet connections -->
<string name="ethernet_label">Ethernet</string>
- <!-- QuickSettings: Onboarding text that introduces users to long press on an option in order to view the option's menu in Settings [CHAR LIMIT=NONE] -->
- <string name="quick_settings_header_onboarding_text">Press & hold on the icons for more options</string>
<!-- QuickSettings: Do not disturb [CHAR LIMIT=NONE] -->
<string name="quick_settings_dnd_label">Do not disturb</string>
<!-- QuickSettings: Do not disturb - Priority only [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 8b57740..adb4e33 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -47,7 +47,6 @@
Key.QS_INVERT_COLORS_ADDED,
Key.QS_WORK_ADDED,
Key.QS_NIGHTDISPLAY_ADDED,
- Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT,
Key.SEEN_MULTI_USER,
Key.NUM_APPS_LAUNCHED,
Key.HAS_SEEN_RECENTS_ONBOARDING,
@@ -77,11 +76,6 @@
String QS_WORK_ADDED = "QsWorkAdded";
@Deprecated
String QS_NIGHTDISPLAY_ADDED = "QsNightDisplayAdded";
- /**
- * Used for tracking how many times the user has seen the long press tooltip in the Quick
- * Settings panel.
- */
- String QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT = "QsLongPressTooltipShownCount";
String SEEN_MULTI_USER = "HasSeenMultiUser";
String NUM_APPS_LAUNCHED = "NumAppsLaunched";
String HAS_SEEN_RECENTS_ONBOARDING = "HasSeenRecentsOnboarding";
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index ddf0bd0..bb82a54 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -28,6 +28,8 @@
import java.io.PrintWriter;
import com.android.internal.os.BinderInternal;
+import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.plugins.PluginManagerImpl;
public class SystemUIService extends Service {
@@ -70,6 +72,10 @@
pw.println("dumping service: " + ui.getClass().getName());
ui.dump(fd, pw, args);
}
+ if (Build.IS_DEBUGGABLE) {
+ pw.println("dumping plugins:");
+ ((PluginManagerImpl) Dependency.get(PluginManager.class)).dump(fd, pw, args);
+ }
} else {
String svc = args[0];
for (SystemUI ui: services) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 34d3928..aa26419 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -59,6 +59,12 @@
}
@Override
+ public void onDestroy() {
+ Dependency.get(PluginManager.class).removePluginListener(this);
+ super.onDestroy();
+ }
+
+ @Override
public void onPluginConnected(DozeServicePlugin plugin, Context pluginContext) {
mDozePlugin = plugin;
mDozePlugin.setDozeRequester(this);
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
index 82c0128..d5541e9 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -168,6 +168,12 @@
return false;
}
+ @Override
+ public String toString() {
+ return String.format("%s@%s (action=%s)",
+ getClass().getSimpleName(), hashCode(), mAction);
+ }
+
private class MainHandler extends Handler {
private static final int PLUGIN_CONNECTED = 1;
private static final int PLUGIN_DISCONNECTED = 2;
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
index 03747d5..2a17e35 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
@@ -50,6 +50,8 @@
import dalvik.system.PathClassLoader;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Map;
@@ -303,6 +305,14 @@
}
}
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println(String.format(" plugin map (%d):", mPluginMap.size()));
+ for (PluginListener listener: mPluginMap.keySet()) {
+ pw.println(String.format(" %s -> %s",
+ listener, mPluginMap.get(listener)));
+ }
+ }
+
@VisibleForTesting
public static class PluginInstanceManagerFactory {
public <T extends Plugin> PluginInstanceManager createPluginInstanceManager(Context context,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index fccd9ce..222c6e82 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -44,7 +44,6 @@
public static final float EXPANDED_TILE_DELAY = .86f;
-
private final ArrayList<View> mAllViews = new ArrayList<>();
/**
* List of {@link View}s representing Quick Settings that are being animated from the quick QS
@@ -66,11 +65,6 @@
private TouchAnimator mNonfirstPageDelayedAnimator;
private TouchAnimator mBrightnessAnimator;
- /**
- * Whether the animation is stable and not in the middle of animating between the collapsed and
- * expanded states.
- */
- private boolean mIsInStableState;
private boolean mOnKeyguard;
private boolean mAllowFancy;
@@ -95,10 +89,6 @@
Log.w(TAG, "QS Not using page layout");
}
panel.setPageListener(this);
-
- // At time of creation, the QS panel is always considered stable as it's not in the middle
- // of collapse/expanded.
- mIsInStableState = true;
}
public void onRtlChanged() {
@@ -253,11 +243,6 @@
} else {
mBrightnessAnimator = null;
}
- View headerView = mQsPanel.getHeaderView();
- if (headerView!= null) {
- firstPageBuilder.addFloat(headerView, "translationY", heightDiff, 0);
- mAllViews.add(headerView);
- }
mFirstPageAnimator = firstPageBuilder
.setListener(this)
.build();
@@ -341,21 +326,11 @@
@Override
public void onAnimationAtStart() {
- if (!mIsInStableState) {
- mQsPanel.onCollapse();
- }
- mIsInStableState = true;
-
mQuickQsPanel.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationAtEnd() {
- if (!mIsInStableState) {
- mQsPanel.onExpanded();
- }
- mIsInStableState = true;
-
mQuickQsPanel.setVisibility(View.INVISIBLE);
final int N = mQuickQsViews.size();
for (int i = 0; i < N; i++) {
@@ -365,11 +340,6 @@
@Override
public void onAnimationStarted() {
- if (mIsInStableState) {
- mQsPanel.onAnimating();
- }
- mIsInStableState = false;
-
mQuickQsPanel.setVisibility(mOnKeyguard ? View.INVISIBLE : View.VISIBLE);
if (mOnFirstPage) {
final int N = mQuickQsViews.size();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 5640be5..f7c388d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -18,7 +18,6 @@
import static com.android.systemui.qs.tileimpl.QSTileImpl.getColorForState;
-import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
@@ -59,7 +58,6 @@
public class QSPanel extends LinearLayout implements Tunable, Callback, BrightnessMirrorListener {
public static final String QS_SHOW_BRIGHTNESS = "qs_show_brightness";
- public static final String QS_SHOW_LONG_PRESS_TOOLTIP = "qs_show_long_press";
protected final Context mContext;
protected final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
@@ -74,7 +72,6 @@
private BrightnessController mBrightnessController;
protected QSTileHost mHost;
- protected QSTooltipView mTooltipView;
protected QSSecurityFooter mFooter;
private boolean mGridContentVisible = true;
@@ -97,9 +94,6 @@
setOrientation(VERTICAL);
- mTooltipView = (QSTooltipView) LayoutInflater.from(mContext)
- .inflate(R.layout.quick_settings_header, this, false);
-
mBrightnessView = LayoutInflater.from(mContext).inflate(
R.layout.quick_settings_brightness_dialog, this, false);
mTileLayout = new TileLayout(mContext);
@@ -107,12 +101,7 @@
Space space = new Space(mContext);
space.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
mContext.getResources().getDimensionPixelSize(R.dimen.qs_footer_height)));
- mScrollLayout = new QSScrollLayout(
- mContext,
- mTooltipView,
- mBrightnessView,
- (View) mTileLayout,
- space);
+ mScrollLayout = new QSScrollLayout(mContext, mBrightnessView, (View) mTileLayout, space);
addView(mScrollLayout);
addDivider();
@@ -145,10 +134,7 @@
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- final TunerService tunerService = Dependency.get(TunerService.class);
- tunerService.addTunable(this, QS_SHOW_BRIGHTNESS);
- tunerService.addTunable(this, QS_SHOW_LONG_PRESS_TOOLTIP);
-
+ Dependency.get(TunerService.class).addTunable(this, QS_SHOW_BRIGHTNESS);
if (mHost != null) {
setTiles(mHost.getTiles());
}
@@ -180,16 +166,11 @@
@Override
public void onTuningChanged(String key, String newValue) {
if (QS_SHOW_BRIGHTNESS.equals(key)) {
- updateViewVisibilityForTuningValue(mBrightnessView, newValue);
- } else if (QS_SHOW_LONG_PRESS_TOOLTIP.equals(key)) {
- updateViewVisibilityForTuningValue(mTooltipView, newValue);
+ mBrightnessView.setVisibility(newValue == null || Integer.parseInt(newValue) != 0
+ ? VISIBLE : GONE);
}
}
- private void updateViewVisibilityForTuningValue(View view, @Nullable String newValue) {
- view.setVisibility(newValue == null || Integer.parseInt(newValue) != 0 ? VISIBLE : GONE);
- }
-
public void openDetails(String subPanel) {
QSTile tile = getTile(subPanel);
showDetailAdapter(true, tile.getDetailAdapter(), new int[]{getWidth() / 2, 0});
@@ -224,10 +205,6 @@
return mBrightnessView;
}
- View getHeaderView() {
- return mTooltipView;
- }
-
public void setCallback(QSDetail.Callback callback) {
mCallback = callback;
}
@@ -289,27 +266,11 @@
if (mCustomizePanel != null && mCustomizePanel.isShown()) {
mCustomizePanel.hide(mCustomizePanel.getWidth() / 2, mCustomizePanel.getHeight() / 2);
}
-
- // Instantly hide the header here since we don't want it to still be animating.
- mTooltipView.setVisibility(View.INVISIBLE);
- }
-
- /**
- * Called when the panel is fully animated out/expanded. This is different from the state
- * tracked by {@link #mExpanded}, which only checks if the panel is even partially pulled out.
- */
- public void onExpanded() {
- mTooltipView.fadeIn();
- }
-
- public void onAnimating() {
- mTooltipView.fadeOut();
}
public void setExpanded(boolean expanded) {
if (mExpanded == expanded) return;
mExpanded = expanded;
-
if (!mExpanded) {
if (mTileLayout instanceof PagedTileLayout) {
((PagedTileLayout) mTileLayout).setCurrentItem(0, false);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTooltipView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTooltipView.java
deleted file mode 100644
index d1f9741..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTooltipView.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2018 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.systemui.qs;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.content.Context;
-import android.os.Handler;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.LinearLayout;
-
-import com.android.systemui.Prefs;
-
-import java.util.concurrent.TimeUnit;
-
-
-/**
- * Tooltip/header view for the Quick Settings panel.
- */
-public class QSTooltipView extends LinearLayout {
-
- private static final int FADE_ANIMATION_DURATION_MS = 300;
- private static final long AUTO_FADE_OUT_DELAY_MS = TimeUnit.SECONDS.toMillis(6);
- private static final int TOOLTIP_NOT_YET_SHOWN_COUNT = 0;
- public static final int MAX_TOOLTIP_SHOWN_COUNT = 3;
-
- private final Handler mHandler = new Handler();
- private final Runnable mAutoFadeOutRunnable = () -> fadeOut();
-
- private int mShownCount;
-
- public QSTooltipView(Context context) {
- this(context, null);
- }
-
- public QSTooltipView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mShownCount = getStoredShownCount();
- }
-
- /** Returns the latest stored tooltip shown count from SharedPreferences. */
- private int getStoredShownCount() {
- return Prefs.getInt(
- mContext,
- Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT,
- TOOLTIP_NOT_YET_SHOWN_COUNT);
- }
-
- /**
- * Fades in the header view if we can show the tooltip - short circuits any running animation.
- */
- public void fadeIn() {
- if (mShownCount < MAX_TOOLTIP_SHOWN_COUNT) {
- animate().cancel();
- setVisibility(View.VISIBLE);
- animate()
- .alpha(1f)
- .setDuration(FADE_ANIMATION_DURATION_MS)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mHandler.postDelayed(mAutoFadeOutRunnable, AUTO_FADE_OUT_DELAY_MS);
- }
- })
- .start();
-
- // Increment and drop the shown count in prefs for the next time we're deciding to
- // fade in the tooltip. We first sanity check that the tooltip count hasn't changed yet
- // in prefs (say, from a long press).
- if (getStoredShownCount() <= mShownCount) {
- Prefs.putInt(mContext, Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT, ++mShownCount);
- }
- }
- }
-
- /**
- * Fades out the header view if it's partially visible - short circuits any running animation.
- */
- public void fadeOut() {
- animate().cancel();
- if (getVisibility() == View.VISIBLE && getAlpha() != 0f) {
- mHandler.removeCallbacks(mAutoFadeOutRunnable);
- animate()
- .alpha(0f)
- .setDuration(FADE_ANIMATION_DURATION_MS)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- perhapsMakeViewInvisible();
- }
- })
- .start();
- } else {
- perhapsMakeViewInvisible();
- }
- }
-
- /**
- * Only update visibility if the view is currently being shown. Otherwise, it's already been
- * hidden by some other manner.
- */
- private void perhapsMakeViewInvisible() {
- if (getVisibility() == View.VISIBLE) {
- setVisibility(View.INVISIBLE);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 1b4b7df..8314855 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -124,8 +124,9 @@
@Override
public void onTuningChanged(String key, String newValue) {
- if (QS_SHOW_BRIGHTNESS.equals(key) || QS_SHOW_LONG_PRESS_TOOLTIP.equals(key)) {
- // No Brightness or Tooltip for you!
+ // No tunings for you.
+ if (key.equals(QS_SHOW_BRIGHTNESS)) {
+ // No Brightness for you.
super.onTuningChanged(key, "0");
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 9fa7beb..65135ab 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -99,11 +99,7 @@
record.tileView.measure(exactly(mCellWidth), exactly(mCellHeight));
previousView = record.tileView.updateAccessibilityOrder(previousView);
}
-
- // Only include the top margin in our measurement if we have more than 1 row to show.
- // Otherwise, don't add the extra margin buffer at top.
- int height = (mCellHeight + mCellMargin) * rows +
- rows != 0 ? (mCellMarginTop - mCellMargin) : 0;
+ int height = (mCellHeight + mCellMargin) * rows + (mCellMarginTop - mCellMargin);
if (height < 0) height = 0;
setMeasuredDimension(width, height);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
index 6263efa..37f2528 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
@@ -107,7 +107,7 @@
void onAnimationAtStart();
/**
- * Called when the animator moves into a position of "1". Start and end delays are
+ * Called when the animator moves into a position of "0". Start and end delays are
* taken into account, so this position may cover a range of fractional inputs.
*/
void onAnimationAtEnd();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 016cbd6..72592829 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -42,7 +42,6 @@
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
-import com.android.systemui.Prefs;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSIconView;
@@ -50,7 +49,6 @@
import com.android.systemui.plugins.qs.QSTile.State;
import com.android.systemui.qs.PagedTileLayout.TilePage;
import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.QSTooltipView;
import java.util.ArrayList;
@@ -193,11 +191,6 @@
public void longClick() {
mMetricsLogger.write(populate(new LogMaker(ACTION_QS_LONG_PRESS).setType(TYPE_ACTION)));
mHandler.sendEmptyMessage(H.LONG_CLICK);
-
- Prefs.putInt(
- mContext,
- Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT,
- QSTooltipView.MAX_TOOLTIP_SHOWN_COUNT);
}
public LogMaker populate(LogMaker logMaker) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 7fe9e35..2a9a381 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -78,6 +78,7 @@
@Override
public void handleSetListening(boolean listening) {
+ if (mController == null) return;
if (listening) {
mController.addCallback(mCallback);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 6205e9a..2d31669 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -240,6 +240,7 @@
public void handleSetListening(boolean listening) {
if (mListening == listening) return;
mListening = listening;
+ if (mController == null) return;
if (mListening) {
mController.addCallback(mZenCallback);
Prefs.registerListener(mContext, mPrefListener);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
index b3ff4e5b..12daff1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
@@ -98,6 +98,8 @@
protected void handleUpdateState(BooleanState state, Object arg) {
final Drawable mEnable = mContext.getDrawable(R.drawable.ic_qs_nfc_enabled);
final Drawable mDisable = mContext.getDrawable(R.drawable.ic_qs_nfc_disabled);
+
+ if (getAdapter() == null) return;
state.value = getAdapter().isEnabled();
state.label = mContext.getString(R.string.quick_settings_nfc_label);
state.icon = new DrawableIcon(state.value ? mEnable : mDisable);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index b7a1500..22e8909 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -300,34 +300,10 @@
} else if (mPowerPluggedIn) {
String indication = computePowerIndication();
if (animate) {
- int yTranslation = mContext.getResources().getInteger(
- R.integer.wired_charging_aod_text_animation_distance);
- int animateUpDuration = mContext.getResources().getInteger(
- R.integer.wired_charging_aod_text_animation_duration_up);
- int animateDownDuration = mContext.getResources().getInteger(
- R.integer.wired_charging_aod_text_animation_duration_down);
- mTextView.animate()
- .translationYBy(yTranslation)
- .setInterpolator(Interpolators.LINEAR)
- .setDuration(animateUpDuration)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mTextView.switchIndication(indication);
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- mTextView.animate()
- .setDuration(animateDownDuration)
- .setInterpolator(Interpolators.BOUNCE)
- .translationYBy(-1 * yTranslation)
- .setListener(null);
- }
- });
+ animateText(mTextView, indication);
} else {
mTextView.switchIndication(indication);
}
-
} else {
String percentage = NumberFormat.getPercentInstance()
.format(mBatteryLevel / 100f);
@@ -355,8 +331,12 @@
if (DEBUG_CHARGING_SPEED) {
indication += ", " + (mChargingWattage / 1000) + " mW";
}
- mTextView.switchIndication(indication);
mTextView.setTextColor(mInitialTextColor);
+ if (animate) {
+ animateText(mTextView, indication);
+ } else {
+ mTextView.switchIndication(indication);
+ }
} else if (!TextUtils.isEmpty(trustManagedIndication)
&& updateMonitor.getUserTrustIsManaged(userId)
&& !updateMonitor.getUserHasTrust(userId)) {
@@ -369,6 +349,34 @@
}
}
+ // animates textView - textView moves up and bounces down
+ private void animateText(KeyguardIndicationTextView textView, String indication) {
+ int yTranslation = mContext.getResources().getInteger(
+ R.integer.wired_charging_keyguard_text_animation_distance);
+ int animateUpDuration = mContext.getResources().getInteger(
+ R.integer.wired_charging_keyguard_text_animation_duration_up);
+ int animateDownDuration = mContext.getResources().getInteger(
+ R.integer.wired_charging_keyguard_text_animation_duration_down);
+ textView.animate()
+ .translationYBy(yTranslation)
+ .setInterpolator(Interpolators.LINEAR)
+ .setDuration(animateUpDuration)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ textView.switchIndication(indication);
+ }
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ textView.animate()
+ .setDuration(animateDownDuration)
+ .setInterpolator(Interpolators.BOUNCE)
+ .translationYBy(-1 * yTranslation)
+ .setListener(null);
+ }
+ });
+ }
+
private String computePowerIndication() {
if (mPowerCharged) {
return mContext.getResources().getString(R.string.keyguard_charged);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 0dea6b8..c047670 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -403,14 +403,18 @@
}
private void updateIcons(Context ctx, Configuration oldConfig, Configuration newConfig) {
+ final boolean quickStepEnabled = isQuickStepSwipeUpEnabled() || isQuickScrubEnabled();
if (oldConfig.orientation != newConfig.orientation
|| oldConfig.densityDpi != newConfig.densityDpi) {
mDockedIcon = getDrawable(ctx,
R.drawable.ic_sysbar_docked, R.drawable.ic_sysbar_docked_dark);
+ mHomeDefaultIcon = quickStepEnabled
+ ? getDrawable(ctx, R.drawable.ic_sysbar_home_quick_step,
+ R.drawable.ic_sysbar_home_quick_step_dark)
+ : getDrawable(ctx, R.drawable.ic_sysbar_home, R.drawable.ic_sysbar_home_dark);
}
if (oldConfig.densityDpi != newConfig.densityDpi
|| oldConfig.getLayoutDirection() != newConfig.getLayoutDirection()) {
- final boolean quickStepEnabled = isQuickStepSwipeUpEnabled() || isQuickScrubEnabled();
mBackIcon = quickStepEnabled
? getDrawable(ctx, R.drawable.ic_sysbar_back_quick_step,
R.drawable.ic_sysbar_back_quick_step_dark)
@@ -422,11 +426,6 @@
: getDrawable(ctx, R.drawable.ic_sysbar_back_ime,
R.drawable.ic_sysbar_back_ime_dark);
mBackAltLandIcon = mBackAltIcon;
-
- mHomeDefaultIcon = quickStepEnabled
- ? getDrawable(ctx, R.drawable.ic_sysbar_home_quick_step,
- R.drawable.ic_sysbar_home_quick_step_dark)
- : getDrawable(ctx, R.drawable.ic_sysbar_home, R.drawable.ic_sysbar_home_dark);
mRecentIcon = getDrawable(ctx,
R.drawable.ic_sysbar_recent, R.drawable.ic_sysbar_recent_dark);
mMenuIcon = getDrawable(ctx, R.drawable.ic_sysbar_menu, R.drawable.ic_sysbar_menu_dark);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
index 0bf01b0..378858a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
@@ -224,6 +224,10 @@
case MotionEvent.ACTION_DOWN: {
int x = (int) event.getX();
int y = (int) event.getY();
+ // End any existing quickscrub animations before starting the new transition
+ if (mQuickScrubEndAnimator != null) {
+ mQuickScrubEndAnimator.end();
+ }
mHomeButtonView = homeButton.getCurrentView();
if (mNavigationBarView.isQuickScrubEnabled()
&& mNavigationBarView.getDownHitTarget() == HIT_TARGET_HOME) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 6764634..1c9c794 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -37,7 +37,6 @@
import android.content.Intent;
import android.metrics.LogMaker;
import android.support.test.filters.SmallTest;
-import android.support.test.InstrumentationRegistry;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
@@ -74,7 +73,6 @@
mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
mHost = mock(QSTileHost.class);
when(mHost.indexOf(spec)).thenReturn(POSITION);
- when(mHost.getContext()).thenReturn(mContext.getBaseContext());
mTile = spy(new TileImpl(mHost));
mTile.mHandler = mTile.new H(mTestableLooper.getLooper());
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 320c37f..abf1de5 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5257,6 +5257,23 @@
// OS: P
FIELD_END_BATTERY_PERCENT = 1308;
+ // ACTION: Settings > Display > Night Light
+ // SUBTYPE: com.android.server.display.ColorDisplayService.AutoMode value
+ // CATEGORY: SETTINGS
+ // OS: P
+ ACTION_NIGHT_DISPLAY_AUTO_MODE_CHANGED = 1309;
+
+ // ACTION: Settings > Display > Night Light
+ // CATEGORY: SETTINGS
+ // SUBTYPE: 0 is starting time, 1 is ending time
+ // OS: P
+ ACTION_NIGHT_DISPLAY_AUTO_MODE_CUSTOM_TIME_CHANGED = 1310;
+
+ // FIELD: Current mode corresponding to a QS tile
+ // CATEGORY: QUICK SETTINGS
+ // OS: P
+ FIELD_QS_MODE = 1311;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/rs/OWNERS b/rs/OWNERS
new file mode 100644
index 0000000..61853d3
--- /dev/null
+++ b/rs/OWNERS
@@ -0,0 +1,5 @@
+butlermichael@google.com
+dgross@google.com
+jeanluc@google.com
+miaowang@google.com
+yangni@google.com
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 4b3abea..3689536 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -514,7 +514,7 @@
*/
@GuardedBy("mLock")
private void updateCachedServiceLocked(int userId, boolean disabled) {
- AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
if (service != null) {
service.destroySessionsLocked();
service.updateLocked(disabled);
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index c023efb..c504465 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -153,8 +153,8 @@
mWindow = null;
return;
}
- content.setFocusable(true);
- content.setOnClickListener(v -> mCallback.onResponsePicked(response));
+ decor.setFocusable(true);
+ decor.setOnClickListener(v -> mCallback.onResponsePicked(response));
Point maxSize = mTempPoint;
resolveMaxWindowSize(context, maxSize);
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 1a0068d..7c109d5 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -16,6 +16,15 @@
package com.android.server;
+import static android.os.storage.OnObbStateChangeListener.ERROR_ALREADY_MOUNTED;
+import static android.os.storage.OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT;
+import static android.os.storage.OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT;
+import static android.os.storage.OnObbStateChangeListener.ERROR_INTERNAL;
+import static android.os.storage.OnObbStateChangeListener.ERROR_NOT_MOUNTED;
+import static android.os.storage.OnObbStateChangeListener.ERROR_PERMISSION_DENIED;
+import static android.os.storage.OnObbStateChangeListener.MOUNTED;
+import static android.os.storage.OnObbStateChangeListener.UNMOUNTED;
+
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
import static com.android.internal.util.XmlUtils.readIntAttribute;
import static com.android.internal.util.XmlUtils.readLongAttribute;
@@ -60,7 +69,6 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
-import android.os.IProgressListener;
import android.os.IStoraged;
import android.os.IVold;
import android.os.IVoldListener;
@@ -87,7 +95,6 @@
import android.os.storage.OnObbStateChangeListener;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
-import android.os.storage.StorageResultCode;
import android.os.storage.StorageVolume;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
@@ -137,8 +144,7 @@
import java.io.PrintWriter;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
-import java.security.NoSuchAlgorithmException;
-import java.security.spec.InvalidKeySpecException;
+import java.security.GeneralSecurityException;
import java.security.spec.KeySpec;
import java.util.ArrayList;
import java.util.Arrays;
@@ -3032,8 +3038,8 @@
// If this is the only one pending we might
// have to bind to the service again.
if (!connectToService()) {
- Slog.e(TAG, "Failed to bind to media container service");
- action.handleError();
+ action.notifyObbStateChange(new ObbException(ERROR_INTERNAL,
+ "Failed to bind to media container service"));
return;
}
}
@@ -3049,10 +3055,10 @@
}
if (mContainerService == null) {
// Something seriously wrong. Bail out
- Slog.e(TAG, "Cannot bind to media container service");
for (ObbAction action : mActions) {
// Indicate service bind error
- action.handleError();
+ action.notifyObbStateChange(new ObbException(ERROR_INTERNAL,
+ "Failed to bind to media container service"));
}
mActions.clear();
} else if (mActions.size() > 0) {
@@ -3074,10 +3080,10 @@
disconnectService();
}
if (!connectToService()) {
- Slog.e(TAG, "Failed to bind to media container service");
for (ObbAction action : mActions) {
// Indicate service bind error
- action.handleError();
+ action.notifyObbStateChange(new ObbException(ERROR_INTERNAL,
+ "Failed to bind to media container service"));
}
mActions.clear();
}
@@ -3167,6 +3173,20 @@
}
}
+ private static class ObbException extends Exception {
+ public final int status;
+
+ public ObbException(int status, String message) {
+ super(message);
+ this.status = status;
+ }
+
+ public ObbException(int status, Throwable cause) {
+ super(cause.getMessage(), cause);
+ this.status = status;
+ }
+ }
+
abstract class ObbAction {
private static final int MAX_RETRIES = 3;
private int mRetries;
@@ -3183,46 +3203,44 @@
Slog.i(TAG, "Starting to execute action: " + toString());
mRetries++;
if (mRetries > MAX_RETRIES) {
- Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
- handleError();
+ notifyObbStateChange(new ObbException(ERROR_INTERNAL,
+ "Failed to bind to media container service"));
} else {
handleExecute();
if (DEBUG_OBB)
Slog.i(TAG, "Posting install MCS_UNBIND");
mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
}
- } catch (RemoteException e) {
- if (DEBUG_OBB)
- Slog.i(TAG, "Posting install MCS_RECONNECT");
- mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
- } catch (Exception e) {
- if (DEBUG_OBB)
- Slog.d(TAG, "Error handling OBB action", e);
- handleError();
+ } catch (ObbException e) {
+ notifyObbStateChange(e);
mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
}
}
- abstract void handleExecute() throws RemoteException, IOException;
- abstract void handleError();
+ abstract void handleExecute() throws ObbException;
- protected ObbInfo getObbInfo() throws IOException {
- ObbInfo obbInfo;
+ protected ObbInfo getObbInfo() throws ObbException {
+ final ObbInfo obbInfo;
try {
obbInfo = mContainerService.getObbInfo(mObbState.canonicalPath);
- } catch (RemoteException e) {
- Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
- + mObbState.canonicalPath);
- obbInfo = null;
+ } catch (Exception e) {
+ throw new ObbException(ERROR_PERMISSION_DENIED, e);
}
- if (obbInfo == null) {
- throw new IOException("Couldn't read OBB file: " + mObbState.canonicalPath);
+ if (obbInfo != null) {
+ return obbInfo;
+ } else {
+ throw new ObbException(ERROR_INTERNAL,
+ "Missing OBB info for: " + mObbState.canonicalPath);
}
- return obbInfo;
}
- protected void sendNewStatusOrIgnore(int status) {
+ protected void notifyObbStateChange(ObbException e) {
+ Slog.w(TAG, e);
+ notifyObbStateChange(e.status);
+ }
+
+ protected void notifyObbStateChange(int status) {
if (mObbState == null || mObbState.token == null) {
return;
}
@@ -3246,16 +3264,14 @@
}
@Override
- public void handleExecute() throws IOException, RemoteException {
+ public void handleExecute() throws ObbException {
warnOnNotMounted();
final ObbInfo obbInfo = getObbInfo();
if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) {
- Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
- + " which is owned by " + obbInfo.packageName);
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
- return;
+ throw new ObbException(ERROR_PERMISSION_DENIED, "Denied attempt to mount OBB "
+ + obbInfo.filename + " which is owned by " + obbInfo.packageName);
}
final boolean isMounted;
@@ -3263,9 +3279,8 @@
isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath);
}
if (isMounted) {
- Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
- return;
+ throw new ObbException(ERROR_ALREADY_MOUNTED,
+ "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
}
final String hashedKey;
@@ -3283,28 +3298,16 @@
BigInteger bi = new BigInteger(key.getEncoded());
hashedKey = bi.toString(16);
binderKey = hashedKey;
- } catch (NoSuchAlgorithmException e) {
- Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
- return;
- } catch (InvalidKeySpecException e) {
- Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
- return;
+ } catch (GeneralSecurityException e) {
+ throw new ObbException(ERROR_INTERNAL, e);
}
}
- int rc = StorageResultCode.OperationSucceeded;
try {
mObbState.volId = mVold.createObb(mObbState.canonicalPath, binderKey,
mObbState.ownerGid);
mVold.mount(mObbState.volId, 0, -1);
- } catch (Exception e) {
- Slog.w(TAG, e);
- rc = StorageResultCode.OperationFailedInternalError;
- }
- if (rc == StorageResultCode.OperationSucceeded) {
if (DEBUG_OBB)
Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath);
@@ -3312,20 +3315,13 @@
addObbStateLocked(mObbState);
}
- sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
- } else {
- Slog.e(TAG, "Couldn't mount OBB file: " + rc);
-
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
+ notifyObbStateChange(MOUNTED);
+ } catch (Exception e) {
+ throw new ObbException(ERROR_COULD_NOT_MOUNT, e);
}
}
@Override
- public void handleError() {
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
- }
-
- @Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("MountObbAction{");
@@ -3344,7 +3340,7 @@
}
@Override
- public void handleExecute() throws IOException {
+ public void handleExecute() throws ObbException {
warnOnNotMounted();
final ObbState existingState;
@@ -3353,45 +3349,32 @@
}
if (existingState == null) {
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
- return;
+ throw new ObbException(ERROR_NOT_MOUNTED, "Missing existingState");
}
if (existingState.ownerGid != mObbState.ownerGid) {
- Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath
- + " (owned by GID " + existingState.ownerGid + ")");
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
+ notifyObbStateChange(new ObbException(ERROR_PERMISSION_DENIED,
+ "Permission denied to unmount OBB " + existingState.rawPath
+ + " (owned by GID " + existingState.ownerGid + ")"));
return;
}
- int rc = StorageResultCode.OperationSucceeded;
try {
mVold.unmount(mObbState.volId);
mVold.destroyObb(mObbState.volId);
mObbState.volId = null;
- } catch (Exception e) {
- Slog.w(TAG, e);
- rc = StorageResultCode.OperationFailedInternalError;
- }
- if (rc == StorageResultCode.OperationSucceeded) {
synchronized (mObbMounts) {
removeObbStateLocked(existingState);
}
- sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
- } else {
- Slog.w(TAG, "Could not unmount OBB: " + existingState);
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
+ notifyObbStateChange(UNMOUNTED);
+ } catch (Exception e) {
+ throw new ObbException(ERROR_COULD_NOT_UNMOUNT, e);
}
}
@Override
- public void handleError() {
- sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
- }
-
- @Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("UnmountObbAction{");
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 5c30764..f4f60c2 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -4516,7 +4516,7 @@
int startActivityFromRecents(int callingPid, int callingUid, int taskId,
SafeActivityOptions options) {
- final TaskRecord task;
+ TaskRecord task = null;
final String callingPackage;
final Intent intent;
final int userId;
@@ -4579,13 +4579,6 @@
targetActivity);
}
- // If we are launching the task in the docked stack, put it into resizing mode so
- // the window renders full-screen with the background filling the void. Also only
- // call this at the end to make sure that tasks exists on the window manager side.
- if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- setResizingDuringAnimation(task);
- }
-
mService.getActivityStartController().postStartActivityProcessingForLastStarter(
task.getTopActivity(), ActivityManager.START_TASK_TO_FRONT,
task.getStack());
@@ -4595,15 +4588,28 @@
intent = task.intent;
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
userId = task.userId;
- int result = mService.getActivityStartController().startActivityInPackage(
+ return mService.getActivityStartController().startActivityInPackage(
task.mCallingUid, callingPid, callingUid, callingPackage, intent, null, null,
- null, 0, 0, options, userId, task,
- "startActivityFromRecents");
- if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- setResizingDuringAnimation(task);
- }
- return result;
+ null, 0, 0, options, userId, task, "startActivityFromRecents");
} finally {
+ if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && task != null) {
+ // If we are launching the task in the docked stack, put it into resizing mode so
+ // the window renders full-screen with the background filling the void. Also only
+ // call this at the end to make sure that tasks exists on the window manager side.
+ setResizingDuringAnimation(task);
+
+ final ActivityDisplay display = task.getStack().getDisplay();
+ final ActivityStack topSecondaryStack =
+ display.getTopStackInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ if (topSecondaryStack.isActivityTypeHome()) {
+ // If the home activity if the top split-screen secondary stack, then the
+ // primary split-screen stack is in the minimized mode which means it can't
+ // receive input keys, so we should move the focused app to the home app so that
+ // window manager can correctly calculate the focus window that can receive
+ // input keys.
+ moveHomeStackToFront("startActivityFromRecents: homeVisibleInSplitScreen");
+ }
+ }
mWindowManager.continueSurfaceLayout();
}
}
diff --git a/services/core/java/com/android/server/audio/OWNERS b/services/core/java/com/android/server/audio/OWNERS
new file mode 100644
index 0000000..b70de29
--- /dev/null
+++ b/services/core/java/com/android/server/audio/OWNERS
@@ -0,0 +1,2 @@
+jmtrivi@google.com
+elaurent@google.com
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index d87a1bb..79450a0 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -2078,8 +2078,33 @@
protected void dumpSyncState(PrintWriter pw) {
final StringBuilder sb = new StringBuilder();
- pw.print("data connected: "); pw.println(mDataConnectionIsConnected);
- pw.print("auto sync: ");
+ pw.print("Data connected: "); pw.println(mDataConnectionIsConnected);
+ pw.print("Battery saver: ");
+ pw.println((mPowerManager != null) && mPowerManager.isPowerSaveMode());
+
+ pw.print("Background network restriction: ");
+ {
+ final ConnectivityManager cm = getConnectivityManager();
+ final int status = (cm == null) ? -1 : cm.getRestrictBackgroundStatus();
+ switch (status) {
+ case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED:
+ pw.println(" disabled");
+ break;
+ case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED:
+ pw.println(" whitelisted");
+ break;
+ case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED:
+ pw.println(" enabled");
+ break;
+ default:
+ pw.print("Unknown(");
+ pw.print(status);
+ pw.println(")");
+ break;
+ }
+ }
+
+ pw.print("Auto sync: ");
List<UserInfo> users = getAllUsers();
if (users != null) {
for (UserInfo user : users) {
@@ -2088,26 +2113,26 @@
}
pw.println();
}
- pw.print("memory low: "); pw.println(mStorageIsLow);
- pw.print("device idle: "); pw.println(mDeviceIsIdle);
- pw.print("reported active: "); pw.println(mReportedSyncActive);
+ pw.print("Memory low: "); pw.println(mStorageIsLow);
+ pw.print("Device idle: "); pw.println(mDeviceIsIdle);
+ pw.print("Reported active: "); pw.println(mReportedSyncActive);
final AccountAndUser[] accounts = AccountManagerService.getSingleton().getAllAccounts();
- pw.print("accounts: ");
+ pw.print("Accounts: ");
if (accounts != INITIAL_ACCOUNTS_ARRAY) {
pw.println(accounts.length);
} else {
pw.println("not known yet");
}
final long now = SystemClock.elapsedRealtime();
- pw.print("now: "); pw.print(now);
+ pw.print("Now: "); pw.print(now);
pw.println(" (" + formatTime(System.currentTimeMillis()) + ")");
sb.setLength(0);
- pw.print("uptime: "); pw.print(formatDurationHMS(sb, now));
+ pw.print("Uptime: "); pw.print(formatDurationHMS(sb, now));
pw.println();
- pw.print("time spent syncing: ");
+ pw.print("Time spent syncing: ");
sb.setLength(0);
pw.print(formatDurationHMS(sb,
diff --git a/services/core/java/com/android/server/content/SyncManagerConstants.java b/services/core/java/com/android/server/content/SyncManagerConstants.java
index 3139d54..061e4ca 100644
--- a/services/core/java/com/android/server/content/SyncManagerConstants.java
+++ b/services/core/java/com/android/server/content/SyncManagerConstants.java
@@ -55,7 +55,6 @@
protected SyncManagerConstants(Context context) {
super(null);
mContext = context;
- refresh();
}
public void start() {
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 3da3551..692535c 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -421,7 +421,7 @@
byteToken[i] = token.get(i);
}
// Send to Keystore
- KeyStore.getInstance().addAuthToken(byteToken);
+ KeyStore.getInstance().addAuthToken(byteToken, mCurrentUserId);
}
if (client != null && client.onAuthenticated(fingerId, groupId)) {
removeClient(client);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
old mode 100644
new mode 100755
index e5f4282..0cba76b
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -660,7 +660,8 @@
@ServiceThreadOnly
void startQueuedActions() {
assertRunOnServiceThread();
- for (HdmiCecFeatureAction action : mActions) {
+ // Use copied action list in that start() may remove itself.
+ for (HdmiCecFeatureAction action : new ArrayList<>(mActions)) {
if (!action.started()) {
Slog.i(TAG, "Starting queued action:" + action);
action.start();
diff --git a/services/core/java/com/android/server/media/OWNERS b/services/core/java/com/android/server/media/OWNERS
new file mode 100644
index 0000000..6f8d823
--- /dev/null
+++ b/services/core/java/com/android/server/media/OWNERS
@@ -0,0 +1,2 @@
+lajos@google.com
+elaurent@google.com
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 884606d2..c47381a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -553,9 +553,9 @@
public static final String PLATFORM_PACKAGE_NAME = "android";
- static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
+ public static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
- static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
+ public static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
DEFAULT_CONTAINER_PACKAGE,
"com.android.defcontainer.DefaultContainerService");
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 6308766..c5cfb8e 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -16,7 +16,7 @@
package com.android.server.pm.permission;
-import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
+import static android.os.Process.FIRST_APPLICATION_UID;
import android.Manifest;
import android.annotation.NonNull;
@@ -28,15 +28,14 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageList;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.PackageManagerInternal.PackagesProvider;
+import android.content.pm.PackageManagerInternal.SyncAdapterPackagesProvider;
import android.content.pm.PackageParser;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
-import android.content.pm.PackageManagerInternal.PackagesProvider;
-import android.content.pm.PackageManagerInternal.SyncAdapterPackagesProvider;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Binder;
@@ -52,15 +51,17 @@
import android.provider.ContactsContract;
import android.provider.MediaStore;
import android.provider.Telephony.Sms.Intents;
-import android.telephony.TelephonyManager;
import android.security.Credentials;
+import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
import android.util.Xml;
+
import com.android.internal.util.XmlUtils;
import com.android.server.LocalServices;
+import com.android.server.pm.PackageManagerService;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -71,14 +72,11 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import static android.os.Process.FIRST_APPLICATION_UID;
-
/**
* This class is the policy for granting runtime permissions to
* platform components and default handlers in the system such
@@ -433,6 +431,13 @@
grantRuntimePermissions(storagePackage, STORAGE_PERMISSIONS, true, userId);
}
+ // Container service
+ PackageParser.Package containerPackage = getSystemPackage(
+ PackageManagerService.DEFAULT_CONTAINER_PACKAGE);
+ if (containerPackage != null) {
+ grantRuntimePermissions(containerPackage, STORAGE_PERMISSIONS, true, userId);
+ }
+
// CertInstaller
Intent certInstallerIntent = new Intent(Credentials.INSTALL_ACTION);
PackageParser.Package certInstallerPackage = getDefaultSystemHandlerActivityPackage(
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index 941cd44..efcadad 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -19,6 +19,8 @@
import android.app.ActivityManager;
import android.content.Context;
import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.security.IKeystoreService;
import android.util.Slog;
import com.android.internal.policy.IKeyguardService;
@@ -51,11 +53,16 @@
private final LockPatternUtils mLockPatternUtils;
private final StateCallback mCallback;
+ IKeystoreService mKeystoreService;
+
public KeyguardStateMonitor(Context context, IKeyguardService service, StateCallback callback) {
mLockPatternUtils = new LockPatternUtils(context);
mCurrentUserId = ActivityManager.getCurrentUser();
mCallback = callback;
+ mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager
+ .getService("android.security.keystore"));
+
try {
service.addStateMonitorCallback(this);
} catch (RemoteException e) {
@@ -86,6 +93,12 @@
@Override // Binder interface
public void onShowingStateChanged(boolean showing) {
mIsShowing = showing;
+
+ if (showing) try {
+ mKeystoreService.lock(mCurrentUserId); // as long as this doesn't recur...
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error locking keystore", e);
+ }
}
@Override // Binder interface
diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
index 3cd3e8b..db95634 100644
--- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java
+++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
@@ -53,7 +53,8 @@
AppWindowThumbnail(Transaction t, AppWindowToken appToken, GraphicBuffer thumbnailHeader) {
mAppToken = appToken;
- mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, appToken.mService);
+ mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished,
+ appToken.mService.mAnimator::addAfterPrepareSurfacesRunnable, appToken.mService);
mWidth = thumbnailHeader.getWidth();
mHeight = thumbnailHeader.getHeight();
@@ -144,6 +145,11 @@
}
@Override
+ public void destroyAfterPendingTransaction(SurfaceControl surface) {
+ mAppToken.destroyAfterPendingTransaction(surface);
+ }
+
+ @Override
public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
t.setLayer(leash, Integer.MAX_VALUE);
}
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index a180a3a..4394a99 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -55,6 +55,11 @@
}
@Override
+ public void destroyAfterPendingTransaction(SurfaceControl surface) {
+ mHost.destroyAfterPendingTransaction(surface);
+ }
+
+ @Override
public SurfaceControl.Builder makeAnimationLeash() {
return mHost.makeAnimationLeash();
}
@@ -114,7 +119,7 @@
if (!mDimming) {
mDimLayer.destroy();
}
- }, mHost.mService);
+ }, mHost.mService.mAnimator::addAfterPrepareSurfacesRunnable, mHost.mService);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2d32c81..d22828d 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -380,6 +380,11 @@
*/
private int mSurfaceSize;
+ /**
+ * A list of surfaces to be destroyed after {@link #mPendingTransaction} is applied.
+ */
+ private final ArrayList<SurfaceControl> mPendingDestroyingSurfaces = new ArrayList<>();
+
/** Temporary float array to retrieve 3x3 matrix values. */
private final float[] mTmpFloats = new float[9];
@@ -1930,6 +1935,10 @@
}
}
mService.mAnimator.removeDisplayLocked(mDisplayId);
+
+ // The pending transaction won't be applied so we should
+ // just clean up any surfaces pending destruction.
+ onPendingTransactionApplied();
} finally {
mRemovingDisplay = false;
}
@@ -3846,6 +3855,22 @@
}
@Override
+ public void destroyAfterPendingTransaction(SurfaceControl surface) {
+ mPendingDestroyingSurfaces.add(surface);
+ }
+
+ /**
+ * Destroys any surfaces that have been put into the pending list with
+ * {@link #destroyAfterPendingTransaction}.
+ */
+ void onPendingTransactionApplied() {
+ for (int i = mPendingDestroyingSurfaces.size() - 1; i >= 0; i--) {
+ mPendingDestroyingSurfaces.get(i).destroy();
+ }
+ mPendingDestroyingSurfaces.clear();
+ }
+
+ @Override
void prepareSurfaces() {
final ScreenRotationAnimation screenRotationAnimation =
mService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
@@ -3859,7 +3884,6 @@
mPendingTransaction.setAlpha(mWindowingLayer,
screenRotationAnimation.getEnterTransformation().getAlpha());
}
-
super.prepareSurfaces();
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index e4edeb87..78dd580 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -219,7 +219,7 @@
private void addAnimation(Task task) {
if (DEBUG) Log.d(TAG, "addAnimation(" + task.getName() + ")");
final SurfaceAnimator anim = new SurfaceAnimator(task, null /* animationFinishedCallback */,
- mService);
+ mService.mAnimator::addAfterPrepareSurfacesRunnable, mService);
final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task);
anim.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */);
task.commitPendingTransaction();
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 2fe55b9..3d60ee4 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -800,6 +800,7 @@
mService.enableScreenIfNeededLocked();
mService.scheduleAnimationLocked();
+ mService.mWindowPlacerLocked.destroyPendingSurfaces();
if (DEBUG_WINDOW_TRACE) Slog.e(TAG,
"performSurfacePlacementInner exit: animating=" + mService.mAnimator.isAnimating());
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 37be149..83baee1 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -33,6 +33,7 @@
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
+import java.util.function.Consumer;
/**
* A class that can run animations on objects that have a set of child surfaces. We do this by
@@ -59,17 +60,21 @@
/**
* @param animatable The object to animate.
* @param animationFinishedCallback Callback to invoke when an animation has finished running.
+ * @param addAfterPrepareSurfaces Consumer that takes a runnable and executes it after preparing
+ * surfaces in WM. Can be implemented differently during testing.
*/
SurfaceAnimator(Animatable animatable, @Nullable Runnable animationFinishedCallback,
- WindowManagerService service) {
+ Consumer<Runnable> addAfterPrepareSurfaces, WindowManagerService service) {
mAnimatable = animatable;
mService = service;
mAnimationFinishedCallback = animationFinishedCallback;
- mInnerAnimationFinishedCallback = getFinishedCallback(animationFinishedCallback);
+ mInnerAnimationFinishedCallback = getFinishedCallback(animationFinishedCallback,
+ addAfterPrepareSurfaces);
}
private OnAnimationFinishedCallback getFinishedCallback(
- @Nullable Runnable animationFinishedCallback) {
+ @Nullable Runnable animationFinishedCallback,
+ Consumer<Runnable> addAfterPrepareSurfaces) {
return anim -> {
synchronized (mService.mWindowMap) {
final SurfaceAnimator target = mService.mAnimationTransferMap.remove(anim);
@@ -78,13 +83,30 @@
return;
}
- if (anim != mAnimation) {
- return;
- }
- reset(mAnimatable.getPendingTransaction(), true /* destroyLeash */);
- if (animationFinishedCallback != null) {
- animationFinishedCallback.run();
- }
+ // TODO: This should use pendingTransaction eventually, but right now things
+ // happening on the animation finished callback are happening on the global
+ // transaction.
+ // For now we need to run this after it's guaranteed that the transaction that
+ // reparents the surface onto the leash is executed already. Otherwise this may be
+ // executed first, leading to surface loss, as the reparent operations wouldn't
+ // be in order.
+ addAfterPrepareSurfaces.accept(() -> {
+ if (anim != mAnimation) {
+ // Callback was from another animation - ignore.
+ return;
+ }
+ final Transaction t = new Transaction();
+ SurfaceControl.openTransaction();
+ try {
+ reset(t, true /* destroyLeash */);
+ if (animationFinishedCallback != null) {
+ animationFinishedCallback.run();
+ }
+ } finally {
+ SurfaceControl.mergeToGlobalTransaction(t);
+ SurfaceControl.closeTransaction();
+ }
+ });
}
};
}
@@ -268,7 +290,7 @@
}
mService.mAnimationTransferMap.remove(mAnimation);
if (mLeash != null && destroyLeash) {
- t.destroy(mLeash);
+ mAnimatable.destroyAfterPendingTransaction(mLeash);
}
mLeash = null;
mAnimation = null;
@@ -357,6 +379,13 @@
void onAnimationLeashDestroyed(Transaction t);
/**
+ * Destroy a given surface after executing {@link #getPendingTransaction}.
+ *
+ * @see WindowContainer#destroyAfterPendingTransaction
+ */
+ void destroyAfterPendingTransaction(SurfaceControl surface);
+
+ /**
* @return A new surface to be used for the animation leash, inserted at the correct
* position in the hierarchy.
*/
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index ab10197..20349b9 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -226,6 +226,13 @@
if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animate");
}
+ final int numDisplays = mDisplayContentsAnimators.size();
+ for (int i = 0; i < numDisplays; i++) {
+ final int displayId = mDisplayContentsAnimators.keyAt(i);
+ final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
+ dc.onPendingTransactionApplied();
+ }
+
boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
boolean doRequest = false;
if (mBulkUpdateParams != 0) {
@@ -259,6 +266,7 @@
}
mService.destroyPreservedSurfaceLocked();
+ mService.mWindowPlacerLocked.destroyPendingSurfaces();
executeAfterPrepareSurfacesRunnables();
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 93e9137..1f7caff 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -109,7 +109,8 @@
WindowContainer(WindowManagerService service) {
mService = service;
mPendingTransaction = service.mTransactionFactory.make();
- mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, service);
+ mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished,
+ service.mAnimator::addAfterPrepareSurfacesRunnable, service);
}
@Override
@@ -285,9 +286,8 @@
}
if (mSurfaceControl != null) {
- getPendingTransaction().destroy(mSurfaceControl);
+ destroyAfterPendingTransaction(mSurfaceControl);
mSurfaceControl = null;
- scheduleAnimation();
}
if (mParent != null) {
@@ -1075,6 +1075,19 @@
return mSurfaceControl;
}
+ /**
+ * Destroy a given surface after executing mPendingTransaction. This is
+ * largely a workaround for destroy not being part of transactions
+ * rather than an intentional design, so please take care when
+ * expanding use.
+ */
+ @Override
+ public void destroyAfterPendingTransaction(SurfaceControl surface) {
+ if (mParent != null) {
+ mParent.destroyAfterPendingTransaction(surface);
+ }
+ }
+
@Override
public Transaction getPendingTransaction() {
return mPendingTransaction;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c1a1452..21b4361 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4067,9 +4067,7 @@
final boolean hasSurface = mWinAnimator.hasSurface();
if (hasSurface) {
- // Use pendingTransaction here so hide is done the same transaction as the other
- // animations when exiting
- mWinAnimator.hide(getPendingTransaction(), "onExitAnimationDone");
+ mWinAnimator.hide("onExitAnimationDone");
}
// If we have an app token, we ask it to destroy the surface for us, so that it can take
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index a699ba0..9621ee5 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -164,8 +164,6 @@
private boolean mAnimationStartDelayed;
- private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
-
/** The pixel format of the underlying SurfaceControl */
int mSurfaceFormat;
@@ -282,21 +280,16 @@
}
}
- void hide(SurfaceControl.Transaction transaction, String reason) {
+ void hide(String reason) {
if (!mLastHidden) {
//dump();
mLastHidden = true;
if (mSurfaceController != null) {
- mSurfaceController.hide(transaction, reason);
+ mSurfaceController.hideInTransaction(reason);
}
}
}
- void hide(String reason) {
- hide(mTmpTransaction, reason);
- SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
- }
-
boolean finishDrawingLocked() {
final boolean startingWindow =
mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index d88e59c..554a600 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -86,8 +86,6 @@
private final int mWindowType;
private final Session mWindowSession;
- private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
-
public WindowSurfaceController(SurfaceSession s, String name, int w, int h, int format,
int flags, WindowStateAnimator animator, int windowType, int ownerUid) {
mAnimator = animator;
@@ -150,23 +148,21 @@
}
}
- void hide(SurfaceControl.Transaction transaction, String reason) {
+ void hideInTransaction(String reason) {
if (SHOW_TRANSACTIONS) logSurface("HIDE ( " + reason + " )", null);
mHiddenForOtherReasons = true;
mAnimator.destroyPreservedSurfaceLocked();
- if (mSurfaceShown) {
- hideSurface(transaction);
- }
+ updateVisibility();
}
- private void hideSurface(SurfaceControl.Transaction transaction) {
+ private void hideSurface() {
if (mSurfaceControl == null) {
return;
}
setShown(false);
try {
- transaction.hide(mSurfaceControl);
+ mSurfaceControl.hide();
} catch (RuntimeException e) {
Slog.w(TAG, "Exception hiding surface in " + this);
}
@@ -425,8 +421,7 @@
private boolean updateVisibility() {
if (mHiddenForCrop || mHiddenForOtherReasons) {
if (mSurfaceShown) {
- hideSurface(mTmpTransaction);
- SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
+ hideSurface();
}
return false;
} else {
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 272f3a5..7364e87 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -102,6 +102,7 @@
}
private final LayerAndToken mTmpLayerAndToken = new LayerAndToken();
+ private final ArrayList<SurfaceControl> mPendingDestroyingSurfaces = new ArrayList<>();
private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
private final Runnable mPerformSurfacePlacement;
@@ -696,6 +697,25 @@
}
}
+ /**
+ * Puts the {@param surface} into a pending list to be destroyed after the current transaction
+ * has been committed.
+ */
+ void destroyAfterTransaction(SurfaceControl surface) {
+ mPendingDestroyingSurfaces.add(surface);
+ }
+
+ /**
+ * Destroys any surfaces that have been put into the pending list with
+ * {@link #destroyAfterTransaction}.
+ */
+ void destroyPendingSurfaces() {
+ for (int i = mPendingDestroyingSurfaces.size() - 1; i >= 0; i--) {
+ mPendingDestroyingSurfaces.get(i).destroy();
+ }
+ mPendingDestroyingSurfaces.clear();
+ }
+
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "mTraversalScheduled=" + mTraversalScheduled);
pw.println(prefix + "mHoldScreenWindow=" + mService.mRoot.mHoldScreenWindow);
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
index 79a9610..b55c79b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -131,6 +131,7 @@
assertNoStartingWindow(controller.getAppWindowToken(mDisplayContent));
controller.getAppWindowToken(mDisplayContent).getParent().getParent().removeImmediately();
+ mDisplayContent.onPendingTransactionApplied();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
index a120eba..64c3037 100644
--- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -23,11 +23,11 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.SurfaceControl;
@@ -39,6 +39,7 @@
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -46,6 +47,7 @@
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
/**
* Test class for {@link SurfaceAnimatorTest}.
@@ -85,7 +87,7 @@
callbackCaptor.getValue().onAnimationFinished(mSpec);
assertNotAnimating(mAnimatable);
assertTrue(mAnimatable.mFinishedCallbackCalled);
- verify(mTransaction).destroy(eq(mAnimatable.mLeash));
+ assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
// TODO: Verify reparenting once we use mPendingTransaction to reparent it back
}
@@ -95,7 +97,7 @@
final SurfaceControl firstLeash = mAnimatable.mLeash;
mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */);
- verify(mTransaction).destroy(eq(firstLeash));
+ assertTrue(mAnimatable.mPendingDestroySurfaces.contains(firstLeash));
assertFalse(mAnimatable.mFinishedCallbackCalled);
final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
@@ -122,7 +124,7 @@
assertNotAnimating(mAnimatable);
verify(mSpec).onAnimationCancelled(any());
assertTrue(mAnimatable.mFinishedCallbackCalled);
- verify(mTransaction).destroy(eq(mAnimatable.mLeash));
+ assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
}
@Test
@@ -143,7 +145,7 @@
verifyZeroInteractions(mSpec);
assertNotAnimating(mAnimatable);
assertTrue(mAnimatable.mFinishedCallbackCalled);
- verify(mTransaction).destroy(eq(mAnimatable.mLeash));
+ assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
}
@Test
@@ -159,11 +161,11 @@
assertNotAnimating(mAnimatable);
assertAnimating(mAnimatable2);
assertEquals(leash, mAnimatable2.mSurfaceAnimator.mLeash);
- verify(mTransaction, never()).destroy(eq(leash));
+ assertFalse(mAnimatable.mPendingDestroySurfaces.contains(leash));
callbackCaptor.getValue().onAnimationFinished(mSpec);
assertNotAnimating(mAnimatable2);
assertTrue(mAnimatable2.mFinishedCallbackCalled);
- verify(mTransaction).destroy(eq(leash));
+ assertTrue(mAnimatable2.mPendingDestroySurfaces.contains(leash));
}
private void assertAnimating(MyAnimatable animatable) {
@@ -180,6 +182,7 @@
final SurfaceControl mParent;
final SurfaceControl mSurface;
+ final ArrayList<SurfaceControl> mPendingDestroySurfaces = new ArrayList<>();
final SurfaceAnimator mSurfaceAnimator;
SurfaceControl mLeash;
boolean mFinishedCallbackCalled;
@@ -195,7 +198,7 @@
.build();
mFinishedCallbackCalled = false;
mLeash = null;
- mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, sWm);
+ mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, Runnable::run, sWm);
}
@Override
@@ -216,6 +219,11 @@
}
@Override
+ public void destroyAfterPendingTransaction(SurfaceControl surface) {
+ mPendingDestroySurfaces.add(surface);
+ }
+
+ @Override
public Builder makeAnimationLeash() {
return new SurfaceControl.Builder(mSession) {
diff --git a/services/usb/OWNERS b/services/usb/OWNERS
new file mode 100644
index 0000000..7897a0c
--- /dev/null
+++ b/services/usb/OWNERS
@@ -0,0 +1,4 @@
+badhri@google.com
+elaurent@google.com
+moltmann@google.com
+zhangjerry@google.com
diff --git a/telecomm/OWNERS b/telecomm/OWNERS
new file mode 100644
index 0000000..a3bcfb2
--- /dev/null
+++ b/telecomm/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+
+tgunn@google.com
+breadley@google.com
+hallliu@google.com
+rgreenwalt@google.com
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 8c18518..0c92c20 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -425,8 +425,14 @@
*/
public static final int PROPERTY_ASSISTED_DIALING_USED = 0x00000200;
+ /**
+ * Indicates that the call is an RTT call. Use {@link #getRttCall()} to get the
+ * {@link RttCall} object that is used to send and receive text.
+ */
+ public static final int PROPERTY_RTT = 0x00000400;
+
//******************************************************************************************
- // Next PROPERTY value: 0x00000400
+ // Next PROPERTY value: 0x00000800
//******************************************************************************************
private final String mTelecomCallId;
@@ -1189,6 +1195,23 @@
return null;
}
}
+
+ /**
+ * Closes the underlying file descriptors
+ * @hide
+ */
+ public void close() {
+ try {
+ mReceiveStream.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ try {
+ mTransmitStream.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
}
/**
@@ -1664,7 +1687,7 @@
* @return true if there is a connection, false otherwise.
*/
public boolean isRttActive() {
- return mRttCall != null;
+ return mRttCall != null && mDetails.hasProperty(Details.PROPERTY_RTT);
}
/**
@@ -1867,7 +1890,8 @@
boolean isRttChanged = false;
boolean rttModeChanged = false;
- if (parcelableCall.getParcelableRttCall() != null && parcelableCall.getIsRttCallChanged()) {
+ if (parcelableCall.getIsRttCallChanged()
+ && mDetails.hasProperty(Details.PROPERTY_RTT)) {
ParcelableRttCall parcelableRttCall = parcelableCall.getParcelableRttCall();
InputStreamReader receiveStream = new InputStreamReader(
new ParcelFileDescriptor.AutoCloseInputStream(
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 3229705..26a2f1c 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -41,6 +41,8 @@
import android.util.ArraySet;
import android.view.Surface;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
@@ -860,18 +862,19 @@
mFdFromInCall = fromInCall;
mFdToInCall = toInCall;
mPipeFromInCall = new InputStreamReader(
- new ParcelFileDescriptor.AutoCloseInputStream(fromInCall));
+ new FileInputStream(fromInCall.getFileDescriptor()));
mPipeToInCall = new OutputStreamWriter(
- new ParcelFileDescriptor.AutoCloseOutputStream(toInCall));
+ new FileOutputStream(toInCall.getFileDescriptor()));
}
/**
* Writes the string {@param input} into the text stream to the UI for this RTT call. Since
* RTT transmits text in real-time, this method should be called as often as text snippets
* are received from the remote user, even if it is only one character.
- *
+ * <p>
* This method is not thread-safe -- calling it from multiple threads simultaneously may
* lead to interleaved text.
+ *
* @param input The message to send to the in-call app.
*/
public void write(String input) throws IOException {
@@ -884,9 +887,10 @@
* Reads a string from the in-call app, blocking if there is no data available. Returns
* {@code null} if the RTT conversation has been terminated and there is no further data
* to read.
- *
+ * <p>
* This method is not thread-safe -- calling it from multiple threads simultaneously may
* lead to interleaved text.
+ *
* @return A string containing text entered by the user, or {@code null} if the
* conversation has been terminated or if there was an error while reading.
*/
@@ -901,6 +905,7 @@
/**
* Non-blocking version of {@link #read()}. Returns {@code null} if there is nothing to
* be read.
+ *
* @return A string containing text entered by the user, or {@code null} if the user has
* not entered any new text yet.
*/
@@ -2635,7 +2640,6 @@
* {@link #onStartRtt(RttTextStream)} has succeeded.
*/
public final void sendRttInitiationSuccess() {
- setRttProperty();
mListeners.forEach((l) -> l.onRttInitiationSuccess(Connection.this));
}
@@ -2647,7 +2651,6 @@
* exception of {@link RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}.
*/
public final void sendRttInitiationFailure(int reason) {
- unsetRttProperty();
mListeners.forEach((l) -> l.onRttInitiationFailure(Connection.this, reason));
}
@@ -2656,7 +2659,6 @@
* side of the coll.
*/
public final void sendRttSessionRemotelyTerminated() {
- unsetRttProperty();
mListeners.forEach((l) -> l.onRttSessionRemotelyTerminated(Connection.this));
}
@@ -2956,22 +2958,6 @@
*/
public void handleRttUpgradeResponse(@Nullable RttTextStream rttTextStream) {}
- /**
- * Internal method to set {@link #PROPERTY_IS_RTT}.
- * @hide
- */
- void setRttProperty() {
- setConnectionProperties(getConnectionProperties() | PROPERTY_IS_RTT);
- }
-
- /**
- * Internal method to un-set {@link #PROPERTY_IS_RTT}.
- * @hide
- */
- void unsetRttProperty() {
- setConnectionProperties(getConnectionProperties() & (~PROPERTY_IS_RTT));
- }
-
static String toLogSafePhoneNumber(String number) {
// For unknown number, log empty string.
if (number == null) {
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index 658b473..b6e6b0e 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -143,6 +143,8 @@
private final boolean mShouldShowIncomingCallUi;
private final ParcelFileDescriptor mRttPipeToInCall;
private final ParcelFileDescriptor mRttPipeFromInCall;
+ // Cached return value of getRttTextStream -- we don't want to wrap it more than once.
+ private Connection.RttTextStream mRttTextStream;
/**
* @param accountHandle The accountHandle which should be used to place the call.
@@ -312,7 +314,10 @@
*/
public Connection.RttTextStream getRttTextStream() {
if (isRequestingRtt()) {
- return new Connection.RttTextStream(mRttPipeToInCall, mRttPipeFromInCall);
+ if (mRttTextStream == null) {
+ mRttTextStream = new Connection.RttTextStream(mRttPipeToInCall, mRttPipeFromInCall);
+ }
+ return mRttTextStream;
} else {
return null;
}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 1547857..ffa0c94 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -143,6 +143,7 @@
private static final String SESSION_HANDOVER_COMPLETE = "CS.hC";
private static final String SESSION_EXTRAS_CHANGED = "CS.oEC";
private static final String SESSION_START_RTT = "CS.+RTT";
+ private static final String SESSION_UPDATE_RTT_PIPES = "CS.uRTT";
private static final String SESSION_STOP_RTT = "CS.-RTT";
private static final String SESSION_RTT_UPGRADE_RESPONSE = "CS.rTRUR";
private static final String SESSION_CONNECTION_SERVICE_FOCUS_LOST = "CS.cSFL";
@@ -1864,7 +1865,6 @@
Log.d(this, "stopRtt(%s)", callId);
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "stopRtt").onStopRtt();
- findConnectionForAction(callId, "stopRtt").unsetRttProperty();
} else if (mConferenceById.containsKey(callId)) {
Log.w(this, "stopRtt called on a conference.");
}
diff --git a/telephony/java/android/telephony/OWNERS b/telephony/OWNERS
similarity index 92%
copy from telephony/java/android/telephony/OWNERS
copy to telephony/OWNERS
index 68dedce..6f67bc2 100644
--- a/telephony/java/android/telephony/OWNERS
+++ b/telephony/OWNERS
@@ -1,14 +1,14 @@
set noparent
-amitmahajan@google.com
+tgunn@google.com
breadley@google.com
-fionaxu@google.com
-jackyu@google.com
hallliu@google.com
rgreenwalt@google.com
-tgunn@google.com
-jminjie@google.com
mpq@google.com
+amitmahajan@google.com
+fionaxu@google.com
+jackyu@google.com
+jminjie@google.com
+satk@google.com
shuoq@google.com
refuhoo@google.com
-
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index f009fb1..7e86966 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -172,7 +172,7 @@
}
/**
- * Get the timing advance value for LTE, as a value between 0..63.
+ * Get the timing advance value for LTE, as a value in range of 0..1282.
* Integer.MAX_VALUE is reported when there is no active RRC
* connection. Refer to 3GPP 36.213 Sec 4.2.3
* @return the LTE timing advance, if available.
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index cb867ab..ec348df 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1526,7 +1526,9 @@
*/
@SystemApi
public List<NetworkRegistrationState> getNetworkRegistrationStates() {
- return mNetworkRegistrationStates;
+ synchronized (mNetworkRegistrationStates) {
+ return new ArrayList<>(mNetworkRegistrationStates);
+ }
}
/**
@@ -1539,11 +1541,15 @@
@SystemApi
public List<NetworkRegistrationState> getNetworkRegistrationStates(int transportType) {
List<NetworkRegistrationState> list = new ArrayList<>();
- for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
- if (networkRegistrationState.getTransportType() == transportType) {
- list.add(networkRegistrationState);
+
+ synchronized (mNetworkRegistrationStates) {
+ for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
+ if (networkRegistrationState.getTransportType() == transportType) {
+ list.add(networkRegistrationState);
+ }
}
}
+
return list;
}
@@ -1557,12 +1563,36 @@
*/
@SystemApi
public NetworkRegistrationState getNetworkRegistrationStates(int transportType, int domain) {
- for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
- if (networkRegistrationState.getTransportType() == transportType
- && networkRegistrationState.getDomain() == domain) {
- return networkRegistrationState;
+ synchronized (mNetworkRegistrationStates) {
+ for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
+ if (networkRegistrationState.getTransportType() == transportType
+ && networkRegistrationState.getDomain() == domain) {
+ return networkRegistrationState;
+ }
}
}
+
return null;
}
+
+ /**
+ * @hide
+ */
+ public void addNetworkRegistrationState(NetworkRegistrationState regState) {
+ if (regState == null) return;
+
+ synchronized (mNetworkRegistrationStates) {
+ for (int i = 0; i < mNetworkRegistrationStates.size(); i++) {
+ NetworkRegistrationState curRegState = mNetworkRegistrationStates.get(i);
+ if (curRegState.getTransportType() == regState.getTransportType()
+ && curRegState.getDomain() == regState.getDomain()) {
+ mNetworkRegistrationStates.remove(i);
+ break;
+ }
+ }
+
+ mNetworkRegistrationStates.add(regState);
+ }
+ }
+
}
diff --git a/tests/ActivityManagerPerfTests/test-app/Android.mk b/tests/ActivityManagerPerfTests/test-app/Android.mk
index b0a5db7..767e899 100644
--- a/tests/ActivityManagerPerfTests/test-app/Android.mk
+++ b/tests/ActivityManagerPerfTests/test-app/Android.mk
@@ -23,6 +23,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
ActivityManagerPerfTestsUtils
+LOCAL_MIN_SDK_VERSION := 25
+
LOCAL_PACKAGE_NAME := ActivityManagerPerfTestsTestApp
include $(BUILD_PACKAGE)
diff --git a/tests/ActivityManagerPerfTests/tests/Android.mk b/tests/ActivityManagerPerfTests/tests/Android.mk
index daf603d..7597e69 100644
--- a/tests/ActivityManagerPerfTests/tests/Android.mk
+++ b/tests/ActivityManagerPerfTests/tests/Android.mk
@@ -27,6 +27,8 @@
LOCAL_PACKAGE_NAME := ActivityManagerPerfTests
+LOCAL_MIN_SDK_VERSION := 25
+
# For android.permission.FORCE_STOP_PACKAGES permission
LOCAL_CERTIFICATE := platform
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 228f9bb..83354d5 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -302,7 +302,7 @@
atraceLogger.atraceStop();
}
}
- closeApp(launch.getApp(), true);
+ closeApp(launch.getApp());
sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
}
} finally {
@@ -575,22 +575,23 @@
}
}
- private void closeApp(String appName, boolean forceStopApp) {
+ private void startHomeIntent() {
Intent homeIntent = new Intent(Intent.ACTION_MAIN);
homeIntent.addCategory(Intent.CATEGORY_HOME);
homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
getInstrumentation().getContext().startActivity(homeIntent);
sleep(POST_LAUNCH_IDLE_TIMEOUT);
- if (forceStopApp) {
- Intent startIntent = mNameToIntent.get(appName);
- if (startIntent != null) {
- String packageName = startIntent.getComponent().getPackageName();
- try {
- mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
- } catch (RemoteException e) {
- Log.w(TAG, "Error closing app", e);
- }
+ }
+
+ private void closeApp(String appName) {
+ Intent startIntent = mNameToIntent.get(appName);
+ if (startIntent != null) {
+ String packageName = startIntent.getComponent().getPackageName();
+ try {
+ mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error closing app", e);
}
}
}
diff --git a/tests/AppLaunchWear/Android.mk b/tests/AppLaunchWear/Android.mk
new file mode 100644
index 0000000..ac123e7
--- /dev/null
+++ b/tests/AppLaunchWear/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := AppLaunchWear
+
+LOCAL_CERTIFICATE := platform
+LOCAL_JAVA_LIBRARIES := android.test.base android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/AppLaunchWear/AndroidManifest.xml b/tests/AppLaunchWear/AndroidManifest.xml
new file mode 100644
index 0000000..7dfd7ba
--- /dev/null
+++ b/tests/AppLaunchWear/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.tests.applaunch"
+ android:sharedUserId="android.uid.system" >
+
+ <uses-permission android:name="android.permission.REAL_GET_TASKS" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+ <uses-sdk
+ android:minSdkVersion="22"
+ android:targetSdkVersion="24" />
+
+ <instrumentation android:label="Measure app start up time"
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.tests.applaunch" />
+
+ <application android:label="App Launch Test">
+ <uses-library android:name="android.test.runner" />
+ </application>
+</manifest>
diff --git a/tests/AppLaunchWear/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunchWear/src/com/android/tests/applaunch/AppLaunch.java
new file mode 100644
index 0000000..f32464b
--- /dev/null
+++ b/tests/AppLaunchWear/src/com/android/tests/applaunch/AppLaunch.java
@@ -0,0 +1,821 @@
+/*
+ * Copyright (C) 2013 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.tests.applaunch;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.app.ActivityManager;
+import android.app.ActivityManager.ProcessErrorStateInfo;
+import android.app.IActivityManager;
+import android.app.UiAutomation;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.support.test.rule.logging.AtraceLogger;
+import android.test.InstrumentationTestCase;
+import android.test.InstrumentationTestRunner;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+/**
+ * This test is intended to measure the time it takes for the apps to start.
+ * Names of the applications are passed in command line, and the
+ * test starts each application, and reports the start up time in milliseconds.
+ * The instrumentation expects the following key to be passed on the command line:
+ * apps - A list of applications to start and their corresponding result keys
+ * in the following format:
+ * -e apps <app name>^<result key>|<app name>^<result key>
+ */
+public class AppLaunch extends InstrumentationTestCase {
+
+ private static final int JOIN_TIMEOUT = 10000;
+ private static final String TAG = AppLaunch.class.getSimpleName();
+
+ // optional parameter: comma separated list of required account types before proceeding
+ // with the app launch
+ private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts";
+ private static final String KEY_APPS = "apps";
+ private static final String KEY_TRIAL_LAUNCH = "trial_launch";
+ private static final String KEY_LAUNCH_ITERATIONS = "launch_iterations";
+ private static final String KEY_LAUNCH_ORDER = "launch_order";
+ private static final String KEY_DROP_CACHE = "drop_cache";
+ private static final String KEY_SIMPLEPERF_CMD = "simpleperf_cmd";
+ private static final String KEY_SIMPLEPERF_APP = "simpleperf_app";
+ private static final String KEY_TRACE_ITERATIONS = "trace_iterations";
+ private static final String KEY_LAUNCH_DIRECTORY = "launch_directory";
+ private static final String KEY_TRACE_DIRECTORY = "trace_directory";
+ private static final String KEY_TRACE_CATEGORY = "trace_categories";
+ private static final String KEY_TRACE_BUFFERSIZE = "trace_bufferSize";
+ private static final String KEY_TRACE_DUMPINTERVAL = "tracedump_interval";
+ private static final String KEY_COMPILER_FILTERS = "compiler_filters";
+
+ private static final String SIMPLEPERF_APP_CMD =
+ "simpleperf --log fatal stat --csv -e cpu-cycles,major-faults --app %s & %s";
+ private static final String WEARABLE_ACTION_GOOGLE =
+ "com.google.android.wearable.action.GOOGLE";
+ private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 5000; // 5s to allow app to idle
+ private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; // 750ms idle for non initial launches
+ private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 5000; // 5s between launching apps
+ private static final String LAUNCH_SUB_DIRECTORY = "launch_logs";
+ private static final String LAUNCH_FILE = "applaunch.txt";
+ private static final String TRACE_SUB_DIRECTORY = "atrace_logs";
+ private static final String DEFAULT_TRACE_CATEGORIES =
+ "sched,freq,gfx,view,dalvik,webview,input,wm,disk,am,wm";
+ private static final String DEFAULT_TRACE_BUFFER_SIZE = "20000";
+ private static final String DEFAULT_TRACE_DUMP_INTERVAL = "10";
+ private static final String TRIAL_LAUNCH = "TRIAL_LAUNCH";
+ private static final String DELIMITER = ",";
+ private static final String DROP_CACHE_SCRIPT = "/data/local/tmp/dropCache.sh";
+ private static final String APP_LAUNCH_CMD = "am start -W -n";
+ private static final String SUCCESS_MESSAGE = "Status: ok";
+ private static final String COMPILE_SUCCESS = "Success";
+ private static final String THIS_TIME = "ThisTime:";
+ private static final String LAUNCH_ITERATION = "LAUNCH_ITERATION - %d";
+ private static final String TRACE_ITERATION = "TRACE_ITERATION-%d";
+ private static final String LAUNCH_ITERATION_PREFIX = "LAUNCH_ITERATION";
+ private static final String TRACE_ITERATION_PREFIX = "TRACE_ITERATION";
+ private static final String LAUNCH_ORDER_CYCLIC = "cyclic";
+ private static final String LAUNCH_ORDER_SEQUENTIAL = "sequential";
+ private static final String COMPILE_CMD = "cmd package compile -f -m %s %s";
+ private static final String SPEED_PROFILE_FILTER = "speed-profile";
+ private static final String VERIFY_FILTER = "verify";
+ private static final String LAUNCH_SCRIPT_NAME = "appLaunch";
+ private static final String WEARABLE_HOME_PACKAGE = "com.google.android.wearable.app";
+
+ private Map<String, Intent> mNameToIntent;
+ private List<LaunchOrder> mLaunchOrderList = new ArrayList<LaunchOrder>();
+ private Map<String, String> mNameToResultKey;
+ private Map<String, Map<String, List<AppLaunchResult>>> mNameToLaunchTime;
+ private IActivityManager mAm;
+ private String mSimplePerfCmd = null;
+ private String mLaunchOrder = null;
+ private boolean mDropCache = false;
+ private int mLaunchIterations = 10;
+ private int mTraceLaunchCount = 0;
+ private String mTraceDirectoryStr = null;
+ private Bundle mResult = new Bundle();
+ private Set<String> mRequiredAccounts;
+ private boolean mTrialLaunch = false;
+ private BufferedWriter mBufferedWriter = null;
+ private boolean mSimplePerfAppOnly = false;
+ private String[] mCompilerFilters = null;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
+ super.tearDown();
+ }
+
+ private void addLaunchResult(LaunchOrder launch, AppLaunchResult result) {
+ mNameToLaunchTime.get(launch.getApp()).get(launch.getCompilerFilter()).add(result);
+ }
+
+ private boolean hasFailureOnFirstLaunch(LaunchOrder launch) {
+ List<AppLaunchResult> results =
+ mNameToLaunchTime.get(launch.getApp()).get(launch.getCompilerFilter());
+ return (results.size() > 0) && (results.get(0).mLaunchTime < 0);
+ }
+
+ public void testMeasureStartUpTime() throws RemoteException, NameNotFoundException,
+ IOException, InterruptedException {
+ InstrumentationTestRunner instrumentation =
+ (InstrumentationTestRunner)getInstrumentation();
+ Bundle args = instrumentation.getArguments();
+ mAm = ActivityManager.getService();
+ String launchDirectory = args.getString(KEY_LAUNCH_DIRECTORY);
+
+ createMappings();
+ parseArgs(args);
+ checkAccountSignIn();
+
+ // Root directory for applaunch file to log the app launch output
+ // Will be useful in case of simpleperf command is used
+ File launchRootDir = null;
+ if (null != launchDirectory && !launchDirectory.isEmpty()) {
+ launchRootDir = new File(launchDirectory);
+ if (!launchRootDir.exists() && !launchRootDir.mkdirs()) {
+ throw new IOException("Unable to create the destination directory");
+ }
+ }
+
+ try {
+ File launchSubDir = new File(launchRootDir, LAUNCH_SUB_DIRECTORY);
+
+ if (!launchSubDir.exists() && !launchSubDir.mkdirs()) {
+ throw new IOException("Unable to create the lauch file sub directory");
+ }
+ File file = new File(launchSubDir, LAUNCH_FILE);
+ FileOutputStream outputStream = new FileOutputStream(file);
+ mBufferedWriter = new BufferedWriter(new OutputStreamWriter(
+ outputStream));
+
+ // Root directory for trace file during the launches
+ File rootTrace = null;
+ File rootTraceSubDir = null;
+ int traceBufferSize = 0;
+ int traceDumpInterval = 0;
+ Set<String> traceCategoriesSet = null;
+ if (null != mTraceDirectoryStr && !mTraceDirectoryStr.isEmpty()) {
+ rootTrace = new File(mTraceDirectoryStr);
+ if (!rootTrace.exists() && !rootTrace.mkdirs()) {
+ throw new IOException("Unable to create the trace directory");
+ }
+ rootTraceSubDir = new File(rootTrace, TRACE_SUB_DIRECTORY);
+ if (!rootTraceSubDir.exists() && !rootTraceSubDir.mkdirs()) {
+ throw new IOException("Unable to create the trace sub directory");
+ }
+ assertNotNull("Trace iteration parameter is mandatory",
+ args.getString(KEY_TRACE_ITERATIONS));
+ mTraceLaunchCount = Integer.parseInt(args.getString(KEY_TRACE_ITERATIONS));
+ String traceCategoriesStr = args
+ .getString(KEY_TRACE_CATEGORY, DEFAULT_TRACE_CATEGORIES);
+ traceBufferSize = Integer.parseInt(args.getString(KEY_TRACE_BUFFERSIZE,
+ DEFAULT_TRACE_BUFFER_SIZE));
+ traceDumpInterval = Integer.parseInt(args.getString(KEY_TRACE_DUMPINTERVAL,
+ DEFAULT_TRACE_DUMP_INTERVAL));
+ traceCategoriesSet = new HashSet<String>();
+ if (!traceCategoriesStr.isEmpty()) {
+ String[] traceCategoriesSplit = traceCategoriesStr.split(DELIMITER);
+ for (int i = 0; i < traceCategoriesSplit.length; i++) {
+ traceCategoriesSet.add(traceCategoriesSplit[i]);
+ }
+ }
+ }
+
+ // Get the app launch order based on launch order, trial launch,
+ // launch iterations and trace iterations
+ setLaunchOrder();
+
+ for (LaunchOrder launch : mLaunchOrderList) {
+ dropCache();
+ String appPkgName = mNameToIntent.get(launch.getApp())
+ .getComponent().getPackageName();
+
+ // App launch times for trial launch will not be used for final
+ // launch time calculations.
+ if (launch.getLaunchReason().equals(TRIAL_LAUNCH)) {
+ // In the "applaunch.txt" file, trail launches is referenced using
+ // "TRIAL_LAUNCH"
+ if (SPEED_PROFILE_FILTER.equals(launch.getCompilerFilter())) {
+ assertTrue(String.format("Not able to compile the app : %s", appPkgName),
+ compileApp(VERIFY_FILTER, appPkgName));
+ } else if (launch.getCompilerFilter() != null) {
+ assertTrue(String.format("Not able to compile the app : %s", appPkgName),
+ compileApp(launch.getCompilerFilter(), appPkgName));
+ }
+ // We only need to run a trial for the speed-profile filter, but we always
+ // run one for "applaunch.txt" consistency.
+ AppLaunchResult launchResult =
+ startApp(launch.getApp(), true, launch.getLaunchReason());
+ if (launchResult.mLaunchTime < 0) {
+ addLaunchResult(launch, new AppLaunchResult());
+ // simply pass the app if launch isn't successful
+ // error should have already been logged by startApp
+ continue;
+ }
+ sleep(INITIAL_LAUNCH_IDLE_TIMEOUT);
+ if (SPEED_PROFILE_FILTER.equals(launch.getCompilerFilter())) {
+ // Send SIGUSR1 to force dumping a profile.
+ String sendSignalCommand =
+ String.format("killall -s SIGUSR1 %s", appPkgName);
+ getInstrumentation().getUiAutomation().executeShellCommand(
+ sendSignalCommand);
+ assertTrue(String.format("Not able to compile the app : %s", appPkgName),
+ compileApp(launch.getCompilerFilter(), appPkgName));
+ }
+ }
+
+ // App launch times used for final calculation
+ else if (launch.getLaunchReason().contains(LAUNCH_ITERATION_PREFIX)) {
+ AppLaunchResult launchResults = null;
+ if (hasFailureOnFirstLaunch(launch)) {
+ // skip if the app has failures while launched first
+ continue;
+ }
+ // In the "applaunch.txt" file app launches are referenced using
+ // "LAUNCH_ITERATION - ITERATION NUM"
+ if (appPkgName.contains(WEARABLE_HOME_PACKAGE)) {
+ launchResults = startApp(launch.getApp(), false, launch.getLaunchReason());
+ } else {
+ launchResults = startApp(launch.getApp(), true, launch.getLaunchReason());
+ }
+ if (launchResults.mLaunchTime < 0) {
+ addLaunchResult(launch, new AppLaunchResult());
+ // if it fails once, skip the rest of the launches
+ continue;
+ } else {
+ addLaunchResult(launch, launchResults);
+ }
+ sleep(POST_LAUNCH_IDLE_TIMEOUT);
+ }
+
+ // App launch times for trace launch will not be used for final
+ // launch time calculations.
+ else if (launch.getLaunchReason().contains(TRACE_ITERATION_PREFIX)) {
+ AtraceLogger atraceLogger = AtraceLogger
+ .getAtraceLoggerInstance(getInstrumentation());
+ // Start the trace
+ try {
+ atraceLogger.atraceStart(traceCategoriesSet, traceBufferSize,
+ traceDumpInterval, rootTraceSubDir,
+ String.format("%s-%s", launch.getApp(), launch.getLaunchReason()));
+ startApp(launch.getApp(), true, launch.getLaunchReason());
+ sleep(POST_LAUNCH_IDLE_TIMEOUT);
+ } finally {
+ // Stop the trace
+ atraceLogger.atraceStop();
+ }
+ }
+ closeApp(launch.getApp(), true);
+ sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
+ }
+ } finally {
+ if (null != mBufferedWriter) {
+ mBufferedWriter.close();
+ }
+ }
+
+ for (String app : mNameToResultKey.keySet()) {
+ for (String compilerFilter : mCompilerFilters) {
+ StringBuilder launchTimes = new StringBuilder();
+ StringBuilder cpuCycles = new StringBuilder();
+ StringBuilder majorFaults = new StringBuilder();
+ for (AppLaunchResult result : mNameToLaunchTime.get(app).get(compilerFilter)) {
+ launchTimes.append(result.mLaunchTime);
+ launchTimes.append(",");
+ if (mSimplePerfAppOnly) {
+ cpuCycles.append(result.mCpuCycles);
+ cpuCycles.append(",");
+ majorFaults.append(result.mMajorFaults);
+ majorFaults.append(",");
+ }
+ }
+ String filterName = (compilerFilter == null) ? "" : ("-" + compilerFilter);
+ mResult.putString(mNameToResultKey.get(app) + filterName, launchTimes.toString());
+ if (mSimplePerfAppOnly) {
+ mResult.putString(mNameToResultKey.get(app) + filterName + "-cpuCycles",
+ cpuCycles.toString());
+ mResult.putString(mNameToResultKey.get(app) + filterName + "-majorFaults",
+ majorFaults.toString());
+ }
+ }
+ }
+ instrumentation.sendStatus(0, mResult);
+ }
+
+ /**
+ * Compile the app package using compilerFilter and return true or false
+ * based on status of the compilation command.
+ */
+ private boolean compileApp(String compilerFilter, String appPkgName) throws IOException {
+ try (ParcelFileDescriptor result = getInstrumentation().getUiAutomation().
+ executeShellCommand(String.format(COMPILE_CMD, compilerFilter, appPkgName));
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
+ new FileInputStream(result.getFileDescriptor())))) {
+ String line;
+ while ((line = bufferedReader.readLine()) != null) {
+ if (line.contains(COMPILE_SUCCESS)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * If launch order is "cyclic" then apps will be launched one after the
+ * other for each iteration count.
+ * If launch order is "sequential" then each app will be launched for given number
+ * iterations at once before launching the other apps.
+ */
+ private void setLaunchOrder() {
+ if (LAUNCH_ORDER_CYCLIC.equalsIgnoreCase(mLaunchOrder)) {
+ for (String compilerFilter : mCompilerFilters) {
+ if (mTrialLaunch) {
+ for (String app : mNameToResultKey.keySet()) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH));
+ }
+ }
+ for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
+ for (String app : mNameToResultKey.keySet()) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
+ String.format(LAUNCH_ITERATION, launchCount)));
+ }
+ }
+ if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
+ for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
+ for (String app : mNameToResultKey.keySet()) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
+ String.format(TRACE_ITERATION, traceCount)));
+ }
+ }
+ }
+ }
+ } else if (LAUNCH_ORDER_SEQUENTIAL.equalsIgnoreCase(mLaunchOrder)) {
+ for (String compilerFilter : mCompilerFilters) {
+ for (String app : mNameToResultKey.keySet()) {
+ if (mTrialLaunch) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH));
+ }
+ for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
+ String.format(LAUNCH_ITERATION, launchCount)));
+ }
+ if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
+ for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
+ mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
+ String.format(TRACE_ITERATION, traceCount)));
+ }
+ }
+ }
+ }
+ } else {
+ assertTrue("Launch order is not valid parameter", false);
+ }
+ }
+
+ private void dropCache() {
+ if (mDropCache) {
+ assertNotNull("Issue in dropping the cache",
+ getInstrumentation().getUiAutomation()
+ .executeShellCommand(DROP_CACHE_SCRIPT));
+ }
+ }
+
+ private void parseArgs(Bundle args) {
+ mNameToResultKey = new LinkedHashMap<String, String>();
+ mNameToLaunchTime = new HashMap<>();
+ String launchIterations = args.getString(KEY_LAUNCH_ITERATIONS);
+ if (launchIterations != null) {
+ mLaunchIterations = Integer.parseInt(launchIterations);
+ }
+ String appList = args.getString(KEY_APPS);
+ if (appList == null)
+ return;
+
+ String appNames[] = appList.split("\\|");
+ for (String pair : appNames) {
+ String[] parts = pair.split("\\^");
+ if (parts.length != 2) {
+ Log.e(TAG, "The apps key is incorrectly formatted");
+ fail();
+ }
+
+ mNameToResultKey.put(parts[0], parts[1]);
+ mNameToLaunchTime.put(parts[0], null);
+ }
+ String requiredAccounts = args.getString(KEY_REQUIRED_ACCOUNTS);
+ if (requiredAccounts != null) {
+ mRequiredAccounts = new HashSet<String>();
+ for (String accountType : requiredAccounts.split(",")) {
+ mRequiredAccounts.add(accountType);
+ }
+ }
+
+ String compilerFilterList = args.getString(KEY_COMPILER_FILTERS);
+ if (compilerFilterList != null) {
+ // If a compiler filter is passed, we make a trial launch to force compilation
+ // of the apps.
+ mTrialLaunch = true;
+ mCompilerFilters = compilerFilterList.split("\\|");
+ } else {
+ // Just pass a null compiler filter to use the current state of the app.
+ mCompilerFilters = new String[1];
+ }
+
+ // Pre-populate the results map to avoid null checks.
+ for (String app : mNameToLaunchTime.keySet()) {
+ HashMap<String, List<AppLaunchResult>> map = new HashMap<>();
+ mNameToLaunchTime.put(app, map);
+ for (String compilerFilter : mCompilerFilters) {
+ map.put(compilerFilter, new ArrayList<>());
+ }
+ }
+
+ mTraceDirectoryStr = args.getString(KEY_TRACE_DIRECTORY);
+ mDropCache = Boolean.parseBoolean(args.getString(KEY_DROP_CACHE));
+ mSimplePerfCmd = args.getString(KEY_SIMPLEPERF_CMD);
+ mLaunchOrder = args.getString(KEY_LAUNCH_ORDER, LAUNCH_ORDER_CYCLIC);
+ mSimplePerfAppOnly = Boolean.parseBoolean(args.getString(KEY_SIMPLEPERF_APP));
+ mTrialLaunch = mTrialLaunch || Boolean.parseBoolean(args.getString(KEY_TRIAL_LAUNCH));
+
+ if (mSimplePerfCmd != null && mSimplePerfAppOnly) {
+ Log.w(TAG, String.format("Passing both %s and %s is not supported, ignoring %s",
+ KEY_SIMPLEPERF_CMD, KEY_SIMPLEPERF_APP));
+ }
+ }
+
+ private boolean hasLeanback(Context context) {
+ return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ }
+
+ private void createMappings() {
+ mNameToIntent = new LinkedHashMap<String, Intent>();
+
+ PackageManager pm = getInstrumentation().getContext()
+ .getPackageManager();
+ Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
+ intentToResolve.addCategory(hasLeanback(getInstrumentation().getContext()) ?
+ Intent.CATEGORY_LEANBACK_LAUNCHER :
+ Intent.CATEGORY_LAUNCHER);
+ List<ResolveInfo> ris = pm.queryIntentActivities(intentToResolve, 0);
+ resolveLoop(ris, intentToResolve, pm);
+ // For Wear
+ intentToResolve = new Intent(WEARABLE_ACTION_GOOGLE);
+ ris = pm.queryIntentActivities(intentToResolve, 0);
+ resolveLoop(ris, intentToResolve, pm);
+ }
+
+ private void resolveLoop(List<ResolveInfo> ris, Intent intentToResolve, PackageManager pm) {
+ if (ris == null || ris.isEmpty()) {
+ Log.i(TAG, "Could not find any apps");
+ } else {
+ for (ResolveInfo ri : ris) {
+ Intent startIntent = new Intent(intentToResolve);
+ startIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ startIntent.setClassName(ri.activityInfo.packageName,
+ ri.activityInfo.name);
+ String appName = ri.loadLabel(pm).toString();
+ if (appName != null) {
+ // Support launching intent using package name or app name
+ mNameToIntent.put(ri.activityInfo.packageName, startIntent);
+ mNameToIntent.put(appName, startIntent);
+ }
+ }
+ }
+ }
+
+ private AppLaunchResult startApp(String appName, boolean forceStopBeforeLaunch,
+ String launchReason) throws NameNotFoundException, RemoteException {
+ Log.i(TAG, "Starting " + appName);
+
+ Intent startIntent = mNameToIntent.get(appName);
+ if (startIntent == null) {
+ Log.w(TAG, "App does not exist: " + appName);
+ mResult.putString(mNameToResultKey.get(appName), "App does not exist");
+ return new AppLaunchResult();
+ }
+ AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent, forceStopBeforeLaunch,
+ launchReason);
+ Thread t = new Thread(runnable);
+ t.start();
+ try {
+ t.join(JOIN_TIMEOUT);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ return runnable.getResult();
+ }
+
+ private void checkAccountSignIn() {
+ // ensure that the device has the required account types before starting test
+ // e.g. device must have a valid Google account sign in to measure a meaningful launch time
+ // for Gmail
+ if (mRequiredAccounts == null || mRequiredAccounts.isEmpty()) {
+ return;
+ }
+ final AccountManager am =
+ (AccountManager) getInstrumentation().getTargetContext().getSystemService(
+ Context.ACCOUNT_SERVICE);
+ Account[] accounts = am.getAccounts();
+ // use set here in case device has multiple accounts of the same type
+ Set<String> foundAccounts = new HashSet<String>();
+ for (Account account : accounts) {
+ if (mRequiredAccounts.contains(account.type)) {
+ foundAccounts.add(account.type);
+ }
+ }
+ // check if account type matches, if not, fail test with message on what account types
+ // are missing
+ if (mRequiredAccounts.size() != foundAccounts.size()) {
+ mRequiredAccounts.removeAll(foundAccounts);
+ StringBuilder sb = new StringBuilder("Device missing these accounts:");
+ for (String account : mRequiredAccounts) {
+ sb.append(' ');
+ sb.append(account);
+ }
+ fail(sb.toString());
+ }
+ }
+
+ private void closeApp(String appName, boolean forceStopApp) {
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN);
+ homeIntent.addCategory(Intent.CATEGORY_HOME);
+ homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ getInstrumentation().getContext().startActivity(homeIntent);
+ sleep(POST_LAUNCH_IDLE_TIMEOUT);
+ if (forceStopApp) {
+ Intent startIntent = mNameToIntent.get(appName);
+ if (startIntent != null) {
+ String packageName = startIntent.getComponent().getPackageName();
+ try {
+ mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error closing app", e);
+ }
+ }
+ }
+ }
+
+ private void sleep(int time) {
+ try {
+ Thread.sleep(time);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+
+ private void reportError(String appName, String processName) {
+ ActivityManager am = (ActivityManager) getInstrumentation()
+ .getContext().getSystemService(Context.ACTIVITY_SERVICE);
+ List<ProcessErrorStateInfo> crashes = am.getProcessesInErrorState();
+ if (crashes != null) {
+ for (ProcessErrorStateInfo crash : crashes) {
+ if (!crash.processName.equals(processName))
+ continue;
+
+ Log.w(TAG, appName + " crashed: " + crash.shortMsg);
+ mResult.putString(mNameToResultKey.get(appName), crash.shortMsg);
+ return;
+ }
+ }
+
+ mResult.putString(mNameToResultKey.get(appName),
+ "Crashed for unknown reason");
+ Log.w(TAG, appName
+ + " not found in process list, most likely it is crashed");
+ }
+
+ private class LaunchOrder {
+ private String mApp;
+ private String mCompilerFilter;
+ private String mLaunchReason;
+
+ LaunchOrder(String app, String compilerFilter, String launchReason){
+ mApp = app;
+ mCompilerFilter = compilerFilter;
+ mLaunchReason = launchReason;
+ }
+
+ public String getApp() {
+ return mApp;
+ }
+
+ public void setApp(String app) {
+ mApp = app;
+ }
+
+ public String getCompilerFilter() {
+ return mCompilerFilter;
+ }
+
+ public String getLaunchReason() {
+ return mLaunchReason;
+ }
+
+ public void setLaunchReason(String launchReason) {
+ mLaunchReason = launchReason;
+ }
+ }
+
+ private class AppLaunchResult {
+ long mLaunchTime;
+ long mCpuCycles;
+ long mMajorFaults;
+
+ AppLaunchResult() {
+ mLaunchTime = -1L;
+ mCpuCycles = -1L;
+ mMajorFaults = -1L;
+ }
+
+ AppLaunchResult(String launchTime, String cpuCycles, String majorFaults) {
+ try {
+ mLaunchTime = Long.parseLong(launchTime, 10);
+ mCpuCycles = Long.parseLong(cpuCycles, 10);
+ mMajorFaults = Long.parseLong(majorFaults, 10);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Error parsing result", e);
+ }
+ }
+ }
+
+ private class AppLaunchRunnable implements Runnable {
+ private Intent mLaunchIntent;
+ private AppLaunchResult mLaunchResult;
+ private boolean mForceStopBeforeLaunch;
+ private String mLaunchReason;
+
+ public AppLaunchRunnable(Intent intent, boolean forceStopBeforeLaunch,
+ String launchReason) {
+ mLaunchIntent = intent;
+ mForceStopBeforeLaunch = forceStopBeforeLaunch;
+ mLaunchReason = launchReason;
+ mLaunchResult = new AppLaunchResult();
+ }
+
+ public AppLaunchResult getResult() {
+ return mLaunchResult;
+ }
+
+ public void run() {
+ File launchFile = null;
+ try {
+ String packageName = mLaunchIntent.getComponent().getPackageName();
+ String componentName = mLaunchIntent.getComponent().flattenToShortString();
+ if (mForceStopBeforeLaunch) {
+ mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
+ }
+ String launchCmd = String.format("%s %s", APP_LAUNCH_CMD, componentName);
+ if (mSimplePerfAppOnly) {
+ try {
+ // executeShellCommand cannot handle shell specific actions, like '&'.
+ // Therefore, we create a file containing the command and make that
+ // the command to launch.
+ launchFile = File.createTempFile(LAUNCH_SCRIPT_NAME, ".sh");
+ launchFile.setExecutable(true);
+ try (FileOutputStream stream = new FileOutputStream(launchFile);
+ BufferedWriter writer =
+ new BufferedWriter(new OutputStreamWriter(stream))) {
+ String cmd = String.format(SIMPLEPERF_APP_CMD, packageName, launchCmd);
+ writer.write(cmd);
+ }
+ launchCmd = launchFile.getAbsolutePath();
+ } catch (IOException e) {
+ Log.w(TAG, "Error writing the launch command", e);
+ return;
+ }
+ } else if (null != mSimplePerfCmd) {
+ launchCmd = String.format("%s %s", mSimplePerfCmd, launchCmd);
+ }
+ Log.v(TAG, "Final launch cmd:" + launchCmd);
+ ParcelFileDescriptor parcelDesc = getInstrumentation().getUiAutomation()
+ .executeShellCommand(launchCmd);
+ mLaunchResult = parseLaunchTimeAndWrite(parcelDesc, String.format
+ ("App Launch :%s %s", componentName, mLaunchReason));
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error launching app", e);
+ } finally {
+ if (launchFile != null) {
+ launchFile.delete();
+ }
+ }
+ }
+
+ /**
+ * Method to parse the launch time info and write the result to file
+ *
+ * @param parcelDesc
+ * @return
+ */
+ private AppLaunchResult parseLaunchTimeAndWrite(ParcelFileDescriptor parcelDesc,
+ String headerInfo) {
+ String launchTime = "-1";
+ String cpuCycles = "-1";
+ String majorFaults = "-1";
+ boolean launchSuccess = false;
+ try {
+ InputStream inputStream = new FileInputStream(parcelDesc.getFileDescriptor());
+ /* SAMPLE OUTPUT :
+ Starting: Intent { cmp=com.google.android.calculator/com.android.calculator2.Calculator }
+ Status: ok
+ Activity: com.google.android.calculator/com.android.calculator2.Calculator
+ ThisTime: 357
+ TotalTime: 357
+ WaitTime: 377
+ Complete*/
+ /* WITH SIMPLEPERF :
+ Performance counter statistics,
+ 6595722690,cpu-cycles,4.511040,GHz,(100%),
+ 0,major-faults,0.000,/sec,(100%),
+ Total test time,1.462129,seconds,*/
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
+ inputStream));
+ String line = null;
+ int lineCount = 1;
+ mBufferedWriter.newLine();
+ mBufferedWriter.write(headerInfo);
+ mBufferedWriter.newLine();
+ while ((line = bufferedReader.readLine()) != null) {
+ if (lineCount == 2 && line.contains(SUCCESS_MESSAGE)) {
+ launchSuccess = true;
+ }
+ // Parse TotalTime which is the launch time
+ if (launchSuccess && lineCount == 5) {
+ String launchSplit[] = line.split(":");
+ launchTime = launchSplit[1].trim();
+ }
+
+ if (mSimplePerfAppOnly) {
+ // Parse simpleperf output.
+ if (lineCount == 9) {
+ if (!line.contains("cpu-cycles")) {
+ Log.e(TAG, "Error in simpleperf output");
+ } else {
+ cpuCycles = line.split(",")[0].trim();
+ }
+ } else if (lineCount == 10) {
+ if (!line.contains("major-faults")) {
+ Log.e(TAG, "Error in simpleperf output");
+ } else {
+ majorFaults = line.split(",")[0].trim();
+ }
+ }
+ }
+ mBufferedWriter.write(line);
+ mBufferedWriter.newLine();
+ lineCount++;
+ }
+ mBufferedWriter.flush();
+ inputStream.close();
+ } catch (IOException e) {
+ Log.w(TAG, "Error writing the launch file", e);
+ }
+ return new AppLaunchResult(launchTime, cpuCycles, majorFaults);
+ }
+
+ }
+}
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index bdbc149..a61ac54 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -15,6 +15,7 @@
import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemClock;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -986,11 +987,16 @@
legacyResults[i] = new RttResult();
legacyResults[i].status = result.getStatus();
legacyResults[i].bssid = result.getMacAddress().toString();
- legacyResults[i].distance = result.getDistanceMm() / 10;
- legacyResults[i].distanceStandardDeviation =
- result.getDistanceStdDevMm() / 10;
- legacyResults[i].rssi = result.getRssi();
- legacyResults[i].ts = result.getRangingTimestampUs();
+ if (result.getStatus() == RangingResult.STATUS_SUCCESS) {
+ legacyResults[i].distance = result.getDistanceMm() / 10;
+ legacyResults[i].distanceStandardDeviation =
+ result.getDistanceStdDevMm() / 10;
+ legacyResults[i].rssi = result.getRssi();
+ legacyResults[i].ts = result.getRangingTimestampUs();
+ } else {
+ // just in case legacy API needed some relatively real timestamp
+ legacyResults[i].ts = SystemClock.elapsedRealtime() * 1000;
+ }
}
listener.onSuccess(legacyResults);
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 897b1ea..d2cdf8d 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -99,35 +99,45 @@
// Supplicant error codes:
/**
* The error code if there was a problem authenticating.
+ * @deprecated This is no longer supported.
*/
+ @Deprecated
public static final int ERROR_AUTHENTICATING = 1;
/**
* The reason code if there is no error during authentication.
* It could also imply that there no authentication in progress,
* this reason code also serves as a reset value.
+ * @deprecated This is no longer supported.
* @hide
*/
+ @Deprecated
public static final int ERROR_AUTH_FAILURE_NONE = 0;
/**
* The reason code if there was a timeout authenticating.
+ * @deprecated This is no longer supported.
* @hide
*/
+ @Deprecated
public static final int ERROR_AUTH_FAILURE_TIMEOUT = 1;
/**
* The reason code if there was a wrong password while
* authenticating.
+ * @deprecated This is no longer supported.
* @hide
*/
+ @Deprecated
public static final int ERROR_AUTH_FAILURE_WRONG_PSWD = 2;
/**
* The reason code if there was EAP failure while
* authenticating.
+ * @deprecated This is no longer supported.
* @hide
*/
+ @Deprecated
public static final int ERROR_AUTH_FAILURE_EAP_FAILURE = 3;
/**
@@ -565,8 +575,10 @@
* to perform Wi-Fi operations) or the connection to the supplicant has been
* lost. One extra provides the connection state as a boolean, where {@code true}
* means CONNECTED.
+ * @deprecated This is no longer supported.
* @see #EXTRA_SUPPLICANT_CONNECTED
*/
+ @Deprecated
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION =
"android.net.wifi.supplicant.CONNECTION_CHANGE";
@@ -575,7 +587,9 @@
* the supplicant daemon has been gained or lost. {@code true} means
* a connection now exists.
* Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
+ * @deprecated This is no longer supported.
*/
+ @Deprecated
public static final String EXTRA_SUPPLICANT_CONNECTED = "connected";
/**
* Broadcast intent action indicating that the state of Wi-Fi connectivity
@@ -612,7 +626,9 @@
* the overall state of connectivity.
* @see #EXTRA_NEW_STATE
* @see #EXTRA_SUPPLICANT_ERROR
+ * @deprecated This is no longer supported.
*/
+ @Deprecated
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String SUPPLICANT_STATE_CHANGED_ACTION =
"android.net.wifi.supplicant.STATE_CHANGE";
@@ -620,7 +636,9 @@
* The lookup key for a {@link SupplicantState} describing the new state
* Retrieve with
* {@link android.content.Intent#getParcelableExtra(String)}.
+ * @deprecated This is no longer supported.
*/
+ @Deprecated
public static final String EXTRA_NEW_STATE = "newState";
/**
@@ -629,7 +647,9 @@
* Retrieve with
* {@link android.content.Intent#getIntExtra(String, int)}.
* @see #ERROR_AUTHENTICATING
+ * @deprecated This is no longer supported.
*/
+ @Deprecated
public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError";
/**
@@ -638,8 +658,10 @@
* Retrieve with
* {@link android.content.Intent#getIntExtra(String, int)}.
* @see #ERROR_AUTH_FAILURE_#REASON_CODE
+ * @deprecated This is no longer supported.
* @hide
*/
+ @Deprecated
public static final String EXTRA_SUPPLICANT_ERROR_REASON = "supplicantErrorReason";
/**
@@ -3617,8 +3639,10 @@
* Restore state from the older version of back up data.
* The old backup data was essentially a backup of wpa_supplicant.conf
* and ipconfig.txt file.
+ * @deprecated this is no longer supported.
* @hide
*/
+ @Deprecated
public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
try {
mService.restoreSupplicantBackupData(supplicantData, ipConfigData);
diff --git a/wifi/java/android/net/wifi/WpsInfo.java b/wifi/java/android/net/wifi/WpsInfo.java
index ae2e771..d12cce1 100644
--- a/wifi/java/android/net/wifi/WpsInfo.java
+++ b/wifi/java/android/net/wifi/WpsInfo.java
@@ -21,37 +21,58 @@
/**
* A class representing Wi-Fi Protected Setup
- *
+ * @deprecated This class is no longer supported.
* {@see WifiP2pConfig}
*/
+@Deprecated
public class WpsInfo implements Parcelable {
- /** Push button configuration */
+ /** Push button configuration
+ * @deprecated This is no longer supported.*/
+ @Deprecated
public static final int PBC = 0;
- /** Display pin method configuration - pin is generated and displayed on device */
+ /** Display pin method configuration - pin is generated and displayed on device
+ * @deprecated This is no longer supported.*/
+ @Deprecated
public static final int DISPLAY = 1;
- /** Keypad pin method configuration - pin is entered on device */
+ /** Keypad pin method configuration - pin is entered on device
+ * @deprecated This is no longer supported.*/
+ @Deprecated
public static final int KEYPAD = 2;
- /** Label pin method configuration - pin is labelled on device */
+ /** Label pin method configuration - pin is labelled on device
+ * @deprecated This is no longer supported.*/
+ @Deprecated
public static final int LABEL = 3;
- /** Invalid configuration */
+ /** Invalid configuration
+ * @deprecated This is no longer supported.*/
+ @Deprecated
public static final int INVALID = 4;
- /** Wi-Fi Protected Setup. www.wi-fi.org/wifi-protected-setup has details */
+ /** Wi-Fi Protected Setup. www.wi-fi.org/wifi-protected-setup has details
+ * @deprecated This is no longer supported.*/
+ @Deprecated
public int setup;
- /** Passed with pin method KEYPAD */
+ /** Passed with pin method KEYPAD
+ * @deprecated This is no longer supported.*/
+ @Deprecated
public String BSSID;
- /** Passed with pin method configuration */
+ /** Passed with pin method configuration
+ * @deprecated This is no longer supported.*/
+ @Deprecated
public String pin;
+ /** @deprecated This API is no longer supported.*/
+ @Deprecated
public WpsInfo() {
setup = INVALID;
BSSID = null;
pin = null;
}
+ /** @deprecated This API is no longer supported.*/
+ @Deprecated
public String toString() {
StringBuffer sbuf = new StringBuffer();
sbuf.append(" setup: ").append(setup);
@@ -63,12 +84,16 @@
return sbuf.toString();
}
- /** Implement the Parcelable interface */
+ /** Implement the Parcelable interface
+ * @deprecated This API is no longer supported.*/
+ @Deprecated
public int describeContents() {
return 0;
}
- /* Copy constructor */
+ /* Copy constructor
+ * @deprecated This API is no longer supported.*/
+ @Deprecated
public WpsInfo(WpsInfo source) {
if (source != null) {
setup = source.setup;
@@ -77,16 +102,22 @@
}
}
- /** Implement the Parcelable interface */
+ /** Implement the Parcelable interface
+ * @deprecated This API is no longer supported. */
+ @Deprecated
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(setup);
dest.writeString(BSSID);
dest.writeString(pin);
}
- /** Implement the Parcelable interface */
+ /** Implement the Parcelable interface
+ * @deprecated This API is no longer supported.*/
+ @Deprecated
public static final Creator<WpsInfo> CREATOR =
new Creator<WpsInfo>() {
+ /** @deprecated This API is nolonger supported.*/
+ @Deprecated
public WpsInfo createFromParcel(Parcel in) {
WpsInfo config = new WpsInfo();
config.setup = in.readInt();
@@ -95,6 +126,8 @@
return config;
}
+ /** @deprecated This API is nolonger supported.*/
+ @Deprecated
public WpsInfo[] newArray(int size) {
return new WpsInfo[size];
}