summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/core/src/android/text/TextPerfUtils.java2
-rw-r--r--api/current.txt10
-rw-r--r--api/system-current.txt5
-rw-r--r--cmds/incidentd/src/FdBuffer.cpp64
-rw-r--r--cmds/incidentd/src/FdBuffer.h10
-rw-r--r--cmds/incidentd/src/IncidentService.cpp3
-rw-r--r--cmds/incidentd/src/Section.cpp81
-rw-r--r--cmds/incidentd/src/incidentd_util.cpp13
-rw-r--r--cmds/incidentd/src/incidentd_util.h4
-rw-r--r--cmds/incidentd/tests/FdBuffer_test.cpp104
-rw-r--r--cmds/incidentd/tests/PrivacyBuffer_test.cpp3
-rw-r--r--cmds/statsd/benchmark/filter_value_benchmark.cpp18
-rw-r--r--cmds/statsd/src/FieldValue.cpp9
-rw-r--r--cmds/statsd/src/FieldValue.h18
-rw-r--r--cmds/statsd/src/HashableDimensionKey.cpp119
-rw-r--r--cmds/statsd/src/HashableDimensionKey.h7
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h4
-rw-r--r--cmds/statsd/src/condition/SimpleConditionTracker.cpp20
-rw-r--r--cmds/statsd/src/condition/StateTracker.cpp17
-rw-r--r--cmds/statsd/src/guardrail/StatsdStats.cpp3
-rw-r--r--cmds/statsd/src/matchers/matcher_util.cpp3
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.cpp137
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.h2
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.cpp44
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h3
-rw-r--r--cmds/statsd/src/statsd_config.proto2
-rw-r--r--cmds/statsd/src/storage/StorageManager.cpp47
-rw-r--r--cmds/statsd/src/storage/StorageManager.h11
-rw-r--r--cmds/statsd/tests/FieldValue_test.cpp69
-rw-r--r--cmds/statsd/tests/e2e/Attribution_e2e_test.cpp217
-rw-r--r--cmds/statsd/tests/statsd_test_util.cpp34
-rw-r--r--cmds/statsd/tests/statsd_test_util.h3
-rw-r--r--config/hiddenapi-light-greylist.txt14
-rw-r--r--core/java/android/app/Notification.java26
-rw-r--r--core/java/android/app/slice/SliceSpec.java2
-rw-r--r--core/java/android/app/usage/UsageEvents.java18
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java2
-rw-r--r--core/java/android/content/pm/PackageManagerInternal.java14
-rw-r--r--core/java/android/content/pm/PackageParser.java2
-rw-r--r--core/java/android/hardware/display/DisplayManagerInternal.java3
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java147
-rw-r--r--core/java/android/metrics/LogMaker.java2
-rw-r--r--core/java/android/provider/Settings.java11
-rw-r--r--core/java/android/security/keystore/recovery/KeyChainSnapshot.java30
-rw-r--r--core/java/android/view/RecordingCanvas.java10
-rw-r--r--core/jni/android/graphics/Paint.cpp9
-rw-r--r--core/jni/android_graphics_Canvas.cpp13
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp214
-rw-r--r--core/jni/fd_utils.cpp165
-rw-r--r--core/jni/fd_utils.h54
-rw-r--r--core/proto/android/server/powermanagerservice.proto2
-rw-r--r--core/tests/coretests/BinderProxyCountingTestApp/Android.mk1
-rw-r--r--core/tests/coretests/BinderProxyCountingTestService/Android.mk1
-rw-r--r--core/tests/coretests/BstatsTestApp/Android.mk3
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java1
-rw-r--r--core/tests/featureflagtests/AndroidTest.xml8
-rw-r--r--core/tests/overlaytests/device/AndroidTest.xml3
-rw-r--r--core/tests/privacytests/AndroidTest.xml8
-rw-r--r--core/tests/utiltests/AndroidTest.xml8
-rw-r--r--core/tests/webkit/AndroidTest.xml5
-rw-r--r--core/tests/webkit/apk_with_native_libs/Android.mk2
-rw-r--r--graphics/java/android/graphics/BaseCanvas.java12
-rw-r--r--libs/hwui/SkiaCanvas.cpp9
-rw-r--r--libs/hwui/hwui/Canvas.cpp7
-rw-r--r--libs/hwui/hwui/Canvas.h2
-rw-r--r--libs/hwui/hwui/MinikinUtils.cpp16
-rw-r--r--libs/hwui/hwui/MinikinUtils.h2
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp25
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.h39
-rw-r--r--libs/hwui/tests/common/TestUtils.cpp2
-rw-r--r--media/OWNERS1
-rw-r--r--media/java/android/media/MediaController2.java18
-rw-r--r--media/java/android/media/MediaPlayer2Impl.java14
-rw-r--r--media/java/android/media/MediaPlaylistAgent.java6
-rw-r--r--media/java/android/media/MediaSession2.java29
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java12
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java10
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java24
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java3
-rw-r--r--packages/SystemUI/res/values/strings.xml3
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl13
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl5
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/OverviewProxyService.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java109
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java)251
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java62
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java5
-rw-r--r--proto/src/metrics_constants.proto4
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java7
-rw-r--r--services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java30
-rw-r--r--services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java5
-rw-r--r--services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java2
-rw-r--r--services/backup/java/com/android/server/backup/internal/PerformBackupTask.java3
-rw-r--r--services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java7
-rw-r--r--services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java6
-rw-r--r--services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java7
-rw-r--r--services/backup/java/com/android/server/backup/utils/AppBackupUtils.java78
-rw-r--r--services/backup/java/com/android/server/backup/utils/FullBackupUtils.java11
-rw-r--r--services/backup/java/com/android/server/backup/utils/RestoreUtils.java11
-rw-r--r--services/backup/java/com/android/server/backup/utils/TarBackupReader.java8
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java61
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java7
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java2
-rw-r--r--services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java1
-rw-r--r--services/core/java/com/android/server/backup/BackupUtils.java82
-rw-r--r--services/core/java/com/android/server/display/DisplayDevice.java18
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java21
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java11
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java12
-rw-r--r--services/core/java/com/android/server/display/OWNERS4
-rw-r--r--services/core/java/com/android/server/display/OverlayDisplayAdapter.java6
-rw-r--r--services/core/java/com/android/server/display/VirtualDisplayAdapter.java6
-rw-r--r--services/core/java/com/android/server/display/WifiDisplayAdapter.java4
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java15
-rw-r--r--services/core/java/com/android/server/media/OWNERS1
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java31
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackageInfo.java25
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java3
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java2
-rw-r--r--services/core/java/com/android/server/wm/BlackFrame.java49
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java59
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java13
-rw-r--r--services/core/java/com/android/server/wm/ScreenRotationAnimation.java151
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimator.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java82
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java11
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfaceController.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java153
-rw-r--r--services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java68
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java44
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java320
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java2
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl5
-rw-r--r--telephony/java/com/android/internal/telephony/RILConstants.java5
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java5
-rw-r--r--wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java3
-rw-r--r--wifi/java/android/net/wifi/rtt/RangingResult.java2
158 files changed, 2659 insertions, 1613 deletions
diff --git a/apct-tests/perftests/core/src/android/text/TextPerfUtils.java b/apct-tests/perftests/core/src/android/text/TextPerfUtils.java
index dccb34be9d07..fefda64b51a7 100644
--- a/apct-tests/perftests/core/src/android/text/TextPerfUtils.java
+++ b/apct-tests/perftests/core/src/android/text/TextPerfUtils.java
@@ -76,7 +76,7 @@ public class TextPerfUtils {
}
SpannableStringBuilder ssb = new SpannableStringBuilder(cs);
- for (int i = 0; i < ssb.length(); i += wordLen) {
+ for (int i = 0; i < ssb.length(); i += wordLen + 1) {
final int spanStart = i;
final int spanEnd = (i + wordLen) > ssb.length() ? ssb.length() : i + wordLen;
diff --git a/api/current.txt b/api/current.txt
index f92896d476e8..8321c1856607 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5196,6 +5196,7 @@ package android.app {
field public static final java.lang.String CATEGORY_ERROR = "err";
field public static final java.lang.String CATEGORY_EVENT = "event";
field public static final java.lang.String CATEGORY_MESSAGE = "msg";
+ field public static final java.lang.String CATEGORY_NAVIGATION = "navigation";
field public static final java.lang.String CATEGORY_PROGRESS = "progress";
field public static final java.lang.String CATEGORY_PROMO = "promo";
field public static final java.lang.String CATEGORY_RECOMMENDATION = "recommendation";
@@ -7419,12 +7420,14 @@ package android.app.usage {
method public int getEventType();
method public java.lang.String getPackageName();
method public java.lang.String getShortcutId();
+ method public int getStandbyBucket();
method public long getTimeStamp();
field public static final int CONFIGURATION_CHANGE = 5; // 0x5
field public static final int MOVE_TO_BACKGROUND = 2; // 0x2
field public static final int MOVE_TO_FOREGROUND = 1; // 0x1
field public static final int NONE = 0; // 0x0
field public static final int SHORTCUT_INVOCATION = 8; // 0x8
+ field public static final int STANDBY_BUCKET_CHANGED = 11; // 0xb
field public static final int USER_INTERACTION = 7; // 0x7
}
@@ -21246,9 +21249,10 @@ package android.inputmethodservice {
method public final boolean switchToPreviousInputMethod();
method public void updateFullscreenMode();
method public void updateInputViewShown();
+ field public static final int BACK_DISPOSITION_ADJUST_NOTHING = 3; // 0x3
field public static final int BACK_DISPOSITION_DEFAULT = 0; // 0x0
- field public static final int BACK_DISPOSITION_WILL_DISMISS = 2; // 0x2
- field public static final int BACK_DISPOSITION_WILL_NOT_DISMISS = 1; // 0x1
+ field public static final deprecated int BACK_DISPOSITION_WILL_DISMISS = 2; // 0x2
+ field public static final deprecated int BACK_DISPOSITION_WILL_NOT_DISMISS = 1; // 0x1
}
public class InputMethodService.InputMethodImpl extends android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodImpl {
@@ -28678,7 +28682,7 @@ package android.net.wifi {
field public static final int IEEE8021X = 3; // 0x3
field public static final int NONE = 0; // 0x0
field public static final int WPA_EAP = 2; // 0x2
- field public static final deprecated int WPA_PSK = 1; // 0x1
+ field public static final int WPA_PSK = 1; // 0x1
field public static final java.lang.String[] strings;
field public static final java.lang.String varName = "key_mgmt";
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 5ec84fee4905..af783caf7c12 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -336,6 +336,9 @@ package android.app {
}
public class Notification implements android.os.Parcelable {
+ field public static final java.lang.String CATEGORY_CAR_EMERGENCY = "car_emergency";
+ field public static final java.lang.String CATEGORY_CAR_INFORMATION = "car_information";
+ field public static final java.lang.String CATEGORY_CAR_WARNING = "car_warning";
field public static final java.lang.String EXTRA_ALLOW_DURING_SETUP = "android.allowDuringSetup";
field public static final java.lang.String EXTRA_SUBSTITUTE_APP_NAME = "android.substName";
field public static final int FLAG_AUTOGROUP_SUMMARY = 1024; // 0x400
@@ -719,10 +722,8 @@ package android.app.usage {
public static final class UsageEvents.Event {
method public java.lang.String getNotificationChannelId();
- method public int getStandbyBucket();
field public static final int NOTIFICATION_INTERRUPTION = 12; // 0xc
field public static final int NOTIFICATION_SEEN = 10; // 0xa
- field public static final int STANDBY_BUCKET_CHANGED = 11; // 0xb
}
public final class UsageStatsManager {
diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp
index 35701446e9d9..2b85ec08f9a6 100644
--- a/cmds/incidentd/src/FdBuffer.cpp
+++ b/cmds/incidentd/src/FdBuffer.cpp
@@ -34,11 +34,11 @@ FdBuffer::FdBuffer()
FdBuffer::~FdBuffer() {}
-status_t FdBuffer::read(int fd, int64_t timeout) {
- struct pollfd pfds = {.fd = fd, .events = POLLIN};
+status_t FdBuffer::read(unique_fd* fd, int64_t timeout) {
+ struct pollfd pfds = {.fd = fd->get(), .events = POLLIN};
mStartTime = uptimeMillis();
- fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
+ fcntl(fd->get(), F_SETFL, fcntl(fd->get(), F_GETFL, 0) | O_NONBLOCK);
while (true) {
if (mBuffer.size() >= MAX_BUFFER_COUNT * BUFFER_SIZE) {
@@ -67,16 +67,16 @@ status_t FdBuffer::read(int fd, int64_t timeout) {
VLOG("return event has error %s", strerror(errno));
return errno != 0 ? -errno : UNKNOWN_ERROR;
} else {
- ssize_t amt = ::read(fd, mBuffer.writeBuffer(), mBuffer.currentToWrite());
+ ssize_t amt = ::read(fd->get(), mBuffer.writeBuffer(), mBuffer.currentToWrite());
if (amt < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
continue;
} else {
- VLOG("Fail to read %d: %s", fd, strerror(errno));
+ VLOG("Fail to read %d: %s", fd->get(), strerror(errno));
return -errno;
}
} else if (amt == 0) {
- VLOG("Reached EOF of fd=%d", fd);
+ VLOG("Reached EOF of fd=%d", fd->get());
break;
}
mBuffer.wp()->move(amt);
@@ -87,7 +87,7 @@ status_t FdBuffer::read(int fd, int64_t timeout) {
return NO_ERROR;
}
-status_t FdBuffer::readFully(int fd) {
+status_t FdBuffer::readFully(unique_fd* fd) {
mStartTime = uptimeMillis();
while (true) {
@@ -99,10 +99,10 @@ status_t FdBuffer::readFully(int fd) {
}
if (mBuffer.writeBuffer() == NULL) return NO_MEMORY;
- ssize_t amt =
- TEMP_FAILURE_RETRY(::read(fd, mBuffer.writeBuffer(), mBuffer.currentToWrite()));
+ ssize_t amt = TEMP_FAILURE_RETRY(
+ ::read(fd->get(), mBuffer.writeBuffer(), mBuffer.currentToWrite()));
if (amt < 0) {
- VLOG("Fail to read %d: %s", fd, strerror(errno));
+ VLOG("Fail to read %d: %s", fd->get(), strerror(errno));
return -errno;
} else if (amt == 0) {
VLOG("Done reading %zu bytes", mBuffer.size());
@@ -116,20 +116,20 @@ status_t FdBuffer::readFully(int fd) {
return NO_ERROR;
}
-status_t FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeoutMs,
- const bool isSysfs) {
+status_t FdBuffer::readProcessedDataInStream(unique_fd* fd, unique_fd* toFd, unique_fd* fromFd,
+ int64_t timeoutMs, const bool isSysfs) {
struct pollfd pfds[] = {
- {.fd = fd, .events = POLLIN},
- {.fd = toFd, .events = POLLOUT},
- {.fd = fromFd, .events = POLLIN},
+ {.fd = fd->get(), .events = POLLIN},
+ {.fd = toFd->get(), .events = POLLOUT},
+ {.fd = fromFd->get(), .events = POLLIN},
};
mStartTime = uptimeMillis();
// mark all fds non blocking
- fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
- fcntl(toFd, F_SETFL, fcntl(toFd, F_GETFL, 0) | O_NONBLOCK);
- fcntl(fromFd, F_SETFL, fcntl(fromFd, F_GETFL, 0) | O_NONBLOCK);
+ fcntl(fd->get(), F_SETFL, fcntl(fd->get(), F_GETFL, 0) | O_NONBLOCK);
+ fcntl(toFd->get(), F_SETFL, fcntl(toFd->get(), F_GETFL, 0) | O_NONBLOCK);
+ fcntl(fromFd->get(), F_SETFL, fcntl(fromFd->get(), F_GETFL, 0) | O_NONBLOCK);
// A circular buffer holds data read from fd and writes to parsing process
uint8_t cirBuf[BUFFER_SIZE];
@@ -166,10 +166,10 @@ status_t FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64
for (int i = 0; i < 3; ++i) {
if ((pfds[i].revents & POLLERR) != 0) {
if (i == 0 && isSysfs) {
- VLOG("fd %d is sysfs, ignore its POLLERR return value", fd);
+ VLOG("fd %d is sysfs, ignore its POLLERR return value", fd->get());
continue;
}
- VLOG("fd[%d]=%d returns error events: %s", i, fd, strerror(errno));
+ VLOG("fd[%d]=%d returns error events: %s", i, fd->get(), strerror(errno));
return errno != 0 ? -errno : UNKNOWN_ERROR;
}
}
@@ -178,17 +178,17 @@ status_t FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64
if (cirSize != BUFFER_SIZE && pfds[0].fd != -1) {
ssize_t amt;
if (rpos >= wpos) {
- amt = ::read(fd, cirBuf + rpos, BUFFER_SIZE - rpos);
+ amt = ::read(fd->get(), cirBuf + rpos, BUFFER_SIZE - rpos);
} else {
- amt = ::read(fd, cirBuf + rpos, wpos - rpos);
+ amt = ::read(fd->get(), cirBuf + rpos, wpos - rpos);
}
if (amt < 0) {
if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
- VLOG("Fail to read fd %d: %s", fd, strerror(errno));
+ VLOG("Fail to read fd %d: %s", fd->get(), strerror(errno));
return -errno;
} // otherwise just continue
} else if (amt == 0) {
- VLOG("Reached EOF of input file %d", fd);
+ VLOG("Reached EOF of input file %d", fd->get());
pfds[0].fd = -1; // reach EOF so don't have to poll pfds[0].
} else {
rpos += amt;
@@ -200,13 +200,13 @@ status_t FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64
if (cirSize > 0 && pfds[1].fd != -1) {
ssize_t amt;
if (rpos > wpos) {
- amt = ::write(toFd, cirBuf + wpos, rpos - wpos);
+ amt = ::write(toFd->get(), cirBuf + wpos, rpos - wpos);
} else {
- amt = ::write(toFd, cirBuf + wpos, BUFFER_SIZE - wpos);
+ amt = ::write(toFd->get(), cirBuf + wpos, BUFFER_SIZE - wpos);
}
if (amt < 0) {
if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
- VLOG("Fail to write toFd %d: %s", toFd, strerror(errno));
+ VLOG("Fail to write toFd %d: %s", toFd->get(), strerror(errno));
return -errno;
} // otherwise just continue
} else {
@@ -217,8 +217,8 @@ status_t FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64
// if buffer is empty and fd is closed, close write fd.
if (cirSize == 0 && pfds[0].fd == -1 && pfds[1].fd != -1) {
- VLOG("Close write pipe %d", toFd);
- ::close(pfds[1].fd);
+ VLOG("Close write pipe %d", toFd->get());
+ toFd->reset();
pfds[1].fd = -1;
}
@@ -231,14 +231,14 @@ status_t FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64
}
// read from parsing process
- ssize_t amt = ::read(fromFd, mBuffer.writeBuffer(), mBuffer.currentToWrite());
+ ssize_t amt = ::read(fromFd->get(), mBuffer.writeBuffer(), mBuffer.currentToWrite());
if (amt < 0) {
if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
- VLOG("Fail to read fromFd %d: %s", fromFd, strerror(errno));
+ VLOG("Fail to read fromFd %d: %s", fromFd->get(), strerror(errno));
return -errno;
} // otherwise just continue
} else if (amt == 0) {
- VLOG("Reached EOF of fromFd %d", fromFd);
+ VLOG("Reached EOF of fromFd %d", fromFd->get());
break;
} else {
mBuffer.wp()->move(amt);
diff --git a/cmds/incidentd/src/FdBuffer.h b/cmds/incidentd/src/FdBuffer.h
index 34ebcf50905d..db3a74b78178 100644
--- a/cmds/incidentd/src/FdBuffer.h
+++ b/cmds/incidentd/src/FdBuffer.h
@@ -18,10 +18,12 @@
#ifndef FD_BUFFER_H
#define FD_BUFFER_H
+#include <android-base/unique_fd.h>
#include <android/util/EncodedBuffer.h>
#include <utils/Errors.h>
using namespace android;
+using namespace android::base;
using namespace android::util;
using namespace std;
@@ -38,13 +40,13 @@ public:
* Returns NO_ERROR if there were no errors or if we timed out.
* Will mark the file O_NONBLOCK.
*/
- status_t read(int fd, int64_t timeoutMs);
+ status_t read(unique_fd* fd, int64_t timeoutMs);
/**
* Read the data until we hit eof.
* Returns NO_ERROR if there were no errors.
*/
- status_t readFully(int fd);
+ status_t readFully(unique_fd* fd);
/**
* Read processed results by streaming data to a parsing process, e.g. incident helper.
@@ -56,8 +58,8 @@ public:
*
* 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(unique_fd* fd, unique_fd* toFd, unique_fd* fromFd,
+ int64_t timeoutMs, const bool isSysfs = false);
/**
* Whether we timed out.
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index d02b4dd99067..aeccefdd15c0 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -352,7 +352,8 @@ status_t IncidentService::cmd_privacy(FILE* in, FILE* out, FILE* err, Vector<Str
printPrivacy(p, out, String8(""));
} else if (opt == "parse") {
FdBuffer buf;
- status_t error = buf.read(fileno(in), 60000);
+ unique_fd infd(fileno(in));
+ status_t error = buf.read(&infd, 60000);
if (error != NO_ERROR) {
fprintf(err, "Error reading from stdin\n");
return error;
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 5cde5a94e2dd..ab4e764d92a4 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -277,8 +277,8 @@ FileSection::~FileSection() {}
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) {
+ unique_fd fd(open(mFilename, O_RDONLY | O_CLOEXEC));
+ if (fd.get() == -1) {
ALOGW("FileSection '%s' failed to open file", this->name.string());
return -errno;
}
@@ -299,9 +299,8 @@ status_t FileSection::Execute(ReportRequestSet* requests) const {
}
// parent process
- status_t readStatus = buffer.readProcessedDataInStream(fd, p2cPipe.writeFd(), c2pPipe.readFd(),
- this->timeoutMs, mIsSysfs);
- close(fd); // close the fd anyway.
+ status_t readStatus = buffer.readProcessedDataInStream(
+ &fd, &p2cPipe.writeFd(), &c2pPipe.readFd(), this->timeoutMs, mIsSysfs);
if (readStatus != NO_ERROR || buffer.timedOut()) {
ALOGW("FileSection '%s' failed to read data from incident helper: %s, timedout: %s",
@@ -342,17 +341,17 @@ GZipSection::~GZipSection() {}
status_t GZipSection::Execute(ReportRequestSet* requests) const {
// Reads the files in order, use the first available one.
int index = 0;
- int fd = -1;
+ unique_fd fd;
while (mFilenames[index] != NULL) {
- fd = open(mFilenames[index], O_RDONLY | O_CLOEXEC);
- if (fd != -1) {
+ fd.reset(open(mFilenames[index], O_RDONLY | O_CLOEXEC));
+ if (fd.get() != -1) {
break;
}
ALOGW("GZipSection failed to open file %s", mFilenames[index]);
index++; // look at the next file.
}
- VLOG("GZipSection is using file %s, fd=%d", mFilenames[index], fd);
- if (fd == -1) return -1;
+ VLOG("GZipSection is using file %s, fd=%d", mFilenames[index], fd.get());
+ if (fd.get() == -1) return -1;
FdBuffer buffer;
Fpipe p2cPipe;
@@ -388,9 +387,9 @@ status_t GZipSection::Execute(ReportRequestSet* requests) const {
VLOG("GZipSection '%s' editPos=%zd, dataBeginAt=%zd", this->name.string(), editPos,
dataBeginAt);
- status_t readStatus = buffer.readProcessedDataInStream(
- fd, p2cPipe.writeFd(), c2pPipe.readFd(), this->timeoutMs, isSysfs(mFilenames[index]));
- close(fd); // close the fd anyway.
+ status_t readStatus =
+ buffer.readProcessedDataInStream(&fd, &p2cPipe.writeFd(), &c2pPipe.readFd(),
+ this->timeoutMs, isSysfs(mFilenames[index]));
if (readStatus != NO_ERROR || buffer.timedOut()) {
ALOGW("GZipSection '%s' failed to read data from gzip: %s, timedout: %s",
@@ -424,7 +423,7 @@ status_t GZipSection::Execute(ReportRequestSet* requests) const {
// ================================================================================
struct WorkerThreadData : public virtual RefBase {
const WorkerThreadSection* section;
- int fds[2];
+ Fpipe pipe;
// Lock protects these fields
mutex lock;
@@ -433,16 +432,10 @@ struct WorkerThreadData : public virtual RefBase {
WorkerThreadData(const WorkerThreadSection* section);
virtual ~WorkerThreadData();
-
- int readFd() { return fds[0]; }
- int writeFd() { return fds[1]; }
};
WorkerThreadData::WorkerThreadData(const WorkerThreadSection* sec)
- : section(sec), workerDone(false), workerError(NO_ERROR) {
- fds[0] = -1;
- fds[1] = -1;
-}
+ : section(sec), workerDone(false), workerError(NO_ERROR) {}
WorkerThreadData::~WorkerThreadData() {}
@@ -454,7 +447,7 @@ WorkerThreadSection::~WorkerThreadSection() {}
static void* worker_thread_func(void* cookie) {
WorkerThreadData* data = (WorkerThreadData*)cookie;
- status_t err = data->section->BlockingCall(data->writeFd());
+ status_t err = data->section->BlockingCall(data->pipe.writeFd().get());
{
unique_lock<mutex> lock(data->lock);
@@ -462,7 +455,7 @@ static void* worker_thread_func(void* cookie) {
data->workerError = err;
}
- close(data->writeFd());
+ data->pipe.writeFd().reset();
data->decStrong(data->section);
// data might be gone now. don't use it after this point in this thread.
return NULL;
@@ -479,8 +472,7 @@ status_t WorkerThreadSection::Execute(ReportRequestSet* requests) const {
sp<WorkerThreadData> data = new WorkerThreadData(this);
// Create the pipe
- err = pipe(data->fds);
- if (err != 0) {
+ if (!data->pipe.init()) {
return -errno;
}
@@ -507,7 +499,7 @@ status_t WorkerThreadSection::Execute(ReportRequestSet* requests) const {
pthread_attr_destroy(&attr);
// Loop reading until either the timeout or the worker side is done (i.e. eof).
- err = buffer.read(data->readFd(), this->timeoutMs);
+ err = buffer.read(&data->pipe.readFd(), this->timeoutMs);
if (err != NO_ERROR) {
// TODO: Log this error into the incident report.
ALOGW("WorkerThreadSection '%s' reader failed with error '%s'", this->name.string(),
@@ -516,7 +508,7 @@ status_t WorkerThreadSection::Execute(ReportRequestSet* requests) const {
// Done with the read fd. The worker thread closes the write one so
// we never race and get here first.
- close(data->readFd());
+ data->pipe.readFd().reset();
// If the worker side is finished, then return its error (which may overwrite
// our possible error -- but it's more interesting anyway). If not, then we timed out.
@@ -602,7 +594,8 @@ status_t CommandSection::Execute(ReportRequestSet* requests) const {
// child process to execute the command as root
if (cmdPid == 0) {
// replace command's stdout with ihPipe's write Fd
- if (dup2(cmdPipe.writeFd(), STDOUT_FILENO) != 1 || !ihPipe.close() || !cmdPipe.close()) {
+ if (dup2(cmdPipe.writeFd().get(), STDOUT_FILENO) != 1 || !ihPipe.close() ||
+ !cmdPipe.close()) {
ALOGW("CommandSection '%s' failed to set up stdout: %s", this->name.string(),
strerror(errno));
_exit(EXIT_FAILURE);
@@ -619,8 +612,8 @@ status_t CommandSection::Execute(ReportRequestSet* requests) const {
return -errno;
}
- close(cmdPipe.writeFd());
- status_t readStatus = buffer.read(ihPipe.readFd(), this->timeoutMs);
+ cmdPipe.writeFd().reset();
+ 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");
@@ -921,10 +914,10 @@ status_t TombstoneSection::BlockingCall(int pipeWriteFd) const {
break;
} else if (child == 0) {
// This is the child process.
- close(dumpPipe.readFd());
+ dumpPipe.readFd().reset();
const int ret = dump_backtrace_to_file_timeout(
pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
- is_java_process ? 5 : 20, dumpPipe.writeFd());
+ is_java_process ? 5 : 20, dumpPipe.writeFd().get());
if (ret == -1) {
if (errno == 0) {
ALOGW("Dumping failed for pid '%d', likely due to a timeout\n", pid);
@@ -932,25 +925,17 @@ status_t TombstoneSection::BlockingCall(int pipeWriteFd) const {
ALOGE("Dumping failed for pid '%d': %s\n", pid, strerror(errno));
}
}
- if (close(dumpPipe.writeFd()) != 0) {
- ALOGW("TombstoneSection '%s' failed to close dump pipe writeFd: %d",
- this->name.string(), errno);
- _exit(EXIT_FAILURE);
- }
-
+ dumpPipe.writeFd().reset();
_exit(EXIT_SUCCESS);
}
- close(dumpPipe.writeFd());
+ dumpPipe.writeFd().reset();
// Parent process.
// Read from the pipe concurrently to avoid blocking the child.
FdBuffer buffer;
- err = buffer.readFully(dumpPipe.readFd());
+ err = buffer.readFully(&dumpPipe.readFd());
if (err != NO_ERROR) {
ALOGW("TombstoneSection '%s' failed to read stack dump: %d", this->name.string(), err);
- if (close(dumpPipe.readFd()) != 0) {
- ALOGW("TombstoneSection '%s' failed to close dump pipe readFd: %s",
- this->name.string(), strerror(errno));
- }
+ dumpPipe.readFd().reset();
break;
}
@@ -967,13 +952,7 @@ status_t TombstoneSection::BlockingCall(int pipeWriteFd) const {
proto.write(android::os::BackTraceProto::Stack::DUMP_DURATION_NS,
static_cast<long long>(Nanotime() - start));
proto.end(token);
-
- if (close(dumpPipe.readFd()) != 0) {
- ALOGW("TombstoneSection '%s' failed to close dump pipe readFd: %d", this->name.string(),
- errno);
- err = -errno;
- break;
- }
+ dumpPipe.readFd().reset();
}
proto.flush(pipeWriteFd);
diff --git a/cmds/incidentd/src/incidentd_util.cpp b/cmds/incidentd/src/incidentd_util.cpp
index c869c7a8d1d4..d7995133c722 100644
--- a/cmds/incidentd/src/incidentd_util.cpp
+++ b/cmds/incidentd/src/incidentd_util.cpp
@@ -53,16 +53,17 @@ bool Fpipe::close() {
bool Fpipe::init() { return Pipe(&mRead, &mWrite); }
-int Fpipe::readFd() const { return mRead.get(); }
+unique_fd& Fpipe::readFd() { return mRead; }
-int Fpipe::writeFd() const { return mWrite.get(); }
+unique_fd& Fpipe::writeFd() { return mWrite; }
pid_t fork_execute_cmd(const char* cmd, char* const argv[], Fpipe* input, Fpipe* output) {
// fork used in multithreaded environment, avoid adding unnecessary code in child process
pid_t pid = fork();
if (pid == 0) {
- if (TEMP_FAILURE_RETRY(dup2(input->readFd(), STDIN_FILENO)) < 0 || !input->close() ||
- TEMP_FAILURE_RETRY(dup2(output->writeFd(), STDOUT_FILENO)) < 0 || !output->close()) {
+ if (TEMP_FAILURE_RETRY(dup2(input->readFd().get(), STDIN_FILENO)) < 0 || !input->close() ||
+ TEMP_FAILURE_RETRY(dup2(output->writeFd().get(), STDOUT_FILENO)) < 0 ||
+ !output->close()) {
ALOGW("Can't setup stdin and stdout for command %s", cmd);
_exit(EXIT_FAILURE);
}
@@ -76,8 +77,8 @@ pid_t fork_execute_cmd(const char* cmd, char* const argv[], Fpipe* input, Fpipe*
_exit(EXIT_FAILURE); // always exits with failure if any
}
// close the fds used in child process.
- close(input->readFd());
- close(output->writeFd());
+ input->readFd().reset();
+ output->writeFd().reset();
return pid;
}
diff --git a/cmds/incidentd/src/incidentd_util.h b/cmds/incidentd/src/incidentd_util.h
index 3f7df91e7e50..228d7762fc81 100644
--- a/cmds/incidentd/src/incidentd_util.h
+++ b/cmds/incidentd/src/incidentd_util.h
@@ -41,8 +41,8 @@ public:
bool init();
bool close();
- int readFd() const;
- int writeFd() const;
+ unique_fd& readFd();
+ unique_fd& writeFd();
private:
unique_fd mRead;
diff --git a/cmds/incidentd/tests/FdBuffer_test.cpp b/cmds/incidentd/tests/FdBuffer_test.cpp
index 0e5eec6c7023..bf770173793f 100644
--- a/cmds/incidentd/tests/FdBuffer_test.cpp
+++ b/cmds/incidentd/tests/FdBuffer_test.cpp
@@ -37,6 +37,7 @@ class FdBufferTest : public Test {
public:
virtual void SetUp() override {
ASSERT_NE(tf.fd, -1);
+ tffd.reset(tf.fd);
ASSERT_NE(p2cPipe.init(), -1);
ASSERT_NE(c2pPipe.init(), -1);
}
@@ -56,13 +57,13 @@ public:
EXPECT_EQ(expected[i], '\0');
}
- bool DoDataStream(int rFd, int wFd) {
+ bool DoDataStream(unique_fd* rFd, unique_fd* wFd) {
char buf[BUFFER_SIZE];
ssize_t nRead;
- while ((nRead = read(rFd, buf, BUFFER_SIZE)) > 0) {
+ while ((nRead = read(rFd->get(), buf, BUFFER_SIZE)) > 0) {
ssize_t nWritten = 0;
while (nWritten < nRead) {
- ssize_t amt = write(wFd, buf + nWritten, nRead - nWritten);
+ ssize_t amt = write(wFd->get(), buf + nWritten, nRead - nWritten);
if (amt < 0) {
return false;
}
@@ -75,6 +76,7 @@ public:
protected:
FdBuffer buffer;
TemporaryFile tf;
+ unique_fd tffd;
Fpipe p2cPipe;
Fpipe c2pPipe;
@@ -85,7 +87,7 @@ protected:
TEST_F(FdBufferTest, ReadAndWrite) {
std::string testdata = "FdBuffer test string";
ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
- ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
+ ASSERT_EQ(NO_ERROR, buffer.read(&tffd, READ_TIMEOUT));
AssertBufferReadSuccessful(testdata.size());
AssertBufferContent(testdata.c_str());
}
@@ -98,7 +100,7 @@ TEST_F(FdBufferTest, IterateEmpty) {
TEST_F(FdBufferTest, ReadAndIterate) {
std::string testdata = "FdBuffer test string";
ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
- ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
+ ASSERT_EQ(NO_ERROR, buffer.read(&tffd, READ_TIMEOUT));
int i = 0;
EncodedBuffer::iterator it = buffer.data();
@@ -117,16 +119,16 @@ TEST_F(FdBufferTest, ReadTimeout) {
ASSERT_TRUE(pid != -1);
if (pid == 0) {
- close(c2pPipe.readFd());
+ c2pPipe.readFd().reset();
while (true) {
write(c2pPipe.writeFd(), "poo", 3);
sleep(1);
}
_exit(EXIT_FAILURE);
} else {
- close(c2pPipe.writeFd());
+ c2pPipe.writeFd().reset();
- status_t status = buffer.read(c2pPipe.readFd(), QUICK_TIMEOUT_MS);
+ status_t status = buffer.read(&c2pPipe.readFd(), QUICK_TIMEOUT_MS);
ASSERT_EQ(NO_ERROR, status);
EXPECT_TRUE(buffer.timedOut());
@@ -143,20 +145,20 @@ TEST_F(FdBufferTest, ReadInStreamAndWrite) {
ASSERT_TRUE(pid != -1);
if (pid == 0) {
- close(p2cPipe.writeFd());
- close(c2pPipe.readFd());
+ p2cPipe.writeFd().reset();
+ c2pPipe.readFd().reset();
ASSERT_TRUE(WriteStringToFd(HEAD, c2pPipe.writeFd()));
- ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
- close(p2cPipe.readFd());
- close(c2pPipe.writeFd());
+ ASSERT_TRUE(DoDataStream(&p2cPipe.readFd(), &c2pPipe.writeFd()));
+ p2cPipe.readFd().reset();
+ c2pPipe.writeFd().reset();
// Must exit here otherwise the child process will continue executing the test binary.
_exit(EXIT_SUCCESS);
} else {
- close(p2cPipe.readFd());
- close(c2pPipe.writeFd());
+ p2cPipe.readFd().reset();
+ c2pPipe.writeFd().reset();
- ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(),
- c2pPipe.readFd(), READ_TIMEOUT));
+ ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&tffd, &p2cPipe.writeFd(),
+ &c2pPipe.readFd(), READ_TIMEOUT));
AssertBufferReadSuccessful(HEAD.size() + testdata.size());
AssertBufferContent(expected.c_str());
wait(&pid);
@@ -172,23 +174,23 @@ TEST_F(FdBufferTest, ReadInStreamAndWriteAllAtOnce) {
ASSERT_TRUE(pid != -1);
if (pid == 0) {
- close(p2cPipe.writeFd());
- close(c2pPipe.readFd());
+ p2cPipe.writeFd().reset();
+ c2pPipe.readFd().reset();
std::string data;
// wait for read finishes then write.
ASSERT_TRUE(ReadFdToString(p2cPipe.readFd(), &data));
data = HEAD + data;
ASSERT_TRUE(WriteStringToFd(data, c2pPipe.writeFd()));
- close(p2cPipe.readFd());
- close(c2pPipe.writeFd());
+ p2cPipe.readFd().reset();
+ c2pPipe.writeFd().reset();
// Must exit here otherwise the child process will continue executing the test binary.
_exit(EXIT_SUCCESS);
} else {
- close(p2cPipe.readFd());
- close(c2pPipe.writeFd());
+ p2cPipe.readFd().reset();
+ c2pPipe.writeFd().reset();
- ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(),
- c2pPipe.readFd(), READ_TIMEOUT));
+ ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&tffd, &p2cPipe.writeFd(),
+ &c2pPipe.readFd(), READ_TIMEOUT));
AssertBufferReadSuccessful(HEAD.size() + testdata.size());
AssertBufferContent(expected.c_str());
wait(&pid);
@@ -202,18 +204,18 @@ TEST_F(FdBufferTest, ReadInStreamEmpty) {
ASSERT_TRUE(pid != -1);
if (pid == 0) {
- close(p2cPipe.writeFd());
- close(c2pPipe.readFd());
- ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
- close(p2cPipe.readFd());
- close(c2pPipe.writeFd());
+ p2cPipe.writeFd().reset();
+ c2pPipe.readFd().reset();
+ ASSERT_TRUE(DoDataStream(&p2cPipe.readFd(), &c2pPipe.writeFd()));
+ p2cPipe.readFd().reset();
+ c2pPipe.writeFd().reset();
_exit(EXIT_SUCCESS);
} else {
- close(p2cPipe.readFd());
- close(c2pPipe.writeFd());
+ p2cPipe.readFd().reset();
+ c2pPipe.writeFd().reset();
- ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(),
- c2pPipe.readFd(), READ_TIMEOUT));
+ ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&tffd, &p2cPipe.writeFd(),
+ &c2pPipe.readFd(), READ_TIMEOUT));
AssertBufferReadSuccessful(0);
AssertBufferContent("");
wait(&pid);
@@ -223,24 +225,24 @@ TEST_F(FdBufferTest, ReadInStreamEmpty) {
TEST_F(FdBufferTest, ReadInStreamMoreThan4MB) {
const std::string testFile = kTestDataPath + "morethan4MB.txt";
size_t fourMB = (size_t)4 * 1024 * 1024;
- int fd = open(testFile.c_str(), O_RDONLY | O_CLOEXEC);
- ASSERT_NE(fd, -1);
+ unique_fd fd(open(testFile.c_str(), O_RDONLY | O_CLOEXEC));
+ ASSERT_NE(fd.get(), -1);
int pid = fork();
ASSERT_TRUE(pid != -1);
if (pid == 0) {
- close(p2cPipe.writeFd());
- close(c2pPipe.readFd());
- ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
- close(p2cPipe.readFd());
- close(c2pPipe.writeFd());
+ p2cPipe.writeFd().reset();
+ c2pPipe.readFd().reset();
+ ASSERT_TRUE(DoDataStream(&p2cPipe.readFd(), &c2pPipe.writeFd()));
+ p2cPipe.readFd().reset();
+ c2pPipe.writeFd().reset();
_exit(EXIT_SUCCESS);
} else {
- close(p2cPipe.readFd());
- close(c2pPipe.writeFd());
+ p2cPipe.readFd().reset();
+ c2pPipe.writeFd().reset();
- 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());
@@ -266,18 +268,18 @@ TEST_F(FdBufferTest, ReadInStreamTimeOut) {
ASSERT_TRUE(pid != -1);
if (pid == 0) {
- close(p2cPipe.writeFd());
- close(c2pPipe.readFd());
+ p2cPipe.writeFd().reset();
+ c2pPipe.readFd().reset();
while (true) {
sleep(1);
}
_exit(EXIT_FAILURE);
} else {
- close(p2cPipe.readFd());
- close(c2pPipe.writeFd());
+ p2cPipe.readFd().reset();
+ c2pPipe.writeFd().reset();
- ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(),
- c2pPipe.readFd(), QUICK_TIMEOUT_MS));
+ ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&tffd, &p2cPipe.writeFd(),
+ &c2pPipe.readFd(), QUICK_TIMEOUT_MS));
EXPECT_TRUE(buffer.timedOut());
kill(pid, SIGKILL); // reap the child process
}
diff --git a/cmds/incidentd/tests/PrivacyBuffer_test.cpp b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
index c7c69a746f0a..5edc0c79785b 100644
--- a/cmds/incidentd/tests/PrivacyBuffer_test.cpp
+++ b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
@@ -58,7 +58,8 @@ public:
void writeToFdBuffer(string str) {
ASSERT_TRUE(WriteStringToFile(str, tf.path));
- ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, 10000));
+ unique_fd tffd(tf.fd);
+ ASSERT_EQ(NO_ERROR, buffer.read(&tffd, 10000));
ASSERT_EQ(str.size(), buffer.size());
}
diff --git a/cmds/statsd/benchmark/filter_value_benchmark.cpp b/cmds/statsd/benchmark/filter_value_benchmark.cpp
index 66c4defe7adb..cfe477d7ca8f 100644
--- a/cmds/statsd/benchmark/filter_value_benchmark.cpp
+++ b/cmds/statsd/benchmark/filter_value_benchmark.cpp
@@ -54,28 +54,12 @@ static void BM_FilterValue(benchmark::State& state) {
translateFieldMatcher(field_matcher, &matchers);
while (state.KeepRunning()) {
- vector<HashableDimensionKey> output;
- filterValues(matchers, event.getValues(), &output);
- }
-}
-
-BENCHMARK(BM_FilterValue);
-
-static void BM_FilterValue2(benchmark::State& state) {
- LogEvent event(1, 100000);
- FieldMatcher field_matcher;
- createLogEventAndMatcher(&event, &field_matcher);
-
- std::vector<Matcher> matchers;
- translateFieldMatcher(field_matcher, &matchers);
-
- while (state.KeepRunning()) {
HashableDimensionKey output;
filterValues(matchers, event.getValues(), &output);
}
}
-BENCHMARK(BM_FilterValue2);
+BENCHMARK(BM_FilterValue);
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp
index 0c9b7016eaff..dfd8705f83aa 100644
--- a/cmds/statsd/src/FieldValue.cpp
+++ b/cmds/statsd/src/FieldValue.cpp
@@ -48,6 +48,11 @@ bool Field::matches(const Matcher& matcher) const {
return true;
}
+ if (matcher.hasAllPositionMatcher() &&
+ (mField & (matcher.mMask & kClearAllPositionMatcherMask)) == matcher.mMatcher.getField()) {
+ return true;
+ }
+
return false;
}
@@ -67,6 +72,10 @@ void translateFieldMatcher(int tag, const FieldMatcher& matcher, int depth, int*
return;
}
switch (matcher.position()) {
+ case Position::ALL:
+ pos[depth] = 0x00;
+ mask[depth] = 0x7f;
+ break;
case Position::ANY:
pos[depth] = 0;
mask[depth] = 0;
diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h
index 0e3ae06033e7..f7ce23b04339 100644
--- a/cmds/statsd/src/FieldValue.h
+++ b/cmds/statsd/src/FieldValue.h
@@ -30,6 +30,7 @@ const int32_t kAttributionField = 1;
const int32_t kMaxLogDepth = 2;
const int32_t kLastBitMask = 0x80;
const int32_t kClearLastBitDeco = 0x7f;
+const int32_t kClearAllPositionMatcherMask = 0xffff00ff;
enum Type { UNKNOWN, INT, LONG, FLOAT, STRING };
@@ -205,6 +206,7 @@ public:
* First: [Matcher Field] 0x02010101 [Mask]0xff7f7f7f
* Last: [Matcher Field] 0x02018001 [Mask]0xff7f807f
* Any: [Matcher Field] 0x02010001 [Mask]0xff7f007f
+ * All: [Matcher Field] 0x02010001 [Mask]0xff7f7f7f
*
* [To match a log Field with a Matcher] we apply the bit mask to the log Field and check if
* the result is equal to the Matcher Field. That's a bit wise AND operation + check if 2 ints are
@@ -226,9 +228,21 @@ struct Matcher {
return mMask;
}
+ inline int32_t getRawMaskAtDepth(int32_t depth) const {
+ int32_t field = (mMask & 0x00ffffff);
+ int32_t shift = 8 * (kMaxLogDepth - depth);
+ int32_t mask = 0xff << shift;
+
+ return (field & mask) >> shift;
+ }
+
+ bool hasAllPositionMatcher() const {
+ return mMatcher.getDepth() == 2 && getRawMaskAtDepth(1) == 0x7f;
+ }
+
bool hasAnyPositionMatcher(int* prefix) const {
- if (mMatcher.getDepth() == 2 && mMatcher.getRawPosAtDepth(2) == 0) {
- (*prefix) = mMatcher.getPrefix(2);
+ if (mMatcher.getDepth() == 2 && mMatcher.getRawPosAtDepth(1) == 0) {
+ (*prefix) = mMatcher.getPrefix(1);
return true;
}
return false;
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index d0c83119dc43..71030345b0aa 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -61,125 +61,22 @@ android::hash_t hashDimension(const HashableDimensionKey& value) {
bool filterValues(const vector<Matcher>& matcherFields, const vector<FieldValue>& values,
HashableDimensionKey* output) {
- for (size_t i = 0; i < matcherFields.size(); ++i) {
- const auto& matcher = matcherFields[i];
- bool found = false;
- for (const auto& value : values) {
+ size_t num_matches = 0;
+ for (const auto& value : values) {
+ for (size_t i = 0; i < matcherFields.size(); ++i) {
+ const auto& matcher = matcherFields[i];
// TODO: potential optimization here to break early because all fields are naturally
// sorted.
if (value.mField.matches(matcher)) {
output->addValue(value);
- output->mutableValue(i)->mField.setTag(value.mField.getTag());
- output->mutableValue(i)->mField.setField(value.mField.getField() & matcher.mMask);
- found = true;
- break;
- }
- }
-
- if (!found) {
- VLOG("We can't find a dimension value for matcher (%d)%#x.", matcher.mMatcher.getTag(),
- matcher.mMatcher.getField());
- return false;
- }
- }
-
- return true;
-}
-
-// Filter fields using the matchers and output the results as a HashableDimensionKey.
-// Note: HashableDimensionKey is just a wrapper for vector<FieldValue>
-bool filterValues(const vector<Matcher>& matcherFields, const vector<FieldValue>& values,
- vector<HashableDimensionKey>* output) {
- output->push_back(HashableDimensionKey());
- // Top level is only tag id. Now take the real child matchers
- int prevAnyMatcherPrefix = 0;
- size_t prevPrevFanout = 0;
- size_t prevFanout = 0;
-
- // For each matcher get matched results.
- vector<FieldValue> matchedResults(2);
- for (const auto& matcher : matcherFields) {
- size_t num_matches = 0;
- for (const auto& value : values) {
- // TODO: potential optimization here to break early because all fields are naturally
- // sorted.
- if (value.mField.matches(matcher)) {
- if (num_matches >= matchedResults.size()) {
- matchedResults.resize(num_matches * 2);
- }
- matchedResults[num_matches].mField.setTag(value.mField.getTag());
- matchedResults[num_matches].mField.setField(value.mField.getField() & matcher.mMask);
- matchedResults[num_matches].mValue = value.mValue;
+ output->mutableValue(num_matches)->mField.setTag(value.mField.getTag());
+ output->mutableValue(num_matches)->mField.setField(
+ value.mField.getField() & matcher.mMask);
num_matches++;
}
}
-
- if (num_matches == 0) {
- VLOG("We can't find a dimension value for matcher (%d)%#x.", matcher.mMatcher.getTag(),
- matcher.mMatcher.getField());
- continue;
- }
-
- if (num_matches == 1) {
- for (auto& dimension : *output) {
- dimension.addValue(matchedResults[0]);
- }
- prevAnyMatcherPrefix = 0;
- prevFanout = 0;
- continue;
- }
-
- // All the complexity below is because we support ANY in dimension.
- bool createFanout = true;
- // createFanout is true when the matcher doesn't need to follow the prev matcher's
- // order.
- // e.g., get (uid, tag) from any position in attribution. because we have translated
- // it as 2 matchers, they need to follow the same ordering, we can't create a cross
- // product of all uid and tags.
- // However, if the 2 matchers have different prefix, they will create a cross product
- // e.g., [any uid] [any some other repeated field], we will create a cross product for them
- if (prevAnyMatcherPrefix != 0) {
- int anyMatcherPrefix = 0;
- bool isAnyMatcher = matcher.hasAnyPositionMatcher(&anyMatcherPrefix);
- if (isAnyMatcher && anyMatcherPrefix == prevAnyMatcherPrefix) {
- createFanout = false;
- } else {
- prevAnyMatcherPrefix = anyMatcherPrefix;
- }
- }
-
- // Each matcher should match exact one field, unless position is ANY
- // When x number of fields matches a matcher, the returned dimension
- // size is multiplied by x.
- int oldSize;
- if (createFanout) {
- // First create fanout (fanout size is matchedResults.Size which could be one,
- // which means we do nothing here)
- oldSize = output->size();
- for (size_t i = 1; i < num_matches; i++) {
- output->insert(output->end(), output->begin(), output->begin() + oldSize);
- }
- prevPrevFanout = oldSize;
- prevFanout = num_matches;
- } else {
- // If we should not create fanout, e.g., uid tag from same position should be remain
- // together.
- oldSize = prevPrevFanout;
- if (prevFanout != num_matches) {
- // sanity check.
- ALOGE("2 Any matcher result in different output");
- return false;
- }
- }
- // now add the matched field value to output
- for (size_t i = 0; i < num_matches; i++) {
- for (int j = 0; j < oldSize; j++) {
- (*output)[i * oldSize + j].addValue(matchedResults[i]);
- }
- }
}
-
- return output->size() > 0 && (*output)[0].getValues().size() > 0;
+ return num_matches > 0;
}
void filterGaugeValues(const std::vector<Matcher>& matcherFields,
diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h
index 4cfed883ec07..6f4941f717ee 100644
--- a/cmds/statsd/src/HashableDimensionKey.h
+++ b/cmds/statsd/src/HashableDimensionKey.h
@@ -122,17 +122,14 @@ android::hash_t hashDimension(const HashableDimensionKey& key);
/**
* Creating HashableDimensionKeys from FieldValues using matcher.
*
- * This function may make modifications to the Field if the matcher has Position=LAST or ANY in
- * it. This is because: for example, when we create dimension from last uid in attribution chain,
+ * This function may make modifications to the Field if the matcher has Position=FIRST,LAST or ALL
+ * in it. This is because: for example, when we create dimension from last uid in attribution chain,
* In one event, uid 1000 is at position 5 and it's the last
* In another event, uid 1000 is at position 6, and it's the last
* these 2 events should be mapped to the same dimension. So we will remove the original position
* from the dimension key for the uid field (by applying 0x80 bit mask).
*/
bool filterValues(const std::vector<Matcher>& matcherFields, const std::vector<FieldValue>& values,
- std::vector<HashableDimensionKey>* output);
-// This function is used when there is at most one output dimension key. (no ANY matcher)
-bool filterValues(const std::vector<Matcher>& matcherFields, const std::vector<FieldValue>& values,
HashableDimensionKey* output);
/**
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 8db82006d082..8b42146c6621 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -121,7 +121,8 @@ private:
FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration3);
FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1);
FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2);
- FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSlice);
+ FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid);
+ FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain);
FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);
FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition);
FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition);
@@ -138,6 +139,7 @@ private:
FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondition);
FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_AND_CombinationCondition);
+
};
} // namespace statsd
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index 4913aef3347f..73efb39ac119 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -327,25 +327,7 @@ void SimpleConditionTracker::evaluateCondition(
// have both sliced and unsliced version of a predicate.
handleConditionEvent(outputValue, matchedState == 1, &overallState, &overallChanged);
} else {
- std::vector<HashableDimensionKey> outputValues;
- filterValues(mOutputDimensions, event.getValues(), &outputValues);
-
- // If this event has multiple nodes in the attribution chain, this log event probably will
- // generate multiple dimensions. If so, we will find if the condition changes for any
- // dimension and ask the corresponding metric producer to verify whether the actual sliced
- // condition has changed or not.
- // A high level assumption is that a predicate is either sliced or unsliced. We will never
- // have both sliced and unsliced version of a predicate.
- for (const HashableDimensionKey& outputValue : outputValues) {
- ConditionState tempState;
- bool tempChanged = false;
- handleConditionEvent(outputValue, matchedState == 1, &tempState, &tempChanged);
- if (tempChanged) {
- overallChanged = true;
- }
- // ConditionState's | operator is overridden
- overallState = overallState | tempState;
- }
+ ALOGE("The condition tracker should not be sliced by ANY position matcher.");
}
conditionCache[mIndex] = overallState;
conditionChangedCache[mIndex] = overallChanged;
diff --git a/cmds/statsd/src/condition/StateTracker.cpp b/cmds/statsd/src/condition/StateTracker.cpp
index c68875c58162..fe1740b24dd4 100644
--- a/cmds/statsd/src/condition/StateTracker.cpp
+++ b/cmds/statsd/src/condition/StateTracker.cpp
@@ -137,21 +137,18 @@ void StateTracker::evaluateCondition(const LogEvent& event,
VLOG("StateTracker evaluate event %s", event.ToString().c_str());
- vector<HashableDimensionKey> keys;
- vector<HashableDimensionKey> outputs;
- filterValues(mPrimaryKeys, event.getValues(), &keys);
- filterValues(mOutputDimensions, event.getValues(), &outputs);
- if (keys.size() != 1 || outputs.size() != 1) {
- ALOGE("More than 1 states in the event?? panic now!");
+ // Primary key can exclusive fields must be simple fields. so there won't be more than
+ // one keys matched.
+ HashableDimensionKey primaryKey;
+ HashableDimensionKey state;
+ if (!filterValues(mPrimaryKeys, event.getValues(), &primaryKey) ||
+ !filterValues(mOutputDimensions, event.getValues(), &state)) {
+ ALOGE("Failed to filter fields in the event?? panic now!");
conditionCache[mIndex] =
mSlicedState.size() > 0 ? ConditionState::kTrue : ConditionState::kFalse;
conditionChangedCache[mIndex] = false;
return;
}
- // Primary key can exclusive fields must be simple fields. so there won't be more than
- // one keys matched.
- const auto& primaryKey = keys[0];
- const auto& state = outputs[0];
hitGuardRail(primaryKey);
VLOG("StateTracker: key %s state %s", primaryKey.toString().c_str(), state.toString().c_str());
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index c6c4d135ad3f..7a55f6065e88 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -21,6 +21,7 @@
#include <android/util/ProtoOutputStream.h>
#include "../stats_log_util.h"
#include "statslog.h"
+#include "storage/StorageManager.h"
namespace android {
namespace os {
@@ -403,6 +404,8 @@ void StatsdStats::dumpStats(FILE* out) const {
fprintf(out, "alert %lld declared %d times\n", (long long)stats.first, stats.second);
}
}
+ fprintf(out, "********Disk Usage stats***********\n");
+ StorageManager::printStats(out);
fprintf(out, "********Pushed Atom stats***********\n");
const size_t atomCounts = mPushedAtomStats.size();
for (size_t i = 2; i < atomCounts; i++) {
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index 364d4e9d5c94..b7105b351a10 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -185,6 +185,9 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher,
ranges.push_back(std::make_pair(newStart, end));
break;
}
+ case Position::ALL:
+ ALOGE("Not supported: field matcher with ALL position.");
+ break;
case Position::POSITION_UNKNOWN:
break;
}
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index bc09683d79ad..c6b9405e424d 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -88,6 +88,12 @@ DurationMetricProducer::DurationMetricProducer(const ConfigKey& key, const Durat
translateFieldMatcher(internalDimensions, &mInternalDimensions);
mContainANYPositionInInternalDimensions = HasPositionANY(internalDimensions);
}
+ if (mContainANYPositionInInternalDimensions) {
+ ALOGE("Position ANY in internal dimension not supported.");
+ }
+ if (mContainANYPositionInDimensionsInWhat) {
+ ALOGE("Position ANY in dimension_in_what not supported.");
+ }
if (metric.has_dimensions_in_condition()) {
translateFieldMatcher(metric.dimensions_in_condition(), &mDimensionsInCondition);
@@ -589,18 +595,10 @@ void DurationMetricProducer::handleStartEvent(const MetricDimensionKey& eventKey
it->second->noteStart(DEFAULT_DIMENSION_KEY, condition,
event.GetElapsedTimestampNs(), conditionKeys);
} else {
- if (mContainANYPositionInInternalDimensions) {
- std::vector<HashableDimensionKey> dimensionKeys;
- filterValues(mInternalDimensions, event.getValues(), &dimensionKeys);
- for (const auto& key : dimensionKeys) {
- it->second->noteStart(key, condition, event.GetElapsedTimestampNs(), conditionKeys);
- }
- } else {
- HashableDimensionKey dimensionKey = DEFAULT_DIMENSION_KEY;
- filterValues(mInternalDimensions, event.getValues(), &dimensionKey);
- it->second->noteStart(
- dimensionKey, condition, event.GetElapsedTimestampNs(), conditionKeys);
- }
+ HashableDimensionKey dimensionKey = DEFAULT_DIMENSION_KEY;
+ filterValues(mInternalDimensions, event.getValues(), &dimensionKey);
+ it->second->noteStart(
+ dimensionKey, condition, event.GetElapsedTimestampNs(), conditionKeys);
}
}
@@ -612,8 +610,8 @@ void DurationMetricProducer::onMatchedLogEventInternalLocked(
ALOGW("Not used in duration tracker.");
}
-void DurationMetricProducer::onMatchedLogEventLocked_simple(const size_t matcherIndex,
- const LogEvent& event) {
+void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
+ const LogEvent& event) {
uint64_t eventTimeNs = event.GetElapsedTimestampNs();
if (eventTimeNs < mStartTimeNs) {
return;
@@ -712,117 +710,6 @@ void DurationMetricProducer::onMatchedLogEventLocked_simple(const size_t matcher
}
}
-void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
- const LogEvent& event) {
- if (!mContainANYPositionInDimensionsInWhat) {
- onMatchedLogEventLocked_simple(matcherIndex, event);
- return;
- }
-
- uint64_t eventTimeNs = event.GetElapsedTimestampNs();
- if (eventTimeNs < mStartTimeNs) {
- return;
- }
-
- flushIfNeededLocked(event.GetElapsedTimestampNs());
-
- // Handles Stopall events.
- if (matcherIndex == mStopAllIndex) {
- for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- for (auto& pair : whatIt.second) {
- pair.second->noteStopAll(event.GetElapsedTimestampNs());
- }
- }
- return;
- }
-
- vector<HashableDimensionKey> dimensionInWhatValues;
- if (!mDimensionsInWhat.empty()) {
- filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhatValues);
- } else {
- dimensionInWhatValues.push_back(DEFAULT_DIMENSION_KEY);
- }
-
- // Handles Stop events.
- if (matcherIndex == mStopIndex) {
- if (mUseWhatDimensionAsInternalDimension) {
- for (const HashableDimensionKey& whatKey : dimensionInWhatValues) {
- auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatKey);
- if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- for (const auto& condIt : whatIt->second) {
- condIt.second->noteStop(whatKey, event.GetElapsedTimestampNs(), false);
- }
- }
- }
- return;
- }
-
- HashableDimensionKey internalDimensionKey = DEFAULT_DIMENSION_KEY;
- if (!mInternalDimensions.empty()) {
- filterValues(mInternalDimensions, event.getValues(), &internalDimensionKey);
- }
-
- for (const HashableDimensionKey& whatDimension : dimensionInWhatValues) {
- auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatDimension);
- if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- for (const auto& condIt : whatIt->second) {
- condIt.second->noteStop(
- internalDimensionKey, event.GetElapsedTimestampNs(), false);
- }
- }
- }
- return;
- }
-
- bool condition;
- ConditionKey conditionKey;
- std::unordered_set<HashableDimensionKey> dimensionKeysInCondition;
- if (mConditionSliced) {
- for (const auto& link : mMetric2ConditionLinks) {
- getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]);
- }
-
- auto conditionState =
- mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition,
- !mSameConditionDimensionsInTracker,
- !mHasLinksToAllConditionDimensionsInTracker,
- &dimensionKeysInCondition);
- condition = (conditionState == ConditionState::kTrue);
- if (mDimensionsInCondition.empty() && condition) {
- dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
- }
- } else {
- condition = mCondition;
- if (condition) {
- dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
- }
- }
-
- for (const auto& whatDimension : dimensionInWhatValues) {
- if (dimensionKeysInCondition.empty()) {
- handleStartEvent(MetricDimensionKey(whatDimension, DEFAULT_DIMENSION_KEY),
- conditionKey, condition, event);
- } else {
- auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatDimension);
- // If the what dimension is already there, we should update all the trackers even
- // the condition is false.
- if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- for (const auto& condIt : whatIt->second) {
- const bool cond = dimensionKeysInCondition.find(condIt.first) !=
- dimensionKeysInCondition.end();
- handleStartEvent(MetricDimensionKey(whatDimension, condIt.first),
- conditionKey, cond, event);
- dimensionKeysInCondition.erase(condIt.first);
- }
- }
- for (const auto& conditionDimension : dimensionKeysInCondition) {
- handleStartEvent(MetricDimensionKey(whatDimension, conditionDimension),
- conditionKey, condition, event);
- }
- }
- }
-}
-
size_t DurationMetricProducer::byteSizeLocked() const {
size_t totalSize = 0;
for (const auto& pair : mPastBuckets) {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 6746e116333f..985749df63dd 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -52,8 +52,6 @@ public:
protected:
void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) override;
- void onMatchedLogEventLocked_simple(const size_t matcherIndex, const LogEvent& event);
-
void onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
const ConditionKey& conditionKeys, bool condition,
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 6c90b031a9cc..f4495a19d700 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -53,39 +53,17 @@ void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const Lo
dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
}
- if (mContainANYPositionInDimensionsInWhat) {
- vector<HashableDimensionKey> dimensionInWhatValues;
- if (!mDimensionsInWhat.empty()) {
- filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhatValues);
- } else {
- dimensionInWhatValues.push_back(DEFAULT_DIMENSION_KEY);
- }
-
- for (const auto& whatDimension : dimensionInWhatValues) {
- for (const auto& conditionDimensionKey : dimensionKeysInCondition) {
- onMatchedLogEventInternalLocked(
- matcherIndex, MetricDimensionKey(whatDimension, conditionDimensionKey),
- conditionKey, condition, event);
- }
- if (dimensionKeysInCondition.empty()) {
- onMatchedLogEventInternalLocked(
- matcherIndex, MetricDimensionKey(whatDimension, DEFAULT_DIMENSION_KEY),
- conditionKey, condition, event);
- }
- }
- } else {
- HashableDimensionKey dimensionInWhat;
- filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
- MetricDimensionKey metricKey(dimensionInWhat, DEFAULT_DIMENSION_KEY);
- for (const auto& conditionDimensionKey : dimensionKeysInCondition) {
- metricKey.setDimensionKeyInCondition(conditionDimensionKey);
- onMatchedLogEventInternalLocked(
- matcherIndex, metricKey, conditionKey, condition, event);
- }
- if (dimensionKeysInCondition.empty()) {
- onMatchedLogEventInternalLocked(
- matcherIndex, metricKey, conditionKey, condition, event);
- }
+ HashableDimensionKey dimensionInWhat;
+ filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
+ MetricDimensionKey metricKey(dimensionInWhat, DEFAULT_DIMENSION_KEY);
+ for (const auto& conditionDimensionKey : dimensionKeysInCondition) {
+ metricKey.setDimensionKeyInCondition(conditionDimensionKey);
+ onMatchedLogEventInternalLocked(
+ matcherIndex, metricKey, conditionKey, condition, event);
+ }
+ if (dimensionKeysInCondition.empty()) {
+ onMatchedLogEventInternalLocked(
+ matcherIndex, metricKey, conditionKey, condition, event);
}
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index bebd53c29886..46a9b34c21a1 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -163,7 +163,8 @@ private:
FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensions);
FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks);
- FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSlice);
+ FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid);
+ FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain);
FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);
FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition);
FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition);
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 1c99e2ad03bc..2c701915f429 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -31,6 +31,8 @@ enum Position {
LAST = 2;
ANY = 3;
+
+ ALL = 4;
}
enum TimeUnit {
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 77387cb8b143..cd41f533fecf 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -345,6 +345,53 @@ void StorageManager::trimToFit(const char* path) {
}
}
+void StorageManager::printStats(FILE* out) {
+ printDirStats(out, STATS_SERVICE_DIR);
+ printDirStats(out, STATS_DATA_DIR);
+}
+
+void StorageManager::printDirStats(FILE* out, const char* path) {
+ fprintf(out, "Printing stats of %s\n", path);
+ unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir);
+ if (dir == NULL) {
+ VLOG("Path %s does not exist", path);
+ return;
+ }
+ dirent* de;
+ int fileCount = 0;
+ int totalFileSize = 0;
+ while ((de = readdir(dir.get()))) {
+ char* name = de->d_name;
+ if (name[0] == '.') {
+ continue;
+ }
+ int64_t result[3];
+ parseFileName(name, result);
+ if (result[0] == -1) continue;
+ int64_t timestamp = result[0];
+ int64_t uid = result[1];
+ int64_t configID = result[2];
+ fprintf(out, "\t #%d, Last updated: %lld, UID: %d, Config ID: %lld",
+ fileCount + 1,
+ (long long)timestamp,
+ (int)uid,
+ (long long)configID);
+ string file_name = getFilePath(path, timestamp, uid, configID);
+ ifstream file(file_name.c_str(), ifstream::in | ifstream::binary);
+ if (file.is_open()) {
+ file.seekg(0, ios::end);
+ int fileSize = file.tellg();
+ file.close();
+ fprintf(out, ", File Size: %d bytes", fileSize);
+ totalFileSize += fileSize;
+ }
+ fprintf(out, "\n");
+ fileCount++;
+ }
+ fprintf(out, "\tTotal number of files: %d, Total size of files: %d bytes.\n",
+ fileCount, totalFileSize);
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/storage/StorageManager.h b/cmds/statsd/src/storage/StorageManager.h
index 13ce5c6c0698..4b7562855f30 100644
--- a/cmds/statsd/src/storage/StorageManager.h
+++ b/cmds/statsd/src/storage/StorageManager.h
@@ -84,6 +84,17 @@ public:
*/
static bool hasIdenticalConfig(const ConfigKey& key,
const vector<uint8_t>& config);
+
+ /**
+ * Prints disk usage statistics related to statsd.
+ */
+ static void printStats(FILE* out);
+
+private:
+ /**
+ * Prints disk usage statistics about a directory related to statsd.
+ */
+ static void printDirStats(FILE* out, const char* path);
};
} // namespace statsd
diff --git a/cmds/statsd/tests/FieldValue_test.cpp b/cmds/statsd/tests/FieldValue_test.cpp
index 5846761cb8e9..73e7c44dc3da 100644
--- a/cmds/statsd/tests/FieldValue_test.cpp
+++ b/cmds/statsd/tests/FieldValue_test.cpp
@@ -45,20 +45,41 @@ TEST(AtomMatcherTest, TestFieldTranslation) {
const auto& matcher12 = output[0];
EXPECT_EQ((int32_t)10, matcher12.mMatcher.getTag());
- EXPECT_EQ((int32_t)0x2010001, matcher12.mMatcher.getField());
+ EXPECT_EQ((int32_t)0x02010001, matcher12.mMatcher.getField());
EXPECT_EQ((int32_t)0xff7f007f, matcher12.mMask);
}
-TEST(AtomMatcherTest, TestFilter) {
+TEST(AtomMatcherTest, TestFieldTranslation_ALL) {
FieldMatcher matcher1;
matcher1.set_field(10);
FieldMatcher* child = matcher1.add_child();
child->set_field(1);
- child->set_position(Position::ANY);
+ child->set_position(Position::ALL);
child = child->add_child();
child->set_field(1);
+ vector<Matcher> output;
+ translateFieldMatcher(matcher1, &output);
+
+ EXPECT_EQ((size_t)1, output.size());
+
+ const auto& matcher12 = output[0];
+ EXPECT_EQ((int32_t)10, matcher12.mMatcher.getTag());
+ EXPECT_EQ((int32_t)0x02010001, matcher12.mMatcher.getField());
+ EXPECT_EQ((int32_t)0xff7f7f7f, matcher12.mMask);
+}
+
+TEST(AtomMatcherTest, TestFilter_ALL) {
+ FieldMatcher matcher1;
+ matcher1.set_field(10);
+ FieldMatcher* child = matcher1.add_child();
+ child->set_field(1);
+ child->set_position(Position::ALL);
+
+ child->add_child()->set_field(1);
+ child->add_child()->set_field(2);
+
child = matcher1.add_child();
child->set_field(2);
@@ -85,32 +106,28 @@ TEST(AtomMatcherTest, TestFilter) {
event.write("some value");
// Convert to a LogEvent
event.init();
- vector<HashableDimensionKey> output;
+ HashableDimensionKey output;
filterValues(matchers, event.getValues(), &output);
- EXPECT_EQ((size_t)(3), output.size());
-
- const auto& key1 = output[0];
- EXPECT_EQ((size_t)2, key1.getValues().size());
- EXPECT_EQ((int32_t)0x02010001, key1.getValues()[0].mField.getField());
- EXPECT_EQ((int32_t)1111, key1.getValues()[0].mValue.int_value);
- EXPECT_EQ((int32_t)0x00020000, key1.getValues()[1].mField.getField());
- EXPECT_EQ("some value", key1.getValues()[1].mValue.str_value);
-
- const auto& key2 = output[1];
- EXPECT_EQ((size_t)2, key2.getValues().size());
- EXPECT_EQ((int32_t)0x02010001, key2.getValues()[0].mField.getField());
- EXPECT_EQ((int32_t)2222, key2.getValues()[0].mValue.int_value);
- EXPECT_EQ((int32_t)0x00020000, key2.getValues()[1].mField.getField());
- EXPECT_EQ("some value", key2.getValues()[1].mValue.str_value);
-
- const auto& key3 = output[2];
- EXPECT_EQ((size_t)2, key3.getValues().size());
- EXPECT_EQ((int32_t)0x02010001, key3.getValues()[0].mField.getField());
- EXPECT_EQ((int32_t)3333, key3.getValues()[0].mValue.int_value);
- EXPECT_EQ((int32_t)0x00020000, key3.getValues()[1].mField.getField());
- EXPECT_EQ("some value", key3.getValues()[1].mValue.str_value);
+ EXPECT_EQ((size_t)7, output.getValues().size());
+ EXPECT_EQ((int32_t)0x02010101, output.getValues()[0].mField.getField());
+ EXPECT_EQ((int32_t)1111, output.getValues()[0].mValue.int_value);
+ EXPECT_EQ((int32_t)0x02010102, output.getValues()[1].mField.getField());
+ EXPECT_EQ("location1", output.getValues()[1].mValue.str_value);
+
+ EXPECT_EQ((int32_t)0x02010201, output.getValues()[2].mField.getField());
+ EXPECT_EQ((int32_t)2222, output.getValues()[2].mValue.int_value);
+ EXPECT_EQ((int32_t)0x02010202, output.getValues()[3].mField.getField());
+ EXPECT_EQ("location2", output.getValues()[3].mValue.str_value);
+
+ EXPECT_EQ((int32_t)0x02010301, output.getValues()[4].mField.getField());
+ EXPECT_EQ((int32_t)3333, output.getValues()[4].mValue.int_value);
+ EXPECT_EQ((int32_t)0x02010302, output.getValues()[5].mField.getField());
+ EXPECT_EQ("location3", output.getValues()[5].mValue.str_value);
+
+ EXPECT_EQ((int32_t)0x00020000, output.getValues()[6].mField.getField());
+ EXPECT_EQ("some value", output.getValues()[6].mValue.str_value);
}
TEST(AtomMatcherTest, TestSubDimension) {
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index 7a7e000fb98f..2574ba79f9d3 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -28,7 +28,7 @@ namespace statsd {
namespace {
-StatsdConfig CreateStatsdConfig() {
+StatsdConfig CreateStatsdConfig(const Position position) {
StatsdConfig config;
auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
auto attributionNodeMatcher =
@@ -46,15 +46,15 @@ StatsdConfig CreateStatsdConfig() {
countMetric->set_what(wakelockAcquireMatcher.id());
*countMetric->mutable_dimensions_in_what() =
CreateAttributionUidAndTagDimensions(
- android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ android::util::WAKELOCK_STATE_CHANGED, {position});
countMetric->set_bucket(FIVE_MINUTES);
return config;
}
} // namespace
-TEST(AttributionE2eTest, TestAttributionMatchAndSlice) {
- auto config = CreateStatsdConfig();
+TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid) {
+ auto config = CreateStatsdConfig(Position::FIRST);
int64_t bucketStartTimeNs = 10000000000;
int64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
@@ -199,6 +199,215 @@ TEST(AttributionE2eTest, TestAttributionMatchAndSlice) {
EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
}
+TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain) {
+ auto config = CreateStatsdConfig(Position::ALL);
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ // Here it assumes that GMS core has two uids.
+ processor->getUidMap()->updateApp(
+ android::String16("com.android.gmscore"), 222 /* uid */, 1 /* version code*/);
+ processor->getUidMap()->updateApp(
+ android::String16("com.android.gmscore"), 444 /* uid */, 1 /* version code*/);
+ processor->getUidMap()->updateApp(
+ android::String16("app1"), 111 /* uid */, 2 /* version code*/);
+ processor->getUidMap()->updateApp(
+ android::String16("APP3"), 333 /* uid */, 2 /* version code*/);
+
+ // GMS core node is in the middle.
+ std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
+ CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(333, "App3")};
+
+ // GMS core node is the last one.
+ std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App1"),
+ CreateAttribution(333, "App3"),
+ CreateAttribution(222, "GMSCoreModule1")};
+
+ // GMS core node is the first one.
+ std::vector<AttributionNodeInternal> attributions3 = {CreateAttribution(222, "GMSCoreModule1"),
+ CreateAttribution(333, "App3")};
+
+ // Single GMS core node.
+ std::vector<AttributionNodeInternal> attributions4 = {CreateAttribution(222, "GMSCoreModule1")};
+
+ // GMS core has another uid.
+ std::vector<AttributionNodeInternal> attributions5 = {CreateAttribution(111, "App1"),
+ CreateAttribution(444, "GMSCoreModule2"),
+ CreateAttribution(333, "App3")};
+
+ // Multiple GMS core nodes.
+ std::vector<AttributionNodeInternal> attributions6 = {CreateAttribution(444, "GMSCoreModule2"),
+ CreateAttribution(222, "GMSCoreModule1")};
+
+ // No GMS core nodes.
+ std::vector<AttributionNodeInternal> attributions7 = {CreateAttribution(111, "App1"),
+ CreateAttribution(333, "App3")};
+ std::vector<AttributionNodeInternal> attributions8 = {CreateAttribution(111, "App1")};
+
+ // GMS core node with isolated uid.
+ const int isolatedUid = 666;
+ std::vector<AttributionNodeInternal> attributions9 = {
+ CreateAttribution(isolatedUid, "GMSCoreModule1")};
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+ // Events 1~4 are in the 1st bucket.
+ events.push_back(CreateAcquireWakelockEvent(
+ attributions1, "wl1", bucketStartTimeNs + 2));
+ events.push_back(CreateAcquireWakelockEvent(
+ attributions2, "wl1", bucketStartTimeNs + 200));
+ events.push_back(CreateAcquireWakelockEvent(
+ attributions3, "wl1", bucketStartTimeNs + bucketSizeNs - 1));
+ events.push_back(CreateAcquireWakelockEvent(
+ attributions4, "wl1", bucketStartTimeNs + bucketSizeNs));
+
+ // Events 5~8 are in the 3rd bucket.
+ events.push_back(CreateAcquireWakelockEvent(
+ attributions5, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 1));
+ events.push_back(CreateAcquireWakelockEvent(
+ attributions6, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 100));
+ events.push_back(CreateAcquireWakelockEvent(
+ attributions7, "wl2", bucketStartTimeNs + 3 * bucketSizeNs - 2));
+ events.push_back(CreateAcquireWakelockEvent(
+ attributions8, "wl2", bucketStartTimeNs + 3 * bucketSizeNs));
+ events.push_back(CreateAcquireWakelockEvent(
+ attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 1));
+ events.push_back(CreateAcquireWakelockEvent(
+ attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 100));
+ events.push_back(CreateIsolatedUidChangedEvent(
+ isolatedUid, 222, true/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs - 1));
+ events.push_back(CreateIsolatedUidChangedEvent(
+ isolatedUid, 222, false/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs + 10));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+
+ StatsLogReport::CountMetricDataWrapper countMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+ EXPECT_EQ(countMetrics.data_size(), 6);
+
+ auto data = countMetrics.data(0);
+ ValidateAttributionUidAndTagDimension(
+ data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, data.bucket_info(1).count());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+ data.bucket_info(1).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 4 * bucketSizeNs,
+ data.bucket_info(1).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(1);
+ ValidateUidDimension(
+ data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222);
+ ValidateAttributionUidAndTagDimension(
+ data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
+ ValidateUidDimension(
+ data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333);
+ ValidateAttributionUidAndTagDimension(
+ data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+
+ data = countMetrics.data(2);
+ ValidateUidDimension(
+ data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444);
+ ValidateAttributionUidAndTagDimension(
+ data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444, "GMSCoreModule2");
+ ValidateUidDimension(
+ data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222);
+ ValidateAttributionUidAndTagDimension(
+ data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(3);
+ ValidateUidDimension(
+ data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
+ ValidateAttributionUidAndTagDimension(
+ data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
+ ValidateUidDimension(
+ data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222);
+ ValidateAttributionUidAndTagDimension(
+ data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
+ ValidateUidDimension(
+ data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333);
+ ValidateAttributionUidAndTagDimension(
+ data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(bucketStartTimeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(4);
+ ValidateUidDimension(
+ data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
+ ValidateAttributionUidAndTagDimension(
+ data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
+ ValidateUidDimension(
+ data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333);
+ ValidateAttributionUidAndTagDimension(
+ data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+ ValidateUidDimension(
+ data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222);
+ ValidateAttributionUidAndTagDimension(
+ data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(bucketStartTimeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(5);
+ ValidateUidDimension(
+ data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
+ ValidateAttributionUidAndTagDimension(
+ data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
+ ValidateUidDimension(
+ data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444);
+ ValidateAttributionUidAndTagDimension(
+ data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444, "GMSCoreModule2");
+ ValidateUidDimension(
+ data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333);
+ ValidateAttributionUidAndTagDimension(
+ data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+}
+
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 2678c8a93463..0f785dff8e81 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -500,12 +500,42 @@ void ValidateUidDimension(const DimensionsValue& value, int atomId, int uid) {
.value_tuple().dimensions_value(0).value_int(), uid);
}
+void ValidateUidDimension(const DimensionsValue& value, int node_idx, int atomId, int uid) {
+ EXPECT_EQ(value.field(), atomId);
+ EXPECT_GT(value.value_tuple().dimensions_value_size(), node_idx);
+ // Attribution field.
+ EXPECT_EQ(value.value_tuple().dimensions_value(node_idx).field(), 1);
+ EXPECT_EQ(value.value_tuple().dimensions_value(node_idx)
+ .value_tuple().dimensions_value(0).field(), 1);
+ EXPECT_EQ(value.value_tuple().dimensions_value(node_idx)
+ .value_tuple().dimensions_value(0).value_int(), uid);
+}
+
+void ValidateAttributionUidAndTagDimension(
+ const DimensionsValue& value, int node_idx, int atomId, int uid, const std::string& tag) {
+ EXPECT_EQ(value.field(), atomId);
+ EXPECT_GT(value.value_tuple().dimensions_value_size(), node_idx);
+ // Attribution field.
+ EXPECT_EQ(1, value.value_tuple().dimensions_value(node_idx).field());
+ // Uid only.
+ EXPECT_EQ(2, value.value_tuple().dimensions_value(node_idx)
+ .value_tuple().dimensions_value_size());
+ EXPECT_EQ(1, value.value_tuple().dimensions_value(node_idx)
+ .value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(uid, value.value_tuple().dimensions_value(node_idx)
+ .value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(2, value.value_tuple().dimensions_value(node_idx)
+ .value_tuple().dimensions_value(1).field());
+ EXPECT_EQ(tag, value.value_tuple().dimensions_value(node_idx)
+ .value_tuple().dimensions_value(1).value_str());
+}
+
void ValidateAttributionUidAndTagDimension(
const DimensionsValue& value, int atomId, int uid, const std::string& tag) {
EXPECT_EQ(value.field(), atomId);
- EXPECT_EQ(value.value_tuple().dimensions_value_size(), 1);
+ EXPECT_EQ(1, value.value_tuple().dimensions_value_size());
// Attribution field.
- EXPECT_EQ(value.value_tuple().dimensions_value(0).field(), 1);
+ EXPECT_EQ(1, value.value_tuple().dimensions_value(0).field());
// Uid only.
EXPECT_EQ(value.value_tuple().dimensions_value(0)
.value_tuple().dimensions_value_size(), 2);
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index 14eba1f67d9d..1ac630ccff96 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -180,9 +180,12 @@ void sortLogEventsByTimestamp(std::vector<std::unique_ptr<LogEvent>> *events);
int64_t StringToId(const string& str);
+void ValidateUidDimension(const DimensionsValue& value, int node_idx, int atomId, int uid);
void ValidateAttributionUidDimension(const DimensionsValue& value, int atomId, int uid);
void ValidateAttributionUidAndTagDimension(
const DimensionsValue& value, int atomId, int uid, const std::string& tag);
+void ValidateAttributionUidAndTagDimension(
+ const DimensionsValue& value, int node_idx, int atomId, int uid, const std::string& tag);
struct DimensionsPair {
DimensionsPair(DimensionsValue m1, DimensionsValue m2) : dimInWhat(m1), dimInCondition(m2){};
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 9f71f26d11cb..06e108c56b7f 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -96,6 +96,7 @@ Landroid/app/ActivityThread;->mLocalProviders: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;->mResourcePackages: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
@@ -116,6 +117,7 @@ Landroid/app/admin/DevicePolicyManager;->packageHasActiveAdmins(Ljava/lang/Strin
Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;ZI)V
Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;Z)V
Landroid/app/admin/DevicePolicyManager;->throwIfParentInstance(Ljava/lang/String;)V
+Landroid/app/admin/DevicePolicyManager;->setDefaultSmsApplication(Landroid/content/ComponentName;Ljava/lang/String;)V
Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_packageHasActiveAdmins:I
Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_removeActiveAdmin:I
Landroid/app/admin/SecurityLog$SecurityEvent;-><init>([B)V
@@ -502,6 +504,7 @@ Landroid/content/res/Resources;->mTypedArrayPool:Landroid/util/Pools$Synchronize
Landroid/content/res/Resources;->setCompatibilityInfo(Landroid/content/res/CompatibilityInfo;)V
Landroid/content/res/Resources;->updateSystemConfiguration(Landroid/content/res/Configuration;Landroid/util/DisplayMetrics;Landroid/content/res/CompatibilityInfo;)V
Landroid/content/res/StringBlock;-><init>(JZ)V
+Landroid/content/res/TypedArray;->extractThemeAttrs()[I
Landroid/content/res/TypedArray;->getNonConfigurationString(II)Ljava/lang/String;
Landroid/content/res/TypedArray;->getValueAt(ILandroid/util/TypedValue;)Z
Landroid/content/res/TypedArray;->mAssets:Landroid/content/res/AssetManager;
@@ -518,6 +521,7 @@ Landroid/content/res/XmlBlock;-><init>([B)V
Landroid/content/res/XmlBlock;->newParser()Landroid/content/res/XmlResourceParser;
Landroid/content/res/XmlBlock$Parser;->mBlock:Landroid/content/res/XmlBlock;
Landroid/content/res/XmlBlock$Parser;->mParseState:J
+Landroid/content/SearchRecentSuggestionsProvider;->mSuggestionProjection:[Ljava/lang/String;
Landroid/content/SyncStatusInfo;->lastSuccessTime:J
Landroid/database/AbstractCursor;->mExtras:Landroid/os/Bundle;
Landroid/database/AbstractCursor;->mNotifyUri:Landroid/net/Uri;
@@ -556,6 +560,7 @@ Landroid/graphics/Bitmap;->reinit(IIZ)V
Landroid/graphics/Camera;->native_instance:J
Landroid/graphics/Canvas;-><init>(J)V
Landroid/graphics/Canvas;->release()V
+Landroid/graphics/ColorMatrixColorFilter;->setColorMatrix(Landroid/graphics/ColorMatrix;)V
Landroid/graphics/drawable/AnimatedImageDrawable;->onAnimationEnd()V
Landroid/graphics/drawable/AnimatedStateListDrawable$AnimatedStateListState;->mStateIds:Landroid/util/SparseIntArray;
Landroid/graphics/drawable/AnimatedStateListDrawable$AnimatedStateListState;->mTransitions:Landroid/util/LongSparseLongArray;
@@ -622,6 +627,8 @@ Landroid/graphics/Movie;->mNativeMovie:J
Landroid/graphics/NinePatch$InsetStruct;-><init>(IIIIIIIIFIF)V
Landroid/graphics/NinePatch;->mBitmap:Landroid/graphics/Bitmap;
Landroid/graphics/Picture;->mNativePicture:J
+Landroid/graphics/PorterDuffColorFilter;->setColor(I)V
+Landroid/graphics/PorterDuffColorFilter;->setMode(Landroid/graphics/PorterDuff$Mode;)V
Landroid/graphics/Region;-><init>(JI)V
Landroid/graphics/Region;->mNativeRegion:J
Landroid/graphics/SurfaceTexture;->mFrameAvailableListener:J
@@ -694,8 +701,13 @@ Landroid/hardware/usb/UsbManager;->getPortStatus(Landroid/hardware/usb/UsbPort;)
Landroid/hardware/usb/UsbManager;->setCurrentFunction(Ljava/lang/String;Z)V
Landroid/hardware/usb/UsbManager;->setPortRoles(Landroid/hardware/usb/UsbPort;II)V
Landroid/hardware/usb/UsbPortStatus;->getCurrentDataRole()I
+Landroid/hardware/usb/UsbPortStatus;->getCurrentMode()I
+Landroid/hardware/usb/UsbPortStatus;->getCurrentPowerRole()I
+Landroid/hardware/usb/UsbPortStatus;->getSupportedRoleCombinations()I
Landroid/hardware/usb/UsbPortStatus;->isConnected()Z
Landroid/hardware/usb/UsbPortStatus;->isRoleCombinationSupported(II)Z
+Landroid/hardware/usb/UsbRequest;->mBuffer:Ljava/nio/ByteBuffer;
+Landroid/hardware/usb/UsbRequest;->mLength:I
Landroid/hardware/usb/UsbRequest;->mNativeContext:J
Landroid/icu/impl/CurrencyData;-><init>()V
Landroid/icu/impl/number/DecimalFormatProperties;->readObject(Ljava/io/ObjectInputStream;)V
@@ -1726,7 +1738,9 @@ Landroid/util/NtpTrustedTime;->getCachedNtpTime()J
Landroid/util/NtpTrustedTime;->getCachedNtpTimeReference()J
Landroid/util/NtpTrustedTime;->getInstance(Landroid/content/Context;)Landroid/util/NtpTrustedTime;
Landroid/util/NtpTrustedTime;->hasCache()Z
+Landroid/util/Pools$SimplePool;->mPool:[Ljava/lang/Object;
Landroid/util/Pools$SynchronizedPool;->acquire()Ljava/lang/Object;
+Landroid/util/Pools$SynchronizedPool;-><init>(I)V
Landroid/util/Rational;->mDenominator:I
Landroid/util/Rational;->mNumerator:I
Landroid/util/Rational;->readObject(Ljava/io/ObjectInputStream;)V
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 13a6be557dae..83d6003b5161 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -763,6 +763,11 @@ public class Notification implements Parcelable
public static final String CATEGORY_CALL = "call";
/**
+ * Notification category: map turn-by-turn navigation.
+ */
+ public static final String CATEGORY_NAVIGATION = "navigation";
+
+ /**
* Notification category: incoming direct message (SMS, instant message, etc.).
*/
public static final String CATEGORY_MESSAGE = "msg";
@@ -835,6 +840,27 @@ public class Notification implements Parcelable
public static final String CATEGORY_REMINDER = "reminder";
/**
+ * Notification category: extreme car emergencies.
+ * @hide
+ */
+ @SystemApi
+ public static final String CATEGORY_CAR_EMERGENCY = "car_emergency";
+
+ /**
+ * Notification category: car warnings.
+ * @hide
+ */
+ @SystemApi
+ public static final String CATEGORY_CAR_WARNING = "car_warning";
+
+ /**
+ * Notification category: general car system information.
+ * @hide
+ */
+ @SystemApi
+ public static final String CATEGORY_CAR_INFORMATION = "car_information";
+
+ /**
* One of the predefined notification categories (see the <code>CATEGORY_*</code> constants)
* that best describes this Notification. May be used by the system for ranking and filtering.
*/
diff --git a/core/java/android/app/slice/SliceSpec.java b/core/java/android/app/slice/SliceSpec.java
index 8cc0384c1007..03ffe6df88ce 100644
--- a/core/java/android/app/slice/SliceSpec.java
+++ b/core/java/android/app/slice/SliceSpec.java
@@ -89,7 +89,7 @@ public final class SliceSpec implements Parcelable {
*
* @param candidate candidate format of data.
* @return true if versions are compatible.
- * @see androidx.app.slice.widget.SliceView
+ * @see androidx.slice.widget.SliceView
*/
public boolean canRender(@NonNull SliceSpec candidate) {
if (!mType.equals(candidate.mType)) return false;
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index f7fb84ba9d0a..4c7e97bcb8da 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -109,11 +109,11 @@ public final class UsageEvents implements Parcelable {
public static final int NOTIFICATION_SEEN = 10;
/**
- * An event type denoting a change in App Standby Bucket. Additional bucket information
- * is contained in mBucketAndReason.
- * @hide
+ * An event type denoting a change in App Standby Bucket. The new bucket can be
+ * retrieved by calling {@link #getStandbyBucket()}.
+ *
+ * @see UsageStatsManager#getAppStandbyBucket()
*/
- @SystemApi
public static final int STANDBY_BUCKET_CHANGED = 11;
/**
@@ -254,8 +254,11 @@ public final class UsageEvents implements Parcelable {
/**
* The event type.
*
- * See {@link #MOVE_TO_BACKGROUND}
- * See {@link #MOVE_TO_FOREGROUND}
+ * @see #MOVE_TO_BACKGROUND
+ * @see #MOVE_TO_FOREGROUND
+ * @see #CONFIGURATION_CHANGE
+ * @see #USER_INTERACTION
+ * @see #STANDBY_BUCKET_CHANGED
*/
public int getEventType() {
return mEventType;
@@ -283,9 +286,8 @@ public final class UsageEvents implements Parcelable {
* Returns the standby bucket of the app, if the event is of type
* {@link #STANDBY_BUCKET_CHANGED}, otherwise returns 0.
* @return the standby bucket associated with the event.
- * @hide
+ *
*/
- @SystemApi
public int getStandbyBucket() {
return (mBucketAndReason & 0xFFFF0000) >>> 16;
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index efa90d308ee0..387a836e6961 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1188,7 +1188,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
if (category != CATEGORY_UNDEFINED) {
pw.println(prefix + "category=" + category);
}
- pw.println("isAllowedToUseHiddenApi=" + isAllowedToUseHiddenApi());
+ pw.println(prefix + "isAllowedToUseHiddenApi=" + isAllowedToUseHiddenApi());
}
super.dumpBack(pw, prefix);
}
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 6feb170b341d..dff51f77788e 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -547,4 +547,18 @@ public abstract class PackageManagerInternal {
/** Updates the flags for the given permission. */
public abstract void updatePermissionFlagsTEMP(@NonNull String permName,
@NonNull String packageName, int flagMask, int flagValues, int userId);
+
+ /**
+ * Returns true if it's still safe to restore data backed up from this app's version
+ * that was signed with restoringFromSigHash.
+ */
+ public abstract boolean isDataRestoreSafe(@NonNull byte[] restoringFromSigHash,
+ @NonNull String packageName);
+
+ /**
+ * Returns true if it's still safe to restore data backed up from this app's version
+ * that was signed with restoringFromSig.
+ */
+ public abstract boolean isDataRestoreSafe(@NonNull Signature restoringFromSig,
+ @NonNull String packageName);
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 5d5a9782884a..bc7540fabc19 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3492,7 +3492,7 @@ public class PackageParser {
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestApplication_usesCleartextTraffic,
- true)) {
+ owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.P)) {
ai.flags |= ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC;
}
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index f468942cc951..504f840af5bf 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -23,6 +23,7 @@ import android.util.IntArray;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
+import android.view.SurfaceControl;
/**
* Display manager local system service interface.
@@ -115,7 +116,7 @@ public abstract class DisplayManagerInternal {
* Called by the window manager to perform traversals while holding a
* surface flinger transaction.
*/
- public abstract void performTraversalInTransactionFromWindowManager();
+ public abstract void performTraversal(SurfaceControl.Transaction t);
/**
* Tells the display manager about properties of the display that depend on the windows on it.
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index b3bf092aeffe..b4c8a5e504bc 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -20,6 +20,8 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
import android.annotation.CallSuper;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
@@ -239,19 +241,89 @@ public class InputMethodService extends AbstractInputMethodService {
static final boolean DEBUG = false;
/**
- * The back button will close the input window.
+ * Allows the system to optimize the back button affordance based on the presence of software
+ * keyboard.
+ *
+ * <p>For instance, on devices that have navigation bar and software-rendered back button, the
+ * system may use a different icon while {@link #isInputViewShown()} returns {@code true}, to
+ * indicate that the back button has "dismiss" affordance.</p>
+ *
+ * <p>Note that {@link KeyEvent#KEYCODE_BACK} events continue to be sent to
+ * {@link #onKeyDown(int, KeyEvent)} even when this mode is specified. The default
+ * implementation of {@link #onKeyDown(int, KeyEvent)} for {@link KeyEvent#KEYCODE_BACK} does
+ * not take this mode into account.</p>
+ *
+ * <p>For API level {@link android.os.Build.VERSION_CODES#O_MR1} and lower devices, this is the
+ * only mode you can safely specify without worrying about the compatibility.</p>
+ *
+ * @see #setBackDisposition(int)
*/
- public static final int BACK_DISPOSITION_DEFAULT = 0; // based on window
+ public static final int BACK_DISPOSITION_DEFAULT = 0;
/**
- * This input method will not consume the back key.
+ * Deprecated flag.
+ *
+ * <p>To avoid compatibility issues, IME developers should not use this flag.</p>
+ *
+ * @deprecated on {@link android.os.Build.VERSION_CODES#P} and later devices, this flag is
+ * handled as a synonym of {@link #BACK_DISPOSITION_DEFAULT}. On
+ * {@link android.os.Build.VERSION_CODES#O_MR1} and prior devices, expected behavior
+ * of this mode had not been well defined. Most likely the end result would be the
+ * same as {@link #BACK_DISPOSITION_DEFAULT}. Either way it is not recommended to
+ * use this mode
+ * @see #setBackDisposition(int)
*/
- public static final int BACK_DISPOSITION_WILL_NOT_DISMISS = 1; // back
+ @Deprecated
+ public static final int BACK_DISPOSITION_WILL_NOT_DISMISS = 1;
/**
- * This input method will consume the back key.
+ * Deprecated flag.
+ *
+ * <p>To avoid compatibility issues, IME developers should not use this flag.</p>
+ *
+ * @deprecated on {@link android.os.Build.VERSION_CODES#P} and later devices, this flag is
+ * handled as a synonym of {@link #BACK_DISPOSITION_DEFAULT}. On
+ * {@link android.os.Build.VERSION_CODES#O_MR1} and prior devices, expected behavior
+ * of this mode had not been well defined. In AOSP implementation running on devices
+ * that have navigation bar, specifying this flag could change the software back
+ * button to "Dismiss" icon no matter whether the software keyboard is shown or not,
+ * but there would be no easy way to restore the icon state even after IME lost the
+ * connection to the application. To avoid user confusions, do not specify this mode
+ * anyway
+ * @see #setBackDisposition(int)
*/
- public static final int BACK_DISPOSITION_WILL_DISMISS = 2; // down
+ @Deprecated
+ public static final int BACK_DISPOSITION_WILL_DISMISS = 2;
+
+ /**
+ * Asks the system to not adjust the back button affordance even when the software keyboard is
+ * shown.
+ *
+ * <p>This mode is useful for UI modes where IME's main soft input window is used for some
+ * supplemental UI, such as floating candidate window for languages such as Chinese and
+ * Japanese, where users expect the back button is, or at least looks to be, handled by the
+ * target application rather than the UI shown by the IME even while {@link #isInputViewShown()}
+ * returns {@code true}.</p>
+ *
+ * <p>Note that {@link KeyEvent#KEYCODE_BACK} events continue to be sent to
+ * {@link #onKeyDown(int, KeyEvent)} even when this mode is specified. The default
+ * implementation of {@link #onKeyDown(int, KeyEvent)} for {@link KeyEvent#KEYCODE_BACK} does
+ * not take this mode into account.</p>
+ *
+ * @see #setBackDisposition(int)
+ */
+ public static final int BACK_DISPOSITION_ADJUST_NOTHING = 3;
+
+ /**
+ * Enum flag to be used for {@link #setBackDisposition(int)}.
+ *
+ * @hide
+ */
+ @Retention(SOURCE)
+ @IntDef(value = {BACK_DISPOSITION_DEFAULT, BACK_DISPOSITION_WILL_NOT_DISMISS,
+ BACK_DISPOSITION_WILL_DISMISS, BACK_DISPOSITION_ADJUST_NOTHING},
+ prefix = "BACK_DISPOSITION_")
+ public @interface BackDispositionMode {}
/**
* @hide
@@ -267,7 +339,7 @@ public class InputMethodService extends AbstractInputMethodService {
// Min and max values for back disposition.
private static final int BACK_DISPOSITION_MIN = BACK_DISPOSITION_DEFAULT;
- private static final int BACK_DISPOSITION_MAX = BACK_DISPOSITION_WILL_DISMISS;
+ private static final int BACK_DISPOSITION_MAX = BACK_DISPOSITION_ADJUST_NOTHING;
InputMethodManager mImm;
@@ -331,6 +403,8 @@ public class InputMethodService extends AbstractInputMethodService {
boolean mIsInputViewShown;
int mStatusIcon;
+
+ @BackDispositionMode
int mBackDisposition;
/**
@@ -1015,8 +1089,19 @@ public class InputMethodService extends AbstractInputMethodService {
public Dialog getWindow() {
return mWindow;
}
-
- public void setBackDisposition(int disposition) {
+
+ /**
+ * Sets the disposition mode that indicates the expected affordance for the back button.
+ *
+ * <p>Keep in mind that specifying this flag does not change the the default behavior of
+ * {@link #onKeyDown(int, KeyEvent)}. It is IME developers' responsibility for making sure that
+ * their custom implementation of {@link #onKeyDown(int, KeyEvent)} is consistent with the mode
+ * specified to this API.</p>
+ *
+ * @see #getBackDisposition()
+ * @param disposition disposition mode to be set
+ */
+ public void setBackDisposition(@BackDispositionMode int disposition) {
if (disposition == mBackDisposition) {
return;
}
@@ -1029,6 +1114,13 @@ public class InputMethodService extends AbstractInputMethodService {
mBackDisposition);
}
+ /**
+ * Retrieves the current disposition mode that indicates the expected back button affordance.
+ *
+ * @see #setBackDisposition(int)
+ * @return currently selected disposition mode
+ */
+ @BackDispositionMode
public int getBackDisposition() {
return mBackDisposition;
}
@@ -1894,7 +1986,6 @@ public class InputMethodService extends AbstractInputMethodService {
mInputStarted = false;
mStartedInputConnection = null;
mCurCompletions = null;
- mBackDisposition = BACK_DISPOSITION_DEFAULT;
}
void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) {
@@ -2096,25 +2187,31 @@ public class InputMethodService extends AbstractInputMethodService {
return mExtractEditText;
}
+
/**
- * Override this to intercept key down events before they are processed by the
- * application. If you return true, the application will not
- * process the event itself. If you return false, the normal application processing
- * will occur as if the IME had not seen the event at all.
- *
- * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK
- * KeyEvent.KEYCODE_BACK} if the IME is currently shown, to
- * possibly hide it when the key goes up (if not canceled or long pressed). In
- * addition, in fullscreen mode only, it will consume DPAD movement
- * events to move the cursor in the extracted text view, not allowing
- * them to perform navigation in the underlying application.
+ * Called back when a {@link KeyEvent} is forwarded from the target application.
+ *
+ * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK} if the IME is
+ * currently shown , to possibly hide it when the key goes up (if not canceled or long pressed).
+ * In addition, in fullscreen mode only, it will consume DPAD movement events to move the cursor
+ * in the extracted text view, not allowing them to perform navigation in the underlying
+ * application.</p>
+ *
+ * <p>The default implementation does not take flags specified to
+ * {@link #setBackDisposition(int)} into account, even on API version
+ * {@link android.os.Build.VERSION_CODES#P} and later devices. IME developers are responsible
+ * for making sure that their special handling for {@link KeyEvent#KEYCODE_BACK} are consistent
+ * with the flag they specified to {@link #setBackDisposition(int)}.</p>
+ *
+ * @param keyCode The value in {@code event.getKeyCode()}
+ * @param event Description of the key event
+ *
+ * @return {@code true} if the event is consumed by the IME and the application no longer needs
+ * to consume it. Return {@code false} when the event should be handled as if the IME
+ * had not seen the event at all.
*/
public boolean onKeyDown(int keyCode, KeyEvent event) {
-
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
- if (mBackDisposition == BACK_DISPOSITION_WILL_NOT_DISMISS) {
- return false;
- }
final ExtractEditText eet = getExtractEditTextIfVisible();
if (eet != null && eet.handleBackInTextActionModeIfNeeded(event)) {
return true;
diff --git a/core/java/android/metrics/LogMaker.java b/core/java/android/metrics/LogMaker.java
index 2bb43bd36be3..e84f91314386 100644
--- a/core/java/android/metrics/LogMaker.java
+++ b/core/java/android/metrics/LogMaker.java
@@ -103,7 +103,7 @@ public class LogMaker {
* @hide // TODO Expose in the future? Too late for O.
*/
public LogMaker setLatency(long milliseconds) {
- entries.put(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS, milliseconds);
+ entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS, milliseconds);
return this;
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 60f72953c312..2b5cece4bb35 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10378,6 +10378,17 @@ public final class Settings {
public static final String SYS_UIDCPUPOWER = "sys_uidcpupower";
/**
+ * traced global setting. This controls weather the deamons: traced and
+ * traced_probes run. This links the sys.traced system property.
+ * The following values are supported:
+ * 0 -> traced and traced_probes are disabled
+ * 1 -> traced and traced_probes are enabled
+ * Any other value defaults to disabled.
+ * @hide
+ */
+ public static final String SYS_TRACED = "sys_traced";
+
+ /**
* An integer to reduce the FPS by this factor. Only for experiments. Need to reboot the
* device for this setting to take full effect.
*
diff --git a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
index 4580c47ac3c3..00f54e16863d 100644
--- a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
+++ b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
@@ -18,12 +18,14 @@ package android.security.keystore.recovery;
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.os.BadParcelableException;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.Preconditions;
import java.security.cert.CertPath;
+import java.security.cert.CertificateException;
import java.util.List;
/**
@@ -54,7 +56,7 @@ public final class KeyChainSnapshot implements Parcelable {
private long mCounterId = DEFAULT_COUNTER_ID;
private byte[] mServerParams;
private byte[] mPublicKey; // The raw public key bytes used
- private CertPath mCertPath; // The certificate path including the intermediate certificates
+ private RecoveryCertPath mCertPath; // The cert path including necessary intermediate certs
private List<KeyChainProtectionParams> mKeyChainProtectionParams;
private List<WrappedApplicationKey> mEntryRecoveryData;
private byte[] mEncryptedRecoveryKeyBlob;
@@ -127,7 +129,17 @@ public final class KeyChainSnapshot implements Parcelable {
*/
// TODO: Change to @NonNull
public CertPath getTrustedHardwareCertPath() {
- return mCertPath;
+ if (mCertPath == null) {
+ return null;
+ } else {
+ try {
+ return mCertPath.getCertPath();
+ } catch (CertificateException e) {
+ // Rethrow an unchecked exception as it should not happen. If such an issue exists,
+ // an exception should have been thrown during service initialization.
+ throw new BadParcelableException(e);
+ }
+ }
}
/**
@@ -232,11 +244,17 @@ public final class KeyChainSnapshot implements Parcelable {
* contain a certificate of the trusted hardware public key and any necessary intermediate
* certificates.
*
- * @param certPath The public key
+ * @param certPath The certificate path
+ * @throws CertificateException if the given certificate path cannot be encoded properly
* @return This builder.
*/
- public Builder setTrustedHardwareCertPath(CertPath certPath) {
- mInstance.mCertPath = certPath;
+ public Builder setTrustedHardwareCertPath(CertPath certPath) throws CertificateException {
+ // TODO: Make it NonNull when the caller code is all updated
+ if (certPath == null) {
+ mInstance.mCertPath = null;
+ } else {
+ mInstance.mCertPath = RecoveryCertPath.createRecoveryCertPath(certPath);
+ }
return this;
}
@@ -302,6 +320,7 @@ public final class KeyChainSnapshot implements Parcelable {
out.writeLong(mCounterId);
out.writeByteArray(mServerParams);
out.writeByteArray(mPublicKey);
+ out.writeTypedObject(mCertPath, /* no flags */ 0);
}
/**
@@ -316,6 +335,7 @@ public final class KeyChainSnapshot implements Parcelable {
mCounterId = in.readLong();
mServerParams = in.createByteArray();
mPublicKey = in.createByteArray();
+ mCertPath = in.readTypedObject(RecoveryCertPath.CREATOR);
}
@Override
diff --git a/core/java/android/view/RecordingCanvas.java b/core/java/android/view/RecordingCanvas.java
index fc7d828de12e..f7a41ffa67e5 100644
--- a/core/java/android/view/RecordingCanvas.java
+++ b/core/java/android/view/RecordingCanvas.java
@@ -474,8 +474,7 @@ public class RecordingCanvas extends Canvas {
}
nDrawTextRun(mNativeCanvasWrapper, text, index, count, contextIndex, contextCount,
- x, y, isRtl, paint.getNativeInstance(), 0 /* measured text */,
- 0 /* measured text offset */);
+ x, y, isRtl, paint.getNativeInstance(), 0 /* measured text */);
}
@Override
@@ -506,19 +505,16 @@ public class RecordingCanvas extends Canvas {
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
long measuredTextPtr = 0;
- int measuredTextOffset = 0;
if (text instanceof PrecomputedText) {
PrecomputedText mt = (PrecomputedText) text;
int paraIndex = mt.findParaIndex(start);
if (end <= mt.getParagraphEnd(paraIndex)) {
// Only support if the target is in the same paragraph.
measuredTextPtr = mt.getMeasuredParagraph(paraIndex).getNativePtr();
- measuredTextOffset = start - mt.getParagraphStart(paraIndex);
}
}
nDrawTextRun(mNativeCanvasWrapper, buf, start - contextStart, len,
- 0, contextLen, x, y, isRtl, paint.getNativeInstance(),
- measuredTextPtr, measuredTextOffset);
+ 0, contextLen, x, y, isRtl, paint.getNativeInstance(), measuredTextPtr);
TemporaryBuffer.recycle(buf);
}
}
@@ -641,7 +637,7 @@ public class RecordingCanvas extends Canvas {
@FastNative
private static native void nDrawTextRun(long nativeCanvas, char[] text, int start, int count,
int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint,
- long nativePrecomputedText, int measuredTextOffset);
+ long nativePrecomputedText);
@FastNative
private static native void nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count,
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 2c05d0b976fc..bd14d45325a7 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -309,7 +309,7 @@ namespace PaintGlue {
jint count, jint bidiFlags, jfloat x, jfloat y, SkPath* path) {
minikin::Layout layout = MinikinUtils::doLayout(
paint, static_cast<minikin::Bidi>(bidiFlags), typeface, text, 0, count, count,
- nullptr, 0);
+ nullptr);
size_t nGlyphs = layout.nGlyphs();
uint16_t* glyphs = new uint16_t[nGlyphs];
SkPoint* pos = new SkPoint[nGlyphs];
@@ -351,8 +351,7 @@ namespace PaintGlue {
SkIRect ir;
minikin::Layout layout = MinikinUtils::doLayout(&paint,
- static_cast<minikin::Bidi>(bidiFlags), typeface, text, 0, count, count, nullptr,
- 0);
+ static_cast<minikin::Bidi>(bidiFlags), typeface, text, 0, count, count, nullptr);
minikin::MinikinRect rect;
layout.getBounds(&rect);
r.fLeft = rect.mLeft;
@@ -468,7 +467,7 @@ namespace PaintGlue {
}
minikin::Layout layout = MinikinUtils::doLayout(paint,
static_cast<minikin::Bidi>(bidiFlags), typeface, str.get(), 0, str.size(),
- str.size(), nullptr, 0);
+ str.size(), nullptr);
size_t nGlyphs = countNonSpaceGlyphs(layout);
if (nGlyphs != 1 && nChars > 1) {
// multiple-character input, and was not a ligature
@@ -489,7 +488,7 @@ namespace PaintGlue {
static const jchar ZZ_FLAG_STR[] = { 0xD83C, 0xDDFF, 0xD83C, 0xDDFF };
minikin::Layout zzLayout = MinikinUtils::doLayout(paint,
static_cast<minikin::Bidi>(bidiFlags), typeface, ZZ_FLAG_STR, 0, 4, 4,
- nullptr, 0);
+ nullptr);
if (zzLayout.nGlyphs() != 1 || layoutContainsNotdef(zzLayout)) {
// The font collection doesn't have a glyph for unknown flag. Just return true.
return true;
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 06de5daab7d2..0017f6cd8a41 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -484,7 +484,7 @@ static void drawTextChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray t
const Typeface* typeface = paint->getAndroidTypeface();
jchar* jchars = env->GetCharArrayElements(text, NULL);
get_canvas(canvasHandle)->drawText(jchars + index, 0, count, count, x, y,
- static_cast<minikin::Bidi>(bidiFlags), *paint, typeface, nullptr, 0);
+ static_cast<minikin::Bidi>(bidiFlags), *paint, typeface, nullptr);
env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
}
@@ -496,13 +496,13 @@ static void drawTextString(JNIEnv* env, jobject, jlong canvasHandle, jstring tex
const int count = end - start;
const jchar* jchars = env->GetStringChars(text, NULL);
get_canvas(canvasHandle)->drawText(jchars + start, 0, count, count, x, y,
- static_cast<minikin::Bidi>(bidiFlags), *paint, typeface, nullptr, 0);
+ static_cast<minikin::Bidi>(bidiFlags), *paint, typeface, nullptr);
env->ReleaseStringChars(text, jchars);
}
static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index,
jint count, jint contextIndex, jint contextCount, jfloat x, jfloat y,
- jboolean isRtl, jlong paintHandle, jlong mtHandle, jint mtOffset) {
+ jboolean isRtl, jlong paintHandle, jlong mtHandle) {
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
minikin::MeasuredText* mt = reinterpret_cast<minikin::MeasuredText*>(mtHandle);
const Typeface* typeface = paint->getAndroidTypeface();
@@ -510,8 +510,7 @@ static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArra
const minikin::Bidi bidiFlags = isRtl ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR;
jchar* jchars = env->GetCharArrayElements(text, NULL);
get_canvas(canvasHandle)->drawText(jchars + contextIndex, index - contextIndex, count,
- contextCount, x, y, bidiFlags, *paint, typeface, mt,
- mtOffset);
+ contextCount, x, y, bidiFlags, *paint, typeface, mt);
env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
}
@@ -526,7 +525,7 @@ static void drawTextRunString(JNIEnv* env, jobject obj, jlong canvasHandle, jstr
jint contextCount = contextEnd - contextStart;
const jchar* jchars = env->GetStringChars(text, NULL);
get_canvas(canvasHandle)->drawText(jchars + contextStart, start - contextStart, count,
- contextCount, x, y, bidiFlags, *paint, typeface, nullptr, 0);
+ contextCount, x, y, bidiFlags, *paint, typeface, nullptr);
env->ReleaseStringChars(text, jchars);
}
@@ -640,7 +639,7 @@ static const JNINativeMethod gDrawMethods[] = {
{"nDrawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
{"nDrawText","(J[CIIFFIJ)V", (void*) CanvasJNI::drawTextChars},
{"nDrawText","(JLjava/lang/String;IIFFIJ)V", (void*) CanvasJNI::drawTextString},
- {"nDrawTextRun","(J[CIIIIFFZJJI)V", (void*) CanvasJNI::drawTextRunChars},
+ {"nDrawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
{"nDrawTextRun","(JLjava/lang/String;IIIIFFZJ)V", (void*) CanvasJNI::drawTextRunString},
{"nDrawTextOnPath","(J[CIIJFFIJ)V", (void*) CanvasJNI::drawTextOnPathChars},
{"nDrawTextOnPath","(JLjava/lang/String;JFFIJ)V", (void*) CanvasJNI::drawTextOnPathString},
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index d05be2ca787b..7c8a52d1432b 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -71,6 +71,9 @@ using android::String8;
using android::base::StringPrintf;
using android::base::WriteStringToFile;
+#define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \
+ append(StringPrintf(__VA_ARGS__))
+
static pid_t gSystemServerPid = 0;
static const char kZygoteClassName[] = "com/android/internal/os/Zygote";
@@ -186,30 +189,32 @@ static void UnsetChldSignalHandler() {
// Calls POSIX setgroups() using the int[] object as an argument.
// A NULL argument is tolerated.
-static void SetGids(JNIEnv* env, jintArray javaGids) {
+static bool SetGids(JNIEnv* env, jintArray javaGids, std::string* error_msg) {
if (javaGids == NULL) {
- return;
+ return true;
}
ScopedIntArrayRO gids(env, javaGids);
if (gids.get() == NULL) {
- RuntimeAbort(env, __LINE__, "Getting gids int array failed");
+ *error_msg = CREATE_ERROR("Getting gids int array failed");
+ return false;
}
int rc = setgroups(gids.size(), reinterpret_cast<const gid_t*>(&gids[0]));
if (rc == -1) {
- std::ostringstream oss;
- oss << "setgroups failed: " << strerror(errno) << ", gids.size=" << gids.size();
- RuntimeAbort(env, __LINE__, oss.str().c_str());
+ *error_msg = CREATE_ERROR("setgroups failed: %s, gids.size=%zu", strerror(errno), gids.size());
+ return false;
}
+
+ return true;
}
// Sets the resource limits via setrlimit(2) for the values in the
// two-dimensional array of integers that's passed in. The second dimension
// contains a tuple of length 3: (resource, rlim_cur, rlim_max). NULL is
// treated as an empty array.
-static void SetRLimits(JNIEnv* env, jobjectArray javaRlimits) {
+static bool SetRLimits(JNIEnv* env, jobjectArray javaRlimits, std::string* error_msg) {
if (javaRlimits == NULL) {
- return;
+ return true;
}
rlimit rlim;
@@ -219,7 +224,8 @@ static void SetRLimits(JNIEnv* env, jobjectArray javaRlimits) {
ScopedLocalRef<jobject> javaRlimitObject(env, env->GetObjectArrayElement(javaRlimits, i));
ScopedIntArrayRO javaRlimit(env, reinterpret_cast<jintArray>(javaRlimitObject.get()));
if (javaRlimit.size() != 3) {
- RuntimeAbort(env, __LINE__, "rlimits array must have a second dimension of size 3");
+ *error_msg = CREATE_ERROR("rlimits array must have a second dimension of size 3");
+ return false;
}
rlim.rlim_cur = javaRlimit[1];
@@ -227,11 +233,13 @@ static void SetRLimits(JNIEnv* env, jobjectArray javaRlimits) {
int rc = setrlimit(javaRlimit[0], &rlim);
if (rc == -1) {
- ALOGE("setrlimit(%d, {%ld, %ld}) failed", javaRlimit[0], rlim.rlim_cur,
+ *error_msg = CREATE_ERROR("setrlimit(%d, {%ld, %ld}) failed", javaRlimit[0], rlim.rlim_cur,
rlim.rlim_max);
- RuntimeAbort(env, __LINE__, "setrlimit failed");
+ return false;
}
}
+
+ return true;
}
// The debug malloc library needs to know whether it's the zygote or a child.
@@ -259,14 +267,16 @@ static void SetUpSeccompFilter(uid_t uid) {
}
}
-static void EnableKeepCapabilities(JNIEnv* env) {
+static bool EnableKeepCapabilities(std::string* error_msg) {
int rc = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
if (rc == -1) {
- RuntimeAbort(env, __LINE__, "prctl(PR_SET_KEEPCAPS) failed");
+ *error_msg = CREATE_ERROR("prctl(PR_SET_KEEPCAPS) failed: %s", strerror(errno));
+ return false;
}
+ return true;
}
-static void DropCapabilitiesBoundingSet(JNIEnv* env) {
+static bool DropCapabilitiesBoundingSet(std::string* error_msg) {
for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
int rc = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
if (rc == -1) {
@@ -274,14 +284,15 @@ static void DropCapabilitiesBoundingSet(JNIEnv* env) {
ALOGE("prctl(PR_CAPBSET_DROP) failed with EINVAL. Please verify "
"your kernel is compiled with file capabilities support");
} else {
- ALOGE("prctl(PR_CAPBSET_DROP, %d) failed: %s", i, strerror(errno));
- RuntimeAbort(env, __LINE__, "prctl(PR_CAPBSET_DROP) failed");
+ *error_msg = CREATE_ERROR("prctl(PR_CAPBSET_DROP, %d) failed: %s", i, strerror(errno));
+ return false;
}
}
}
+ return true;
}
-static void SetInheritable(JNIEnv* env, uint64_t inheritable) {
+static bool SetInheritable(uint64_t inheritable, std::string* error_msg) {
__user_cap_header_struct capheader;
memset(&capheader, 0, sizeof(capheader));
capheader.version = _LINUX_CAPABILITY_VERSION_3;
@@ -289,21 +300,23 @@ static void SetInheritable(JNIEnv* env, uint64_t inheritable) {
__user_cap_data_struct capdata[2];
if (capget(&capheader, &capdata[0]) == -1) {
- ALOGE("capget failed: %s", strerror(errno));
- RuntimeAbort(env, __LINE__, "capget failed");
+ *error_msg = CREATE_ERROR("capget failed: %s", strerror(errno));
+ return false;
}
capdata[0].inheritable = inheritable;
capdata[1].inheritable = inheritable >> 32;
if (capset(&capheader, &capdata[0]) == -1) {
- ALOGE("capset(inh=%" PRIx64 ") failed: %s", inheritable, strerror(errno));
- RuntimeAbort(env, __LINE__, "capset failed");
+ *error_msg = CREATE_ERROR("capset(inh=%" PRIx64 ") failed: %s", inheritable, strerror(errno));
+ return false;
}
+
+ return true;
}
-static void SetCapabilities(JNIEnv* env, uint64_t permitted, uint64_t effective,
- uint64_t inheritable) {
+static bool SetCapabilities(uint64_t permitted, uint64_t effective, uint64_t inheritable,
+ std::string* error_msg) {
__user_cap_header_struct capheader;
memset(&capheader, 0, sizeof(capheader));
capheader.version = _LINUX_CAPABILITY_VERSION_3;
@@ -319,18 +332,20 @@ static void SetCapabilities(JNIEnv* env, uint64_t permitted, uint64_t effective,
capdata[1].inheritable = inheritable >> 32;
if (capset(&capheader, &capdata[0]) == -1) {
- ALOGE("capset(perm=%" PRIx64 ", eff=%" PRIx64 ", inh=%" PRIx64 ") failed: %s", permitted,
- effective, inheritable, strerror(errno));
- RuntimeAbort(env, __LINE__, "capset failed");
+ *error_msg = CREATE_ERROR("capset(perm=%" PRIx64 ", eff=%" PRIx64 ", inh=%" PRIx64 ") "
+ "failed: %s", permitted, effective, inheritable, strerror(errno));
+ return false;
}
+ return true;
}
-static void SetSchedulerPolicy(JNIEnv* env) {
+static bool SetSchedulerPolicy(std::string* error_msg) {
errno = -set_sched_policy(0, SP_DEFAULT);
if (errno != 0) {
- ALOGE("set_sched_policy(0, SP_DEFAULT) failed");
- RuntimeAbort(env, __LINE__, "set_sched_policy(0, SP_DEFAULT) failed");
+ *error_msg = CREATE_ERROR("set_sched_policy(0, SP_DEFAULT) failed: %s", strerror(errno));
+ return false;
}
+ return true;
}
static int UnmountTree(const char* path) {
@@ -364,7 +379,7 @@ static int UnmountTree(const char* path) {
// Create a private mount namespace and bind mount appropriate emulated
// storage for the given user.
static bool MountEmulatedStorage(uid_t uid, jint mount_mode,
- bool force_mount_namespace) {
+ bool force_mount_namespace, std::string* error_msg) {
// See storage config details at http://source.android.com/tech/storage/
String8 storageSource;
@@ -381,7 +396,7 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode,
// Create a second private mount namespace for our process
if (unshare(CLONE_NEWNS) == -1) {
- ALOGW("Failed to unshare(): %s", strerror(errno));
+ *error_msg = CREATE_ERROR("Failed to unshare(): %s", strerror(errno));
return false;
}
@@ -392,7 +407,9 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode,
if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage",
NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
- ALOGW("Failed to mount %s to /storage: %s", storageSource.string(), strerror(errno));
+ *error_msg = CREATE_ERROR("Failed to mount %s to /storage: %s",
+ storageSource.string(),
+ strerror(errno));
return false;
}
@@ -400,11 +417,14 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode,
userid_t user_id = multiuser_get_user_id(uid);
const String8 userSource(String8::format("/mnt/user/%d", user_id));
if (fs_prepare_dir(userSource.string(), 0751, 0, 0) == -1) {
+ *error_msg = CREATE_ERROR("fs_prepare_dir failed on %s", userSource.string());
return false;
}
if (TEMP_FAILURE_RETRY(mount(userSource.string(), "/storage/self",
NULL, MS_BIND, NULL)) == -1) {
- ALOGW("Failed to mount %s to /storage/self: %s", userSource.string(), strerror(errno));
+ *error_msg = CREATE_ERROR("Failed to mount %s to /storage/self: %s",
+ userSource.string(),
+ strerror(errno));
return false;
}
@@ -436,31 +456,32 @@ static bool NeedsNoRandomizeWorkaround() {
// descriptor (if any) is closed via dup2(), replacing it with a valid
// (open) descriptor to /dev/null.
-static void DetachDescriptors(JNIEnv* env, jintArray fdsToClose) {
+static bool DetachDescriptors(JNIEnv* env, jintArray fdsToClose, std::string* error_msg) {
if (!fdsToClose) {
- return;
+ return true;
}
jsize count = env->GetArrayLength(fdsToClose);
ScopedIntArrayRO ar(env, fdsToClose);
if (ar.get() == NULL) {
- RuntimeAbort(env, __LINE__, "Bad fd array");
+ *error_msg = "Bad fd array";
+ return false;
}
jsize i;
int devnull;
for (i = 0; i < count; i++) {
devnull = open("/dev/null", O_RDWR);
if (devnull < 0) {
- ALOGE("Failed to open /dev/null: %s", strerror(errno));
- RuntimeAbort(env, __LINE__, "Failed to open /dev/null");
- continue;
+ *error_msg = std::string("Failed to open /dev/null: ").append(strerror(errno));
+ return false;
}
ALOGV("Switching descriptor %d to /dev/null: %s", ar[i], strerror(errno));
if (dup2(devnull, ar[i]) < 0) {
- ALOGE("Failed dup2() on descriptor %d: %s", ar[i], strerror(errno));
- RuntimeAbort(env, __LINE__, "Failed dup2()");
+ *error_msg = StringPrintf("Failed dup2() on descriptor %d: %s", ar[i], strerror(errno));
+ return false;
}
close(devnull);
}
+ return true;
}
void SetThreadName(const char* thread_name) {
@@ -495,20 +516,23 @@ void SetThreadName(const char* thread_name) {
// The list of open zygote file descriptors.
static FileDescriptorTable* gOpenFdTable = NULL;
-static void FillFileDescriptorVector(JNIEnv* env,
+static bool FillFileDescriptorVector(JNIEnv* env,
jintArray java_fds,
- std::vector<int>* fds) {
+ std::vector<int>* fds,
+ std::string* error_msg) {
CHECK(fds != nullptr);
if (java_fds != nullptr) {
ScopedIntArrayRO ar(env, java_fds);
if (ar.get() == nullptr) {
- RuntimeAbort(env, __LINE__, "Bad fd array");
+ *error_msg = "Bad fd array";
+ return false;
}
fds->reserve(ar.size());
for (size_t i = 0; i < ar.size(); ++i) {
fds->push_back(ar[i]);
}
}
+ return true;
}
// Utility routine to fork zygote and specialize the child process.
@@ -526,32 +550,53 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
sigemptyset(&sigchld);
sigaddset(&sigchld, SIGCHLD);
+ auto fail_fn = [env, java_se_name, is_system_server](const std::string& msg)
+ __attribute__ ((noreturn)) {
+ const char* se_name_c_str = nullptr;
+ std::unique_ptr<ScopedUtfChars> se_name;
+ if (java_se_name != nullptr) {
+ se_name.reset(new ScopedUtfChars(env, java_se_name));
+ se_name_c_str = se_name->c_str();
+ }
+ if (se_name_c_str == nullptr && is_system_server) {
+ se_name_c_str = "system_server";
+ }
+ const std::string& error_msg = (se_name_c_str == nullptr)
+ ? msg
+ : StringPrintf("(%s) %s", se_name_c_str, msg.c_str());
+ env->FatalError(error_msg.c_str());
+ __builtin_unreachable();
+ };
+
// Temporarily block SIGCHLD during forks. The SIGCHLD handler might
// log, which would result in the logging FDs we close being reopened.
// This would cause failures because the FDs are not whitelisted.
//
// Note that the zygote process is single threaded at this point.
if (sigprocmask(SIG_BLOCK, &sigchld, nullptr) == -1) {
- ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
- RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_BLOCK, { SIGCHLD }) failed.");
+ fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
}
// Close any logging related FDs before we start evaluating the list of
// file descriptors.
__android_log_close();
+ std::string error_msg;
+
// If this is the first fork for this zygote, create the open FD table.
// If it isn't, we just need to check whether the list of open files has
// changed (and it shouldn't in the normal case).
std::vector<int> fds_to_ignore;
- FillFileDescriptorVector(env, fdsToIgnore, &fds_to_ignore);
+ if (!FillFileDescriptorVector(env, fdsToIgnore, &fds_to_ignore, &error_msg)) {
+ fail_fn(error_msg);
+ }
if (gOpenFdTable == NULL) {
- gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore);
+ gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, &error_msg);
if (gOpenFdTable == NULL) {
- RuntimeAbort(env, __LINE__, "Unable to construct file descriptor table.");
+ fail_fn(error_msg);
}
- } else if (!gOpenFdTable->Restat(fds_to_ignore)) {
- RuntimeAbort(env, __LINE__, "Unable to restat file descriptor table.");
+ } else if (!gOpenFdTable->Restat(fds_to_ignore, &error_msg)) {
+ fail_fn(error_msg);
}
pid_t pid = fork();
@@ -560,17 +605,18 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
PreApplicationInit();
// Clean up any descriptors which must be closed immediately
- DetachDescriptors(env, fdsToClose);
+ if (!DetachDescriptors(env, fdsToClose, &error_msg)) {
+ fail_fn(error_msg);
+ }
// Re-open all remaining open file descriptors so that they aren't shared
// with the zygote across a fork.
- if (!gOpenFdTable->ReopenOrDetach()) {
- RuntimeAbort(env, __LINE__, "Unable to reopen whitelisted descriptors.");
+ if (!gOpenFdTable->ReopenOrDetach(&error_msg)) {
+ fail_fn(error_msg);
}
if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
- ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
- RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed.");
+ fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
}
// Must be called when the new process still has CAP_SYS_ADMIN. The other alternative is to
@@ -580,11 +626,17 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
// Keep capabilities across UID change, unless we're staying root.
if (uid != 0) {
- EnableKeepCapabilities(env);
+ if (!EnableKeepCapabilities(&error_msg)) {
+ fail_fn(error_msg);
+ }
}
- SetInheritable(env, permittedCapabilities);
- DropCapabilitiesBoundingSet(env);
+ if (!SetInheritable(permittedCapabilities, &error_msg)) {
+ fail_fn(error_msg);
+ }
+ if (!DropCapabilitiesBoundingSet(&error_msg)) {
+ fail_fn(error_msg);
+ }
bool use_native_bridge = !is_system_server && (instructionSet != NULL)
&& android::NativeBridgeAvailable();
@@ -601,8 +653,8 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
ALOGW("Native bridge will not be used because dataDir == NULL.");
}
- if (!MountEmulatedStorage(uid, mount_external, use_native_bridge)) {
- ALOGW("Failed to mount emulated storage: %s", strerror(errno));
+ if (!MountEmulatedStorage(uid, mount_external, use_native_bridge, &error_msg)) {
+ ALOGW("Failed to mount emulated storage: %s (%s)", error_msg.c_str(), strerror(errno));
if (errno == ENOTCONN || errno == EROFS) {
// When device is actively encrypting, we get ENOTCONN here
// since FUSE was mounted before the framework restarted.
@@ -610,7 +662,7 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
// FUSE hasn't been created yet by init.
// In either case, continue without external storage.
} else {
- RuntimeAbort(env, __LINE__, "Cannot continue without emulated storage");
+ fail_fn(error_msg);
}
}
@@ -625,9 +677,14 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
}
}
- SetGids(env, javaGids);
+ std::string error_msg;
+ if (!SetGids(env, javaGids, &error_msg)) {
+ fail_fn(error_msg);
+ }
- SetRLimits(env, javaRlimits);
+ if (!SetRLimits(env, javaRlimits, &error_msg)) {
+ fail_fn(error_msg);
+ }
if (use_native_bridge) {
ScopedUtfChars isa_string(env, instructionSet);
@@ -637,14 +694,12 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
int rc = setresgid(gid, gid, gid);
if (rc == -1) {
- ALOGE("setresgid(%d) failed: %s", gid, strerror(errno));
- RuntimeAbort(env, __LINE__, "setresgid failed");
+ fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno)));
}
rc = setresuid(uid, uid, uid);
if (rc == -1) {
- ALOGE("setresuid(%d) failed: %s", uid, strerror(errno));
- RuntimeAbort(env, __LINE__, "setresuid failed");
+ fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno)));
}
if (NeedsNoRandomizeWorkaround()) {
@@ -656,9 +711,14 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
}
}
- SetCapabilities(env, permittedCapabilities, effectiveCapabilities, permittedCapabilities);
+ if (!SetCapabilities(permittedCapabilities, effectiveCapabilities, permittedCapabilities,
+ &error_msg)) {
+ fail_fn(error_msg);
+ }
- SetSchedulerPolicy(env);
+ if (!SetSchedulerPolicy(&error_msg)) {
+ fail_fn(error_msg);
+ }
const char* se_info_c_str = NULL;
ScopedUtfChars* se_info = NULL;
@@ -666,7 +726,7 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
se_info = new ScopedUtfChars(env, java_se_info);
se_info_c_str = se_info->c_str();
if (se_info_c_str == NULL) {
- RuntimeAbort(env, __LINE__, "se_info_c_str == NULL");
+ fail_fn("se_info_c_str == NULL");
}
}
const char* se_name_c_str = NULL;
@@ -675,14 +735,13 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
se_name = new ScopedUtfChars(env, java_se_name);
se_name_c_str = se_name->c_str();
if (se_name_c_str == NULL) {
- RuntimeAbort(env, __LINE__, "se_name_c_str == NULL");
+ fail_fn("se_name_c_str == NULL");
}
}
rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
if (rc == -1) {
- ALOGE("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
- is_system_server, se_info_c_str, se_name_c_str);
- RuntimeAbort(env, __LINE__, "selinux_android_setcontext failed");
+ fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
+ is_system_server, se_info_c_str, se_name_c_str));
}
// Make it easier to debug audit logs by setting the main thread's name to the
@@ -703,15 +762,14 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
is_system_server, is_child_zygote, instructionSet);
if (env->ExceptionCheck()) {
- RuntimeAbort(env, __LINE__, "Error calling post fork hooks.");
+ fail_fn("Error calling post fork hooks.");
}
} else if (pid > 0) {
// the parent process
// We blocked SIGCHLD prior to a fork, we unblock it here.
if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
- ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
- RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed.");
+ fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
}
}
return pid;
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 2e6058268115..c5904e0e9e5e 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -123,14 +123,57 @@ FileDescriptorWhitelist::FileDescriptorWhitelist()
FileDescriptorWhitelist* FileDescriptorWhitelist::instance_ = nullptr;
+// Keeps track of all relevant information (flags, offset etc.) of an
+// open zygote file descriptor.
+class FileDescriptorInfo {
+ public:
+ // Create a FileDescriptorInfo for a given file descriptor. Returns
+ // |NULL| if an error occurred.
+ static FileDescriptorInfo* CreateFromFd(int fd, std::string* error_msg);
+
+ // Checks whether the file descriptor associated with this object
+ // refers to the same description.
+ bool Restat() const;
+
+ bool ReopenOrDetach(std::string* error_msg) const;
+
+ const int fd;
+ const struct stat stat;
+ const std::string file_path;
+ const int open_flags;
+ const int fd_flags;
+ const int fs_flags;
+ const off_t offset;
+ const bool is_sock;
+
+ private:
+ FileDescriptorInfo(int fd);
+
+ FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags,
+ int fd_flags, int fs_flags, off_t offset);
+
+ // Returns the locally-bound name of the socket |fd|. Returns true
+ // iff. all of the following hold :
+ //
+ // - the socket's sa_family is AF_UNIX.
+ // - the length of the path is greater than zero (i.e, not an unnamed socket).
+ // - the first byte of the path isn't zero (i.e, not a socket with an abstract
+ // address).
+ static bool GetSocketName(const int fd, std::string* result);
+
+ bool DetachSocket(std::string* error_msg) const;
+
+ DISALLOW_COPY_AND_ASSIGN(FileDescriptorInfo);
+};
+
// static
-FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) {
+FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, std::string* error_msg) {
struct stat f_stat;
// This should never happen; the zygote should always have the right set
// of permissions required to stat all its open files.
if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
- PLOG(ERROR) << "Unable to stat fd " << fd;
- return NULL;
+ *error_msg = android::base::StringPrintf("Unable to stat %d", fd);
+ return nullptr;
}
const FileDescriptorWhitelist* whitelist = FileDescriptorWhitelist::Get();
@@ -138,13 +181,15 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) {
if (S_ISSOCK(f_stat.st_mode)) {
std::string socket_name;
if (!GetSocketName(fd, &socket_name)) {
- return NULL;
+ *error_msg = "Unable to get socket name";
+ return nullptr;
}
if (!whitelist->IsAllowed(socket_name)) {
- LOG(ERROR) << "Socket name not whitelisted : " << socket_name
- << " (fd=" << fd << ")";
- return NULL;
+ *error_msg = android::base::StringPrintf("Socket name not whitelisted : %s (fd=%d)",
+ socket_name.c_str(),
+ fd);
+ return nullptr;
}
return new FileDescriptorInfo(fd);
@@ -161,19 +206,22 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) {
// with the child process across forks but those should have been closed
// before we got to this point.
if (!S_ISCHR(f_stat.st_mode) && !S_ISREG(f_stat.st_mode)) {
- LOG(ERROR) << "Unsupported st_mode " << f_stat.st_mode;
- return NULL;
+ *error_msg = android::base::StringPrintf("Unsupported st_mode %u", f_stat.st_mode);
+ return nullptr;
}
std::string file_path;
const std::string fd_path = android::base::StringPrintf("/proc/self/fd/%d", fd);
if (!android::base::Readlink(fd_path, &file_path)) {
- return NULL;
+ *error_msg = android::base::StringPrintf("Could not read fd link %s: %s",
+ fd_path.c_str(),
+ strerror(errno));
+ return nullptr;
}
if (!whitelist->IsAllowed(file_path)) {
- LOG(ERROR) << "Not whitelisted : " << file_path;
- return NULL;
+ *error_msg = std::string("Not whitelisted : ").append(file_path);
+ return nullptr;
}
// File descriptor flags : currently on FD_CLOEXEC. We can set these
@@ -181,8 +229,11 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) {
// there won't be any races.
const int fd_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD));
if (fd_flags == -1) {
- PLOG(ERROR) << "Failed fcntl(" << fd << ", F_GETFD)";
- return NULL;
+ *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_GETFD) (%s): %s",
+ fd,
+ file_path.c_str(),
+ strerror(errno));
+ return nullptr;
}
// File status flags :
@@ -199,8 +250,11 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) {
// their presence and pass them in to open().
int fs_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL));
if (fs_flags == -1) {
- PLOG(ERROR) << "Failed fcntl(" << fd << ", F_GETFL)";
- return NULL;
+ *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_GETFL) (%s): %s",
+ fd,
+ file_path.c_str(),
+ strerror(errno));
+ return nullptr;
}
// File offset : Ignore the offset for non seekable files.
@@ -225,9 +279,9 @@ bool FileDescriptorInfo::Restat() const {
return f_stat.st_ino == stat.st_ino && f_stat.st_dev == stat.st_dev;
}
-bool FileDescriptorInfo::ReopenOrDetach() const {
+bool FileDescriptorInfo::ReopenOrDetach(std::string* error_msg) const {
if (is_sock) {
- return DetachSocket();
+ return DetachSocket(error_msg);
}
// NOTE: This might happen if the file was unlinked after being opened.
@@ -236,31 +290,49 @@ bool FileDescriptorInfo::ReopenOrDetach() const {
const int new_fd = TEMP_FAILURE_RETRY(open(file_path.c_str(), open_flags));
if (new_fd == -1) {
- PLOG(ERROR) << "Failed open(" << file_path << ", " << open_flags << ")";
+ *error_msg = android::base::StringPrintf("Failed open(%s, %i): %s",
+ file_path.c_str(),
+ open_flags,
+ strerror(errno));
return false;
}
if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFD, fd_flags)) == -1) {
close(new_fd);
- PLOG(ERROR) << "Failed fcntl(" << new_fd << ", F_SETFD, " << fd_flags << ")";
+ *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_SETFD, %d) (%s): %s",
+ new_fd,
+ fd_flags,
+ file_path.c_str(),
+ strerror(errno));
return false;
}
if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFL, fs_flags)) == -1) {
close(new_fd);
- PLOG(ERROR) << "Failed fcntl(" << new_fd << ", F_SETFL, " << fs_flags << ")";
+ *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_SETFL, %d) (%s): %s",
+ new_fd,
+ fs_flags,
+ file_path.c_str(),
+ strerror(errno));
return false;
}
if (offset != -1 && TEMP_FAILURE_RETRY(lseek64(new_fd, offset, SEEK_SET)) == -1) {
close(new_fd);
- PLOG(ERROR) << "Failed lseek64(" << new_fd << ", SEEK_SET)";
+ *error_msg = android::base::StringPrintf("Failed lseek64(%d, SEEK_SET) (%s): %s",
+ new_fd,
+ file_path.c_str(),
+ strerror(errno));
return false;
}
if (TEMP_FAILURE_RETRY(dup2(new_fd, fd)) == -1) {
close(new_fd);
- PLOG(ERROR) << "Failed dup2(" << fd << ", " << new_fd << ")";
+ *error_msg = android::base::StringPrintf("Failed dup2(%d, %d) (%s): %s",
+ fd,
+ new_fd,
+ file_path.c_str(),
+ strerror(errno));
return false;
}
@@ -336,20 +408,22 @@ bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) {
return true;
}
-bool FileDescriptorInfo::DetachSocket() const {
+bool FileDescriptorInfo::DetachSocket(std::string* error_msg) const {
const int dev_null_fd = open("/dev/null", O_RDWR);
if (dev_null_fd < 0) {
- PLOG(ERROR) << "Failed to open /dev/null";
+ *error_msg = std::string("Failed to open /dev/null: ").append(strerror(errno));
return false;
}
if (dup2(dev_null_fd, fd) == -1) {
- PLOG(ERROR) << "Failed dup2 on socket descriptor " << fd;
+ *error_msg = android::base::StringPrintf("Failed dup2 on socket descriptor %d: %s",
+ fd,
+ strerror(errno));
return false;
}
if (close(dev_null_fd) == -1) {
- PLOG(ERROR) << "Failed close(" << dev_null_fd << ")";
+ *error_msg = android::base::StringPrintf("Failed close(%d): %s", dev_null_fd, strerror(errno));
return false;
}
@@ -357,11 +431,12 @@ bool FileDescriptorInfo::DetachSocket() const {
}
// static
-FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ignore) {
+FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ignore,
+ std::string* error_msg) {
DIR* d = opendir(kFdPath);
- if (d == NULL) {
- PLOG(ERROR) << "Unable to open directory " << std::string(kFdPath);
- return NULL;
+ if (d == nullptr) {
+ *error_msg = std::string("Unable to open directory ").append(kFdPath);
+ return nullptr;
}
int dir_fd = dirfd(d);
dirent* e;
@@ -377,7 +452,7 @@ FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_
continue;
}
- FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd);
+ FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd, error_msg);
if (info == NULL) {
if (closedir(d) == -1) {
PLOG(ERROR) << "Unable to close directory";
@@ -388,19 +463,21 @@ FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_
}
if (closedir(d) == -1) {
- PLOG(ERROR) << "Unable to close directory";
- return NULL;
+ *error_msg = "Unable to close directory";
+ return nullptr;
}
return new FileDescriptorTable(open_fd_map);
}
-bool FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore) {
+bool FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, std::string* error_msg) {
std::set<int> open_fds;
// First get the list of open descriptors.
DIR* d = opendir(kFdPath);
if (d == NULL) {
- PLOG(ERROR) << "Unable to open directory " << std::string(kFdPath);
+ *error_msg = android::base::StringPrintf("Unable to open directory %s: %s",
+ kFdPath,
+ strerror(errno));
return false;
}
@@ -420,21 +497,21 @@ bool FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore) {
}
if (closedir(d) == -1) {
- PLOG(ERROR) << "Unable to close directory";
+ *error_msg = android::base::StringPrintf("Unable to close directory: %s", strerror(errno));
return false;
}
- return RestatInternal(open_fds);
+ return RestatInternal(open_fds, error_msg);
}
// Reopens all file descriptors that are contained in the table. Returns true
// if all descriptors were successfully re-opened or detached, and false if an
// error occurred.
-bool FileDescriptorTable::ReopenOrDetach() {
+bool FileDescriptorTable::ReopenOrDetach(std::string* error_msg) {
std::unordered_map<int, FileDescriptorInfo*>::const_iterator it;
for (it = open_fd_map_.begin(); it != open_fd_map_.end(); ++it) {
const FileDescriptorInfo* info = it->second;
- if (info == NULL || !info->ReopenOrDetach()) {
+ if (info == NULL || !info->ReopenOrDetach(error_msg)) {
return false;
}
}
@@ -447,7 +524,7 @@ FileDescriptorTable::FileDescriptorTable(
: open_fd_map_(map) {
}
-bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds) {
+bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds, std::string* error_msg) {
bool error = false;
// Iterate through the list of file descriptors we've already recorded
@@ -455,6 +532,8 @@ bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds) {
//
// (a) they continue to be open.
// (b) they refer to the same file.
+ //
+ // We'll only store the last error message.
std::unordered_map<int, FileDescriptorInfo*>::iterator it = open_fd_map_.begin();
while (it != open_fd_map_.end()) {
std::set<int>::const_iterator element = open_fds.find(it->first);
@@ -475,7 +554,7 @@ bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds) {
// The file descriptor refers to a different description. We must
// update our entry in the table.
delete it->second;
- it->second = FileDescriptorInfo::CreateFromFd(*element);
+ it->second = FileDescriptorInfo::CreateFromFd(*element, error_msg);
if (it->second == NULL) {
// The descriptor no longer no longer refers to a whitelisted file.
// We flag an error and remove it from the list of files we're
@@ -510,7 +589,7 @@ bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds) {
std::set<int>::const_iterator it;
for (it = open_fds.begin(); it != open_fds.end(); ++it) {
const int fd = (*it);
- FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd);
+ FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd, error_msg);
if (info == NULL) {
// A newly opened file is not on the whitelist. Flag an error and
// continue.
diff --git a/core/jni/fd_utils.h b/core/jni/fd_utils.h
index a39e387fde6c..a3570d7ed1fb 100644
--- a/core/jni/fd_utils.h
+++ b/core/jni/fd_utils.h
@@ -28,6 +28,8 @@
#include <android-base/macros.h>
+class FileDescriptorInfo;
+
// Whitelist of open paths that the zygote is allowed to keep open.
//
// In addition to the paths listed in kPathWhitelist in file_utils.cpp, and
@@ -66,49 +68,6 @@ class FileDescriptorWhitelist {
DISALLOW_COPY_AND_ASSIGN(FileDescriptorWhitelist);
};
-// Keeps track of all relevant information (flags, offset etc.) of an
-// open zygote file descriptor.
-class FileDescriptorInfo {
- public:
- // Create a FileDescriptorInfo for a given file descriptor. Returns
- // |NULL| if an error occurred.
- static FileDescriptorInfo* CreateFromFd(int fd);
-
- // Checks whether the file descriptor associated with this object
- // refers to the same description.
- bool Restat() const;
-
- bool ReopenOrDetach() const;
-
- const int fd;
- const struct stat stat;
- const std::string file_path;
- const int open_flags;
- const int fd_flags;
- const int fs_flags;
- const off_t offset;
- const bool is_sock;
-
- private:
- FileDescriptorInfo(int fd);
-
- FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags,
- int fd_flags, int fs_flags, off_t offset);
-
- // Returns the locally-bound name of the socket |fd|. Returns true
- // iff. all of the following hold :
- //
- // - the socket's sa_family is AF_UNIX.
- // - the length of the path is greater than zero (i.e, not an unnamed socket).
- // - the first byte of the path isn't zero (i.e, not a socket with an abstract
- // address).
- static bool GetSocketName(const int fd, std::string* result);
-
- bool DetachSocket() const;
-
- DISALLOW_COPY_AND_ASSIGN(FileDescriptorInfo);
-};
-
// A FileDescriptorTable is a collection of FileDescriptorInfo objects
// keyed by their FDs.
class FileDescriptorTable {
@@ -116,19 +75,20 @@ class FileDescriptorTable {
// Creates a new FileDescriptorTable. This function scans
// /proc/self/fd for the list of open file descriptors and collects
// information about them. Returns NULL if an error occurs.
- static FileDescriptorTable* Create(const std::vector<int>& fds_to_ignore);
+ static FileDescriptorTable* Create(const std::vector<int>& fds_to_ignore,
+ std::string* error_msg);
- bool Restat(const std::vector<int>& fds_to_ignore);
+ bool Restat(const std::vector<int>& fds_to_ignore, std::string* error_msg);
// Reopens all file descriptors that are contained in the table. Returns true
// if all descriptors were successfully re-opened or detached, and false if an
// error occurred.
- bool ReopenOrDetach();
+ bool ReopenOrDetach(std::string* error_msg);
private:
FileDescriptorTable(const std::unordered_map<int, FileDescriptorInfo*>& map);
- bool RestatInternal(std::set<int>& open_fds);
+ bool RestatInternal(std::set<int>& open_fds, std::string* error_msg);
static int ParseFd(dirent* e, int dir_fd);
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index 64aa98b1136e..c58de563692b 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -198,7 +198,7 @@ message WakeLockProto {
}
optional .android.os.WakeLockLevelEnum lock_level = 1;
- optional string tag = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
+ optional string tag = 2;
optional WakeLockFlagsProto flags = 3;
optional bool is_disabled = 4;
// Acquire time in ms
diff --git a/core/tests/coretests/BinderProxyCountingTestApp/Android.mk b/core/tests/coretests/BinderProxyCountingTestApp/Android.mk
index c3af6bd123b8..4642694d7b67 100644
--- a/core/tests/coretests/BinderProxyCountingTestApp/Android.mk
+++ b/core/tests/coretests/BinderProxyCountingTestApp/Android.mk
@@ -24,5 +24,6 @@ LOCAL_PACKAGE_NAME := BinderProxyCountingTestApp
LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := platform
+LOCAL_COMPATIBILITY_SUITE := device-tests
include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/BinderProxyCountingTestService/Android.mk b/core/tests/coretests/BinderProxyCountingTestService/Android.mk
index 34016ed633b1..f852c7afeacd 100644
--- a/core/tests/coretests/BinderProxyCountingTestService/Android.mk
+++ b/core/tests/coretests/BinderProxyCountingTestService/Android.mk
@@ -24,5 +24,6 @@ LOCAL_PACKAGE_NAME := BinderProxyCountingTestService
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
+LOCAL_COMPATIBILITY_SUITE := device-tests
include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/BstatsTestApp/Android.mk b/core/tests/coretests/BstatsTestApp/Android.mk
index e04536ba7499..a5872a5e5be9 100644
--- a/core/tests/coretests/BstatsTestApp/Android.mk
+++ b/core/tests/coretests/BstatsTestApp/Android.mk
@@ -30,4 +30,5 @@ LOCAL_CERTIFICATE := platform
LOCAL_DEX_PREOPT := false
LOCAL_PROGUARD_ENABLED := disabled
-include $(BUILD_PACKAGE) \ No newline at end of file
+LOCAL_COMPATIBILITY_SUITE := device-tests
+include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 22a261e35453..73fb7139cbd4 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -383,6 +383,7 @@ public class SettingsBackupTest {
Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE,
Settings.Global.SYS_VDSO,
Settings.Global.SYS_UIDCPUPOWER,
+ Settings.Global.SYS_TRACED,
Settings.Global.FPS_DEVISOR,
Settings.Global.TCP_DEFAULT_INIT_RWND,
Settings.Global.TETHER_DUN_APN,
diff --git a/core/tests/featureflagtests/AndroidTest.xml b/core/tests/featureflagtests/AndroidTest.xml
index 44f9c3e37853..38c048ab061e 100644
--- a/core/tests/featureflagtests/AndroidTest.xml
+++ b/core/tests/featureflagtests/AndroidTest.xml
@@ -15,14 +15,16 @@
limitations under the License.
-->
<configuration description="Runs Frameworks Utility Tests.">
- <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
<option name="test-file-name" value="FrameworksCoreFeatureFlagTests.apk" />
</target_preparer>
- <option name="test-suite-tag" value="apct" />
<option name="test-tag" value="FrameworksCoreFeatureFlagTests" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.frameworks.coretests.featureflagtests" />
- <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
</test>
</configuration>
diff --git a/core/tests/overlaytests/device/AndroidTest.xml b/core/tests/overlaytests/device/AndroidTest.xml
index f06983559830..6507839a4288 100644
--- a/core/tests/overlaytests/device/AndroidTest.xml
+++ b/core/tests/overlaytests/device/AndroidTest.xml
@@ -17,8 +17,10 @@
<configuration description="Test module config for OverlayDeviceTests">
<option name="test-tag" value="OverlayDeviceTests" />
<option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="cleanup-apks" value="true" />
<option name="test-file-name" value="OverlayDeviceTests.apk" />
<option name="test-file-name" value="OverlayDeviceTests_AppOverlayOne.apk" />
<option name="test-file-name" value="OverlayDeviceTests_AppOverlayTwo.apk" />
@@ -42,6 +44,5 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.overlaytest" />
- <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
</test>
</configuration>
diff --git a/core/tests/privacytests/AndroidTest.xml b/core/tests/privacytests/AndroidTest.xml
index a43f48eb6e68..8098c1497865 100644
--- a/core/tests/privacytests/AndroidTest.xml
+++ b/core/tests/privacytests/AndroidTest.xml
@@ -14,12 +14,14 @@
limitations under the License.
-->
<configuration description="Runs Privacy Tests.">
- <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
<option name="test-file-name" value="FrameworksPrivacyLibraryTests.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.frameworks.coretests.privacy" />
- <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
</test>
-</configuration> \ No newline at end of file
+</configuration>
diff --git a/core/tests/utiltests/AndroidTest.xml b/core/tests/utiltests/AndroidTest.xml
index 65bb8decc332..270d7731a974 100644
--- a/core/tests/utiltests/AndroidTest.xml
+++ b/core/tests/utiltests/AndroidTest.xml
@@ -14,14 +14,16 @@
limitations under the License.
-->
<configuration description="Runs Frameworks Utility Tests.">
- <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
<option name="test-file-name" value="FrameworksUtilTests.apk" />
</target_preparer>
- <option name="test-suite-tag" value="apct" />
<option name="test-tag" value="FrameworksUtilTests" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.frameworks.utiltests" />
- <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
</test>
</configuration>
diff --git a/core/tests/webkit/AndroidTest.xml b/core/tests/webkit/AndroidTest.xml
index 78cfa462beeb..4c50b7df3368 100644
--- a/core/tests/webkit/AndroidTest.xml
+++ b/core/tests/webkit/AndroidTest.xml
@@ -14,7 +14,9 @@
limitations under the License.
-->
<configuration description="Runs Frameworks WebView Loading Tests.">
- <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="test-file-name" value="WebViewLoadingTests.apk" />
<option name="test-file-name" value="WebViewLoadingOnDiskTestApk.apk" />
<option name="test-file-name" value="WebViewLoadingFromApkTestApk.apk" />
@@ -24,6 +26,5 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.webkit.tests" />
- <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
</test>
</configuration>
diff --git a/core/tests/webkit/apk_with_native_libs/Android.mk b/core/tests/webkit/apk_with_native_libs/Android.mk
index c51de6a7897e..e18a7e0df175 100644
--- a/core/tests/webkit/apk_with_native_libs/Android.mk
+++ b/core/tests/webkit/apk_with_native_libs/Android.mk
@@ -45,6 +45,7 @@ LOCAL_CFLAGS := $(MY_CFLAGS)
LOCAL_SDK_VERSION := $(MY_SDK_VERSION)
LOCAL_PROGUARD_ENABLED := $(MY_PROGUARD_ENABLED)
LOCAL_MULTILIB := $(MY_MULTILIB)
+LOCAL_COMPATIBILITY_SUITE := device-tests
include $(BUILD_PACKAGE)
@@ -65,5 +66,6 @@ LOCAL_CFLAGS := $(MY_CFLAGS)
LOCAL_SDK_VERSION := $(MY_SDK_VERSION)
LOCAL_PROGUARD_ENABLED := $(MY_PROGUARD_ENABLED)
LOCAL_MULTILIB := $(MY_MULTILIB)
+LOCAL_COMPATIBILITY_SUITE := device-tests
include $(BUILD_PACKAGE)
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index 07df0454362c..5dc446391ec6 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -454,8 +454,7 @@ public abstract class BaseCanvas {
throwIfHasHwBitmapInSwMode(paint);
nDrawTextRun(mNativeCanvasWrapper, text, index, count, contextIndex, contextCount,
- x, y, isRtl, paint.getNativeInstance(), 0 /* measured text */,
- 0 /* measured text offset */);
+ x, y, isRtl, paint.getNativeInstance(), 0 /* measured text */);
}
public void drawTextRun(@NonNull CharSequence text, int start, int end, int contextStart,
@@ -486,19 +485,16 @@ public abstract class BaseCanvas {
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
long measuredTextPtr = 0;
- int measuredTextOffset = 0;
if (text instanceof PrecomputedText) {
PrecomputedText mt = (PrecomputedText) text;
int paraIndex = mt.findParaIndex(start);
if (end <= mt.getParagraphEnd(paraIndex)) {
- // Only suppor the same paragraph.
+ // Only suppor the text in the same paragraph.
measuredTextPtr = mt.getMeasuredParagraph(paraIndex).getNativePtr();
- measuredTextOffset = start - mt.getParagraphStart(paraIndex);
}
}
nDrawTextRun(mNativeCanvasWrapper, buf, start - contextStart, len,
- 0, contextLen, x, y, isRtl, paint.getNativeInstance(),
- measuredTextPtr, measuredTextOffset);
+ 0, contextLen, x, y, isRtl, paint.getNativeInstance(), measuredTextPtr);
TemporaryBuffer.recycle(buf);
}
}
@@ -647,7 +643,7 @@ public abstract class BaseCanvas {
private static native void nDrawTextRun(long nativeCanvas, char[] text, int start, int count,
int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint,
- long nativePrecomputedText, int measuredTextOffset);
+ long nativePrecomputedText);
private static native void nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count,
long nativePath, float hOffset, float vOffset, int bidiFlags, long nativePaint);
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 2b0b22df7edf..40b811d813fd 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -764,6 +764,13 @@ void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& p
void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
const SkPaint& paint, const SkPath& path, size_t start,
size_t end) {
+ // Set align to left for drawing, as we don't want individual
+ // glyphs centered or right-aligned; the offsets take care of
+ // that portion of the alignment.
+ SkPaint paintCopy(paint);
+ paintCopy.setTextAlign(SkPaint::kLeft_Align);
+ SkASSERT(paintCopy.getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
+
const int N = end - start;
SkAutoSTMalloc<1024, uint8_t> storage(N * (sizeof(uint16_t) + sizeof(SkRSXform)));
SkRSXform* xform = (SkRSXform*)storage.get();
@@ -788,7 +795,7 @@ void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset,
xform[i - start].fTy = pos.y() + tan.x() * y - halfWidth * tan.y();
}
- this->asSkCanvas()->drawTextRSXform(glyphs, sizeof(uint16_t) * N, xform, nullptr, paint);
+ this->asSkCanvas()->drawTextRSXform(glyphs, sizeof(uint16_t) * N, xform, nullptr, paintCopy);
}
// ----------------------------------------------------------------------------
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index ad4c8be74d75..20543df85068 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -158,13 +158,13 @@ private:
void Canvas::drawText(const uint16_t* text, int start, int count, int contextCount, float x,
float y, minikin::Bidi bidiFlags, const Paint& origPaint,
- const Typeface* typeface, minikin::MeasuredText* mt, int mtOffset) {
+ const Typeface* typeface, minikin::MeasuredText* mt) {
// minikin may modify the original paint
Paint paint(origPaint);
minikin::Layout layout =
MinikinUtils::doLayout(&paint, bidiFlags, typeface, text, start, count, contextCount,
- mt, mtOffset);
+ mt);
x += MinikinUtils::xOffsetForTextAlign(&paint, layout);
@@ -212,8 +212,7 @@ void Canvas::drawTextOnPath(const uint16_t* text, int count, minikin::Bidi bidiF
const Typeface* typeface) {
Paint paintCopy(paint);
minikin::Layout layout =
- MinikinUtils::doLayout(&paintCopy, bidiFlags, typeface, text, 0, count, count, nullptr,
- 0);
+ MinikinUtils::doLayout(&paintCopy, bidiFlags, typeface, text, 0, count, count, nullptr);
hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path);
// Set align to left for drawing, as we don't want individual
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index fabb8d2e4549..d04bb2e5ad03 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -270,7 +270,7 @@ public:
*/
void drawText(const uint16_t* text, int start, int count, int contextCount, float x, float y,
minikin::Bidi bidiFlags, const Paint& origPaint, const Typeface* typeface,
- minikin::MeasuredText* mt, int mtOffset);
+ minikin::MeasuredText* mt);
void drawTextOnPath(const uint16_t* text, int count, minikin::Bidi bidiFlags,
const SkPath& path, float hOffset, float vOffset, const Paint& paint,
diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp
index a0d000dd2179..5b69bb78101f 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -49,8 +49,7 @@ minikin::MinikinPaint MinikinUtils::prepareMinikinPaint(const Paint* paint,
minikin::Layout MinikinUtils::doLayout(const Paint* paint, minikin::Bidi bidiFlags,
const Typeface* typeface, const uint16_t* buf, size_t start,
- size_t count, size_t bufSize, minikin::MeasuredText* mt,
- int mtOffset) {
+ size_t count, size_t bufSize, minikin::MeasuredText* mt) {
minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
minikin::Layout layout;
@@ -62,15 +61,9 @@ minikin::Layout MinikinUtils::doLayout(const Paint* paint, minikin::Bidi bidiFla
if (mt == nullptr) {
layout.doLayout(textBuf,range, bidiFlags, minikinPaint, startHyphen, endHyphen);
- return layout;
+ } else {
+ mt->buildLayout(textBuf, range, minikinPaint, bidiFlags, startHyphen, endHyphen, &layout);
}
-
- if (mt->buildLayout(textBuf, range, minikinPaint, bidiFlags, mtOffset, startHyphen, endHyphen,
- &layout)) {
- return layout;
- }
-
- layout.doLayout(textBuf, range, bidiFlags, minikinPaint, startHyphen, endHyphen);
return layout;
}
@@ -85,7 +78,8 @@ float MinikinUtils::measureText(const Paint* paint, minikin::Bidi bidiFlags,
const minikin::EndHyphenEdit endHyphen = minikin::endHyphenEdit(hyphenEdit);
return minikin::Layout::measureText(textBuf, range, bidiFlags, minikinPaint, startHyphen,
- endHyphen, advances, nullptr /* extent */);
+ endHyphen, advances, nullptr /* extent */,
+ nullptr /* layout pieces */);
}
bool MinikinUtils::hasVariationSelector(const Typeface* typeface, uint32_t codepoint, uint32_t vs) {
diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h
index 124fe4f81fbe..77dfbb21f7b5 100644
--- a/libs/hwui/hwui/MinikinUtils.h
+++ b/libs/hwui/hwui/MinikinUtils.h
@@ -45,7 +45,7 @@ public:
ANDROID_API static minikin::Layout doLayout(const Paint* paint, minikin::Bidi bidiFlags,
const Typeface* typeface, const uint16_t* buf,
size_t start, size_t count, size_t bufSize,
- minikin::MeasuredText* mt, int mtOffset);
+ minikin::MeasuredText* mt);
ANDROID_API static float measureText(const Paint* paint, minikin::Bidi bidiFlags,
const Typeface* typeface, const uint16_t* buf,
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 25c76eb4db3e..62d78e73ccc0 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -148,31 +148,6 @@ void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
// Recording Canvas draw operations: Bitmaps
// ----------------------------------------------------------------------------
-inline static const SkPaint* bitmapPaint(const SkPaint* origPaint, SkPaint* tmpPaint,
- sk_sp<SkColorFilter> colorSpaceFilter) {
- if ((origPaint && origPaint->isAntiAlias()) || colorSpaceFilter) {
- if (origPaint) {
- *tmpPaint = *origPaint;
- }
-
- if (colorSpaceFilter) {
- if (tmpPaint->getColorFilter()) {
- tmpPaint->setColorFilter(
- SkColorFilter::MakeComposeFilter(tmpPaint->refColorFilter(), colorSpaceFilter));
- } else {
- tmpPaint->setColorFilter(colorSpaceFilter);
- }
- LOG_ALWAYS_FATAL_IF(!tmpPaint->getColorFilter());
- }
-
-
- // disabling AA on bitmap draws matches legacy HWUI behavior
- tmpPaint->setAntiAlias(false);
- return tmpPaint;
- } else {
- return origPaint;
- }
-}
void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
SkPaint tmpPaint;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index 0e5dbdbab078..93807a5476e6 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -88,6 +88,45 @@ private:
* @param height used to calculate recording bounds.
*/
void initDisplayList(uirenderer::RenderNode* renderNode, int width, int height);
+
+ inline static const SkPaint* bitmapPaint(const SkPaint* origPaint, SkPaint* tmpPaint,
+ sk_sp<SkColorFilter> colorSpaceFilter) {
+ bool fixBlending = false;
+ bool fixAA = false;
+ if (origPaint) {
+ // kClear blend mode is drawn as kDstOut on HW for compatibility with Android O and
+ // older.
+ fixBlending = sApiLevel <= 27 && origPaint->getBlendMode() == SkBlendMode::kClear;
+ fixAA = origPaint->isAntiAlias();
+ }
+
+ if (fixBlending || fixAA || colorSpaceFilter) {
+ if (origPaint) {
+ *tmpPaint = *origPaint;
+ }
+
+ if (fixBlending) {
+ tmpPaint->setBlendMode(SkBlendMode::kDstOut);
+ }
+
+ if (colorSpaceFilter) {
+ if (tmpPaint->getColorFilter()) {
+ tmpPaint->setColorFilter(SkColorFilter::MakeComposeFilter(
+ tmpPaint->refColorFilter(), colorSpaceFilter));
+ } else {
+ tmpPaint->setColorFilter(colorSpaceFilter);
+ }
+ LOG_ALWAYS_FATAL_IF(!tmpPaint->getColorFilter());
+ }
+
+ // disabling AA on bitmap draws matches legacy HWUI behavior
+ tmpPaint->setAntiAlias(false);
+ return tmpPaint;
+ } else {
+ return origPaint;
+ }
+ }
+
};
}; // namespace skiapipeline
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 51cf772e8691..b99854e5af07 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -125,7 +125,7 @@ void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint
SkPaint glyphPaint(paint);
glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
canvas->drawText(utf16.get(), 0, strlen(text), strlen(text), x, y, minikin::Bidi::LTR,
- glyphPaint, nullptr, nullptr /* measured text */, 0 /* measured text offset */);
+ glyphPaint, nullptr, nullptr /* measured text */);
}
void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint& paint,
diff --git a/media/OWNERS b/media/OWNERS
index f198f4324fc8..3e9a25e93034 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -4,3 +4,4 @@ lajos@google.com
marcone@google.com
sungsoo@google.com
wjia@google.com
+jaewan@google.com
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
index b51c662539cf..40be018dc2c6 100644
--- a/media/java/android/media/MediaController2.java
+++ b/media/java/android/media/MediaController2.java
@@ -836,20 +836,30 @@ public class MediaController2 implements AutoCloseable {
}
/**
- * Sets the index of current DataSourceDesc in the play list to be played.
+ * Skips to the item in the playlist.
+ * <p>
+ * This calls {@link MediaPlaylistAgent#skipToPlaylistItem(MediaItem2)}.
*
- * @param item the index of DataSourceDesc in the play list you want to play
- * @throws IllegalArgumentException if the play list is null
- * @throws NullPointerException if index is outside play list range
+ * @param item The item in the playlist you want to play
*/
public void skipToPlaylistItem(@NonNull MediaItem2 item) {
mProvider.skipToPlaylistItem_impl(item);
}
+ /**
+ * Skips to the previous item in the playlist.
+ * <p>
+ * This calls {@link MediaPlaylistAgent#skipToPreviousItem()}.
+ */
public void skipToPreviousItem() {
mProvider.skipToPreviousItem_impl();
}
+ /**
+ * Skips to the next item in the playlist.
+ * <p>
+ * This calls {@link MediaPlaylistAgent#skipToNextItem()}.
+ */
public void skipToNextItem() {
mProvider.skipToNextItem_impl();
}
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 1c4d898acb4f..030e50d67df9 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -82,7 +82,6 @@ import java.util.Vector;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
-
/**
* @hide
*/
@@ -118,6 +117,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
private AtomicInteger mBufferedPercentageCurrent;
private AtomicInteger mBufferedPercentageNext;
+ private volatile float mVolume = 1.0f;
// Modular DRM
private final Object mDrmLock = new Object();
@@ -553,6 +553,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
addTask(new Task(CALL_COMPLETED_SET_PLAYER_VOLUME, false) {
@Override
void process() {
+ mVolume = volume;
_setVolume(volume, volume);
}
});
@@ -567,8 +568,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
*/
@Override
public float getPlayerVolume() {
- // TODO: get real volume
- return 1.0f;
+ return mVolume;
}
/**
@@ -3227,9 +3227,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
@Override
public void clearMediaPlayer2EventCallback() {
synchronized (mEventCbLock) {
- for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
- mEventCallbackRecords.remove(cb);
- }
+ mEventCallbackRecords.clear();
}
}
@@ -3300,9 +3298,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
@Override
public void clearDrmEventCallback() {
synchronized (mDrmEventCbLock) {
- for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
- mDrmEventCallbackRecords.remove(cb);
- }
+ mDrmEventCallbackRecords.clear();
}
}
diff --git a/media/java/android/media/MediaPlaylistAgent.java b/media/java/android/media/MediaPlaylistAgent.java
index 1d7520ff9f0d..65884743523a 100644
--- a/media/java/android/media/MediaPlaylistAgent.java
+++ b/media/java/android/media/MediaPlaylistAgent.java
@@ -266,10 +266,16 @@ public abstract class MediaPlaylistAgent {
mProvider.skipToPlaylistItem_impl(item);
}
+ /**
+ * Skips to the previous item in the playlist.
+ */
public void skipToPreviousItem() {
mProvider.skipToPreviousItem_impl();
}
+ /**
+ * Skips to the next item in the playlist.
+ */
public void skipToNextItem() {
mProvider.skipToNextItem_impl();
}
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index 91bfacee9789..a7aa3a7fe64c 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -1779,20 +1779,41 @@ public class MediaSession2 implements AutoCloseable {
}
/**
- * Skip to the item in the play list.
+ * Skips to the item in the playlist.
+ * <p>
+ * This calls {@link MediaPlaylistAgent#skipToPlaylistItem(MediaItem2)} and the behavior depends
+ * on the playlist agent implementation, especially with the shuffle/repeat mode.
*
- * @param item item in the play list you want to play
- * @throws IllegalArgumentException if the play list is null
- * @throws NullPointerException if index is outside play list range
+ * @param item The item in the playlist you want to play
+ * @see #getShuffleMode()
+ * @see #getRepeatMode()
*/
public void skipToPlaylistItem(@NonNull MediaItem2 item) {
mProvider.skipToPlaylistItem_impl(item);
}
+ /**
+ * Skips to the previous item.
+ * <p>
+ * This calls {@link MediaPlaylistAgent#skipToPreviousItem()} and the behavior depends on the
+ * playlist agent implementation, especially with the shuffle/repeat mode.
+ *
+ * @see #getShuffleMode()
+ * @see #getRepeatMode()
+ **/
public void skipToPreviousItem() {
mProvider.skipToPreviousItem_impl();
}
+ /**
+ * Skips to the next item.
+ * <p>
+ * This calls {@link MediaPlaylistAgent#skipToNextItem()} and the behavior depends on the
+ * playlist agent implementation, especially with the shuffle/repeat mode.
+ *
+ * @see #getShuffleMode()
+ * @see #getRepeatMode()
+ */
public void skipToNextItem() {
mProvider.skipToNextItem_impl();
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
index 2b6d09f9b72e..70816782541d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
@@ -19,6 +19,7 @@ package com.android.settingslib.fuelgauge;
import android.os.IDeviceIdleController;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.support.annotation.VisibleForTesting;
import android.util.ArraySet;
import android.util.Log;
@@ -37,6 +38,7 @@ public class PowerWhitelistBackend {
private final IDeviceIdleController mDeviceIdleService;
private final ArraySet<String> mWhitelistedApps = new ArraySet<>();
private final ArraySet<String> mSysWhitelistedApps = new ArraySet<>();
+ private final ArraySet<String> mSysWhitelistedAppsExceptIdle = new ArraySet<>();
public PowerWhitelistBackend() {
mDeviceIdleService = IDeviceIdleController.Stub.asInterface(
@@ -62,6 +64,10 @@ public class PowerWhitelistBackend {
return mWhitelistedApps.contains(pkg);
}
+ public boolean isSysWhitelistedExceptIdle(String pkg) {
+ return mSysWhitelistedAppsExceptIdle.contains(pkg);
+ }
+
public void addApp(String pkg) {
try {
mDeviceIdleService.addPowerSaveWhitelistApp(pkg);
@@ -83,6 +89,7 @@ public class PowerWhitelistBackend {
@VisibleForTesting
public void refreshList() {
mSysWhitelistedApps.clear();
+ mSysWhitelistedAppsExceptIdle.clear();
mWhitelistedApps.clear();
try {
String[] whitelistedApps = mDeviceIdleService.getFullPowerWhitelist();
@@ -93,6 +100,11 @@ public class PowerWhitelistBackend {
for (String app : sysWhitelistedApps) {
mSysWhitelistedApps.add(app);
}
+ String[] sysWhitelistedAppsExceptIdle =
+ mDeviceIdleService.getSystemPowerWhitelistExceptIdle();
+ for (String app : sysWhitelistedAppsExceptIdle) {
+ mSysWhitelistedAppsExceptIdle.add(app);
+ }
} catch (RemoteException e) {
Log.w(TAG, "Unable to reach IDeviceIdleController", e);
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
index c6a1428fa34e..5a123af02ca4 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
@@ -48,6 +48,7 @@ public class PowerWhitelistBackendTest {
MockitoAnnotations.initMocks(this);
doReturn(new String[] {}).when(mDeviceIdleService).getFullPowerWhitelist();
doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelist();
+ doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelistExceptIdle();
doNothing().when(mDeviceIdleService).addPowerSaveWhitelistApp(anyString());
doNothing().when(mDeviceIdleService).removePowerSaveWhitelistApp(anyString());
mPowerWhitelistBackend = new PowerWhitelistBackend(mDeviceIdleService);
@@ -88,6 +89,15 @@ public class PowerWhitelistBackendTest {
assertThat(mPowerWhitelistBackend.isSysWhitelisted(PACKAGE_ONE)).isTrue();
assertThat(mPowerWhitelistBackend.isSysWhitelisted(PACKAGE_TWO)).isFalse();
assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isFalse();
+ }
+
+ @Test
+ public void testIsSystemWhitelistedExceptIdle() throws Exception {
+ doReturn(new String[]{PACKAGE_TWO}).when(
+ mDeviceIdleService).getSystemPowerWhitelistExceptIdle();
+ mPowerWhitelistBackend.refreshList();
+ assertThat(mPowerWhitelistBackend.isSysWhitelistedExceptIdle(PACKAGE_ONE)).isFalse();
+ assertThat(mPowerWhitelistBackend.isSysWhitelistedExceptIdle(PACKAGE_TWO)).isTrue();
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index cfcfb95b0f88..4530f8062f0d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -40,6 +40,7 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
@@ -2594,15 +2595,26 @@ class DatabaseHelper extends SQLiteOpenHelper {
loadSetting(stmt, Settings.Global.CALL_AUTO_RETRY, 0);
// Set the preferred network mode to target desired value or Default
- // value defined in RILConstants
- int type;
- type = RILConstants.PREFERRED_NETWORK_MODE;
- loadSetting(stmt, Settings.Global.PREFERRED_NETWORK_MODE, type);
+ // value defined in system property
+ String val = "";
+ String mode;
+ for (int phoneId = 0;
+ phoneId < TelephonyManager.getDefault().getPhoneCount(); phoneId++) {
+ mode = TelephonyManager.getTelephonyProperty(phoneId,
+ "ro.telephony.default_network",
+ Integer.toString(RILConstants.PREFERRED_NETWORK_MODE));
+ if (phoneId == 0) {
+ val = mode;
+ } else {
+ val = val + "," + mode;
+ }
+ }
+ loadSetting(stmt, Settings.Global.PREFERRED_NETWORK_MODE, val);
// Set the preferred cdma subscription source to target desired value or default
// value defined in Phone
- type = SystemProperties.getInt("ro.telephony.default_cdma_sub",
- Phone.PREFERRED_CDMA_SUBSCRIPTION);
+ int type = SystemProperties.getInt("ro.telephony.default_cdma_sub",
+ Phone.PREFERRED_CDMA_SUBSCRIPTION);
loadSetting(stmt, Settings.Global.CDMA_SUBSCRIPTION_MODE, type);
loadIntegerSetting(stmt, Settings.Global.LOW_BATTERY_SOUND_TIMEOUT,
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java
index 6131acc91ca5..aa2fb32f13a8 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java
@@ -16,6 +16,7 @@ package com.android.systemui.plugins.statusbar.phone;
import android.graphics.Canvas;
import android.view.MotionEvent;
+import android.view.View;
import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.annotations.ProvidesInterface;
@@ -42,6 +43,8 @@ public interface NavGesture extends Plugin {
public void onLayout(boolean changed, int left, int top, int right, int bottom);
+ public void onNavigationButtonLongPress(View v);
+
public default void destroy() { }
}
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 814b3efb74ef..2c73f1e97b09 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1062,6 +1062,9 @@
<!-- The text to clear all notifications. [CHAR LIMIT=60] -->
<string name="clear_all_notifications_text">Clear all</string>
+ <!-- The text to show in the notifications shade when dnd is suppressing notifications. [CHAR LIMIT=100] -->
+ <string name="dnd_suppressing_shade_text">Do Not disturb is hiding notifications</string>
+
<!-- Media projection permission dialog action text. [CHAR LIMIT=60] -->
<string name="media_projection_action_text">Start now</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index ef36610b48c6..861244539725 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -80,4 +80,17 @@ oneway interface IOverviewProxy {
* Sent when overview is to be hidden.
*/
void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
+
+ /**
+ * Sent when a user swipes up over the navigation bar to launch overview. Swipe up is determined
+ * by passing the touch slop in the direction towards launcher from navigation bar. During and
+ * after this event is sent the caller will continue to send motion events. The motion
+ * {@param event} passed after the touch slop was exceeded will also be passed after by
+ * {@link onMotionEvent}. Since motion events will be sent, motion up or cancel can still be
+ * sent to cancel overview regardless the current state of launcher (eg. if overview is already
+ * visible, this event will still be sent if user swipes up). When this signal is sent,
+ * navigation bar will not handle any gestures such as quick scrub or switch and the home button
+ * will cancel (long) press.
+ */
+ void onQuickStep(in MotionEvent event);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 846aaddf74de..4799f398fb7a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -36,11 +36,6 @@ interface ISystemUiProxy {
void startScreenPinning(int taskId) = 1;
/**
- * Called when the overview service has started the recents animation.
- */
- void onRecentsAnimationStarted() = 2;
-
- /**
* Specifies the text to be shown for onboarding the new swipe-up gesture to access recents.
*/
void setRecentsOnboardingText(CharSequence text) = 3;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index f0952f9641f2..10ba7f6704de 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -47,12 +47,12 @@ import java.util.HashMap;
import java.util.List;
import java.util.function.Consumer;
-import androidx.app.slice.Slice;
-import androidx.app.slice.SliceItem;
-import androidx.app.slice.core.SliceQuery;
-import androidx.app.slice.widget.ListContent;
-import androidx.app.slice.widget.RowContent;
-import androidx.app.slice.widget.SliceLiveData;
+import androidx.slice.Slice;
+import androidx.slice.SliceItem;
+import androidx.slice.core.SliceQuery;
+import androidx.slice.widget.ListContent;
+import androidx.slice.widget.RowContent;
+import androidx.slice.widget.SliceLiveData;
/**
* View visible under the clock on the lock screen and AoD.
@@ -117,7 +117,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
private void showSlice(Slice slice) {
- ListContent lc = new ListContent(slice);
+ ListContent lc = new ListContent(getContext(), slice);
mHasHeader = lc.hasHeader();
List<SliceItem> subItems = lc.getRowItems();
if (!mHasHeader) {
@@ -125,7 +125,8 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
} else {
mTitle.setVisibility(VISIBLE);
// If there's a header it'll be the first subitem
- RowContent header = new RowContent(subItems.get(0), true /* showStartItem */);
+ RowContent header = new RowContent(getContext(), subItems.get(0),
+ true /* showStartItem */);
SliceItem mainTitle = header.getTitleItem();
CharSequence title = mainTitle != null ? mainTitle.getText() : null;
mTitle.setText(title);
@@ -149,7 +150,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
final int startIndex = mHasHeader ? 1 : 0; // First item is header; skip it
for (int i = startIndex; i < subItemsCount; i++) {
SliceItem item = subItems.get(i);
- RowContent rc = new RowContent(item, true /* showStartItem */);
+ RowContent rc = new RowContent(getContext(), item, true /* showStartItem */);
final Uri itemTag = item.getSlice().getUri();
// Try to reuse the view if already exists in the layout
KeyguardSliceButton button = mRow.findViewWithTag(itemTag);
@@ -182,6 +183,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
}
button.setCompoundDrawables(iconDrawable, null, null, null);
button.setOnClickListener(this);
+ button.setClickable(pendingIntent != null);
}
// Removing old views
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index 041af0e47119..a4af6b26a854 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -102,15 +102,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
}
}
- public void onRecentsAnimationStarted() {
- long token = Binder.clearCallingIdentity();
- try {
- mHandler.post(OverviewProxyService.this::notifyRecentsAnimationStarted);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
public void onSplitScreenInvoked() {
long token = Binder.clearCallingIdentity();
try {
@@ -283,9 +274,9 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
}
}
- private void notifyRecentsAnimationStarted() {
+ public void notifyQuickStepStarted() {
for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
- mConnectionCallbacks.get(i).onRecentsAnimationStarted();
+ mConnectionCallbacks.get(i).onQuickStepStarted();
}
}
@@ -300,7 +291,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
public interface OverviewProxyListener {
default void onConnectionChanged(boolean isConnected) {}
- default void onRecentsAnimationStarted() {}
+ default void onQuickStepStarted() {}
default void onInteractionFlagsChanged(@InteractionType int flags) {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 4d54bdd2225c..9a20c81c4919 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -239,10 +239,13 @@ public class ScreenDecorations extends SystemUI implements Tunable {
| WindowManager.LayoutParams.FLAG_SLIPPERY
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT);
- lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS
+ | WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+
if (!DEBUG_SCREENSHOT_ROUNDED_CORNERS) {
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
}
+
lp.setTitle("ScreenDecorOverlay");
lp.gravity = Gravity.TOP | Gravity.LEFT;
lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
@@ -385,6 +388,7 @@ public class ScreenDecorations extends SystemUI implements Tunable {
mBounds.set(mInfo.displayCutout.getBounds());
localBounds(mBoundingRect);
mInfo.displayCutout.getBounds().getBoundaryPath(mBoundingPath);
+ invalidate();
newVisible = VISIBLE;
} else {
newVisible = GONE;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 26618bff4db7..d81b32b162b7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -40,10 +40,10 @@ import java.util.Date;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
-import androidx.app.slice.Slice;
-import androidx.app.slice.SliceProvider;
-import androidx.app.slice.builders.ListBuilder;
-import androidx.app.slice.builders.ListBuilder.RowBuilder;
+import androidx.slice.Slice;
+import androidx.slice.SliceProvider;
+import androidx.slice.builders.ListBuilder;
+import androidx.slice.builders.ListBuilder.RowBuilder;
/**
* Simple Slice provider that shows the current date.
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 0486a9dcca74..a4927b7704c5 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -63,7 +63,6 @@ import android.util.Pair;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
-import android.view.View.OnTouchListener;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowManager.LayoutParams;
@@ -551,7 +550,6 @@ public class PipMenuActivity extends Activity {
alpha = (int) (interpolatedAlpha * 255);
} else {
if (mMenuState == MENU_STATE_CLOSE) {
- mSettingsButton.setAlpha(menuAlpha);
mDismissButton.setAlpha(menuAlpha);
}
alpha = (int) (fraction * DISMISS_BACKGROUND_ALPHA * 255);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index d9359a43d8a8..c348187115f0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -189,7 +189,7 @@ public class RecentsOnboarding {
}
}
- public void onRecentsAnimationStarted() {
+ public void onQuickStepStarted() {
boolean alreadySeenRecentsOnboarding = Prefs.getBoolean(mContext,
Prefs.Key.HAS_SEEN_RECENTS_ONBOARDING, false);
if (!alreadySeenRecentsOnboarding) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
index 58adde269758..3698c3a0038d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar;
import android.annotation.ColorInt;
+import android.annotation.StringRes;
import android.content.Context;
import android.content.res.Configuration;
import android.util.AttributeSet;
@@ -30,6 +31,7 @@ import com.android.systemui.statusbar.stack.StackScrollState;
public class EmptyShadeView extends StackScrollerDecorView {
private TextView mEmptyText;
+ private @StringRes int mText = R.string.empty_shade_text;
public EmptyShadeView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -38,7 +40,7 @@ public class EmptyShadeView extends StackScrollerDecorView {
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- mEmptyText.setText(R.string.empty_shade_text);
+ mEmptyText.setText(mText);
}
@Override
@@ -50,6 +52,11 @@ public class EmptyShadeView extends StackScrollerDecorView {
mEmptyText.setTextColor(color);
}
+ public void setText(@StringRes int text) {
+ mText = text;
+ mEmptyText.setText(mText);
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 9fa06f77fe9e..c5781d9a46c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -175,8 +175,8 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
}
@Override
- public void onRecentsAnimationStarted() {
- mNavigationBarView.setRecentsAnimationStarted(true);
+ public void onQuickStepStarted() {
+ mNavigationBarView.onQuickStepStarted();
// Use navbar dragging as a signal to hide the rotate button
setRotateSuggestionButtonState(false);
@@ -343,10 +343,19 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
boolean showImeSwitcher) {
boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
int hints = mNavigationIconHints;
- if (imeShown && backDisposition != InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS) {
- hints |= NAVIGATION_HINT_BACK_ALT;
- } else {
- hints &= ~NAVIGATION_HINT_BACK_ALT;
+ switch (backDisposition) {
+ case InputMethodService.BACK_DISPOSITION_DEFAULT:
+ case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS:
+ case InputMethodService.BACK_DISPOSITION_WILL_DISMISS:
+ if (imeShown) {
+ hints |= NAVIGATION_HINT_BACK_ALT;
+ } else {
+ hints &= ~NAVIGATION_HINT_BACK_ALT;
+ }
+ break;
+ case InputMethodService.BACK_DISPOSITION_ADJUST_NOTHING:
+ hints &= ~NAVIGATION_HINT_BACK_ALT;
+ break;
}
if (showImeSwitcher) {
hints |= NAVIGATION_HINT_IME_SHOWN;
@@ -751,6 +760,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
if (shouldDisableNavbarGestures()) {
return false;
}
+ mNavigationBarView.onNavigationButtonLongPress(v);
mMetricsLogger.action(MetricsEvent.ACTION_ASSIST_LONG_PRESS);
mAssistManager.startAssist(new Bundle() /* args */);
mStatusBar.awakenDreams();
@@ -787,10 +797,12 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
}
private boolean onLongPressBackHome(View v) {
+ mNavigationBarView.onNavigationButtonLongPress(v);
return onLongPressNavigationButtons(v, R.id.back, R.id.home);
}
private boolean onLongPressBackRecents(View v) {
+ mNavigationBarView.onNavigationButtonLongPress(v);
return onLongPressNavigationButtons(v, R.id.back, R.id.recent_apps);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 6a1ed51e85b4..cd000fe4ba70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -19,31 +19,22 @@ package com.android.systemui.statusbar.phone;
import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_TOP;
-import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
-import static com.android.systemui.OverviewProxyService.TAG_OPS;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
-import android.graphics.Matrix;
import android.graphics.Rect;
-import android.os.RemoteException;
-import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.systemui.Dependency;
-import com.android.systemui.OverviewProxyService;
-import com.android.systemui.OverviewProxyService.OverviewProxyListener;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
-import com.android.systemui.shared.recents.IOverviewProxy;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.tuner.TunerService;
@@ -75,25 +66,14 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture
private NavigationBarView mNavigationBarView;
private boolean mIsVertical;
- private final QuickScrubController mQuickScrubController;
+ private final QuickStepController mQuickStepController;
private final int mScrollTouchSlop;
- private final Matrix mTransformGlobalMatrix = new Matrix();
- private final Matrix mTransformLocalMatrix = new Matrix();
private final StatusBar mStatusBar;
private int mTouchDownX;
private int mTouchDownY;
private boolean mDownOnRecents;
private VelocityTracker mVelocityTracker;
- private OverviewProxyService mOverviewProxyService = Dependency.get(OverviewProxyService.class);
- private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
- @Override
- public void onRecentsAnimationStarted() {
- mRecentsAnimationStarted = true;
- mQuickScrubController.setRecentsAnimationStarted(true /* started */);
- }
- };
- private boolean mRecentsAnimationStarted;
private boolean mDockWindowEnabled;
private boolean mDockWindowTouchSlopExceeded;
private int mDragMode;
@@ -103,14 +83,12 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture
mStatusBar = SysUiServiceProvider.getComponent(context, StatusBar.class);
Resources r = context.getResources();
mScrollTouchSlop = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance);
- mQuickScrubController = new QuickScrubController(context);
+ mQuickStepController = new QuickStepController(context);
Dependency.get(TunerService.class).addTunable(this, KEY_DOCK_WINDOW_GESTURE);
- mOverviewProxyService.addCallback(mOverviewProxyListener);
}
public void destroy() {
Dependency.get(TunerService.class).removeTunable(this);
- mOverviewProxyService.removeCallback(mOverviewProxyListener);
}
public void setComponents(RecentsComponent recentsComponent, Divider divider,
@@ -118,65 +96,19 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture
mRecentsComponent = recentsComponent;
mDivider = divider;
mNavigationBarView = navigationBarView;
- mQuickScrubController.setComponents(mNavigationBarView);
+ mQuickStepController.setComponents(mNavigationBarView);
}
public void setBarState(boolean isVertical, boolean isRTL) {
mIsVertical = isVertical;
- mQuickScrubController.setBarState(isVertical, isRTL);
- }
-
- private boolean proxyMotionEvents(MotionEvent event) {
- final IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
- if (overviewProxy != null && mNavigationBarView.isQuickStepSwipeUpEnabled()) {
- mNavigationBarView.requestUnbufferedDispatch(event);
- event.transform(mTransformGlobalMatrix);
- try {
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
- overviewProxy.onPreMotionEvent(mNavigationBarView.getDownHitTarget());
- }
- overviewProxy.onMotionEvent(event);
- if (DEBUG_OVERVIEW_PROXY) {
- Log.d(TAG_OPS, "Send MotionEvent: " + event.toString());
- }
- return true;
- } catch (RemoteException e) {
- Log.e(TAG, "Callback failed", e);
- } finally {
- event.transform(mTransformLocalMatrix);
- }
- }
- return false;
+ mQuickStepController.setBarState(isVertical, isRTL);
}
public boolean onInterceptTouchEvent(MotionEvent event) {
- if (mNavigationBarView.inScreenPinning() || mStatusBar.isKeyguardShowing()
- || !mStatusBar.isPresenterFullyCollapsed()) {
+ if (!canHandleGestures()) {
return false;
}
-
- int action = event.getActionMasked();
- switch (action) {
- case MotionEvent.ACTION_DOWN: {
- mTouchDownX = (int) event.getX();
- mTouchDownY = (int) event.getY();
- mTransformGlobalMatrix.set(Matrix.IDENTITY_MATRIX);
- mTransformLocalMatrix.set(Matrix.IDENTITY_MATRIX);
- mNavigationBarView.transformMatrixToGlobal(mTransformGlobalMatrix);
- mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
- mRecentsAnimationStarted = false;
- mQuickScrubController.setRecentsAnimationStarted(false /* started */);
- break;
- }
- }
- boolean handledByQuickscrub = mQuickScrubController.onInterceptTouchEvent(event);
- if (!handledByQuickscrub) {
- // Proxy motion events until we start intercepting for quickscrub
- proxyMotionEvents(event);
- }
-
- boolean result = handledByQuickscrub;
- result |= mRecentsAnimationStarted;
+ boolean result = mQuickStepController.onInterceptTouchEvent(event);
if (mDockWindowEnabled) {
result |= interceptDockWindowEvent(event);
}
@@ -184,18 +116,10 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture
}
public boolean onTouchEvent(MotionEvent event) {
- if (mNavigationBarView.inScreenPinning() || mStatusBar.isKeyguardShowing()
- || !mStatusBar.isPresenterFullyCollapsed()) {
+ if (!canHandleGestures()) {
return false;
}
-
- // The same down event was just sent on intercept and therefore can be ignored here
- boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN
- && mOverviewProxyService.getProxy() != null;
- boolean result = mQuickScrubController.onTouchEvent(event)
- || ignoreProxyDownEvent
- || proxyMotionEvents(event);
- result |= mRecentsAnimationStarted;
+ boolean result = mQuickStepController.onTouchEvent(event);
if (mDockWindowEnabled) {
result |= handleDockWindowEvent(event);
}
@@ -203,17 +127,19 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture
}
public void onDraw(Canvas canvas) {
- if (mNavigationBarView.isQuickScrubEnabled()) {
- mQuickScrubController.onDraw(canvas);
- }
+ mQuickStepController.onDraw(canvas);
}
public void onLayout(boolean changed, int left, int top, int right, int bottom) {
- mQuickScrubController.onLayout(changed, left, top, right, bottom);
+ mQuickStepController.onLayout(changed, left, top, right, bottom);
}
public void onDarkIntensityChange(float intensity) {
- mQuickScrubController.onDarkIntensityChange(intensity);
+ mQuickStepController.onDarkIntensityChange(intensity);
+ }
+
+ public void onNavigationButtonLongPress(View v) {
+ mQuickStepController.onNavigationButtonLongPress(v);
}
private boolean interceptDockWindowEvent(MotionEvent event) {
@@ -342,6 +268,11 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture
mVelocityTracker = null;
}
+ private boolean canHandleGestures() {
+ return !mNavigationBarView.inScreenPinning() && !mStatusBar.isKeyguardShowing()
+ && mStatusBar.isPresenterFullyCollapsed();
+ }
+
private int calculateDragMode() {
if (mIsVertical && !mDivider.getView().isHorizontalDivision()) {
return DRAG_MODE_DIVIDER;
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 e97fa855e5e7..fcbd37c50f73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -290,18 +290,12 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
notifyVerticalChangedListener(mVertical);
}
- public void setRecentsAnimationStarted(boolean started) {
+ public void onQuickStepStarted() {
if (mRecentsOnboarding != null) {
- mRecentsOnboarding.onRecentsAnimationStarted();
+ mRecentsOnboarding.onQuickStepStarted();
}
}
- public void onConnectionChanged(boolean isConnected) {
- updateSlippery();
- updateNavButtonIcons();
- setUpSwipeUpOnboarding(isConnected);
- }
-
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
@@ -675,6 +669,10 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
}
}
+ public void onNavigationButtonLongPress(View v) {
+ mGestureHelper.onNavigationButtonLongPress(v);
+ }
+
public void onPanelExpandedChange(boolean expanded) {
updateSlippery();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index 00aff53595ff..19544b170d1f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -25,6 +25,7 @@ import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
@@ -55,10 +56,10 @@ import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_
/**
* Class to detect gestures on the navigation bar and implement quick scrub and switch.
*/
-public class QuickScrubController extends GestureDetector.SimpleOnGestureListener implements
+public class QuickStepController extends GestureDetector.SimpleOnGestureListener implements
GestureHelper {
- private static final String TAG = "QuickScrubController";
+ private static final String TAG = "QuickStepController";
private static final int QUICK_SWITCH_FLING_VELOCITY = 0;
private static final int ANIM_DURATION_MS = 200;
private static final long LONG_PRESS_DELAY_MS = 225;
@@ -75,7 +76,8 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
private boolean mDraggingActive;
private boolean mQuickScrubActive;
private boolean mAllowQuickSwitch;
- private boolean mRecentsAnimationStarted;
+ private boolean mAllowGestureDetection;
+ private boolean mQuickStepStarted;
private float mDownOffset;
private float mTranslation;
private int mTouchDownX;
@@ -101,6 +103,8 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
private final ValueAnimator mButtonAnimator;
private final AnimatorSet mQuickScrubEndAnimator;
private final Context mContext;
+ private final Matrix mTransformGlobalMatrix = new Matrix();
+ private final Matrix mTransformLocalMatrix = new Matrix();
private final ArgbEvaluator mTrackColorEvaluator = new ArgbEvaluator();
private final AnimatorUpdateListener mTrackAnimatorListener = valueAnimator -> {
@@ -123,7 +127,6 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
private AnimatorListenerAdapter mQuickScrubEndListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- mNavigationBarView.getHomeButton().setClickable(true);
mQuickScrubActive = false;
mTranslation = 0;
mQuickScrubEndAnimator.setCurrentPlayTime(mQuickScrubEndAnimator.getDuration());
@@ -165,7 +168,7 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
}
};
- public QuickScrubController(Context context) {
+ public QuickStepController(Context context) {
mContext = context;
mScrollTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mOverviewEventSender = Dependency.get(OverviewProxyService.class);
@@ -197,31 +200,35 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- final ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
- if (!mNavigationBarView.isQuickScrubEnabled()) {
- homeButton.setDelayTouchFeedback(false);
- return false;
- }
-
return handleTouchEvent(event);
}
/**
- * @return true if we want to handle touch events for quick scrub/switch and prevent proxying
- * the event to the overview service.
+ * @return true if we want to handle touch events for quick scrub/switch or if down event (that
+ * will get consumed and ignored). No events will be proxied to the overview service.
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
- return handleTouchEvent(event);
+ // The same down event was just sent on intercept and therefore can be ignored here
+ final boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN
+ && mOverviewEventSender.getProxy() != null;
+ return ignoreProxyDownEvent || handleTouchEvent(event);
}
private boolean handleTouchEvent(MotionEvent event) {
- final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
+ if (!mNavigationBarView.isQuickScrubEnabled()
+ && !mNavigationBarView.isQuickStepSwipeUpEnabled()) {
+ mNavigationBarView.getHomeButton().setDelayTouchFeedback(false /* delay */);
+ return false;
+ }
+ mNavigationBarView.requestUnbufferedDispatch(event);
+
final ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
if (mGestureDetector.onTouchEvent(event)) {
// If the fling has been handled on UP, then skip proxying the UP
return true;
}
+ final boolean homePressed = mNavigationBarView.getDownHitTarget() == HIT_TARGET_HOME;
int action = event.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
@@ -232,89 +239,99 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
mQuickScrubEndAnimator.end();
}
mHomeButtonView = homeButton.getCurrentView();
- if (mNavigationBarView.isQuickScrubEnabled()
- && mNavigationBarView.getDownHitTarget() == HIT_TARGET_HOME) {
- mTouchDownX = x;
- mTouchDownY = y;
- homeButton.setDelayTouchFeedback(true);
+ homeButton.setDelayTouchFeedback(true /* delay */);
+ mTouchDownX = x;
+ mTouchDownY = y;
+ if (homePressed) {
mHandler.postDelayed(mLongPressRunnable, LONG_PRESS_DELAY_MS);
- } else {
- homeButton.setDelayTouchFeedback(false);
- mTouchDownX = mTouchDownY = -1;
}
+ mTransformGlobalMatrix.set(Matrix.IDENTITY_MATRIX);
+ mTransformLocalMatrix.set(Matrix.IDENTITY_MATRIX);
+ mNavigationBarView.transformMatrixToGlobal(mTransformGlobalMatrix);
+ mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
+ mQuickStepStarted = false;
mAllowQuickSwitch = true;
+ mAllowGestureDetection = true;
break;
}
case MotionEvent.ACTION_MOVE: {
- if (mTouchDownX != -1) {
- int x = (int) event.getX();
- int y = (int) event.getY();
- int xDiff = Math.abs(x - mTouchDownX);
- int yDiff = Math.abs(y - mTouchDownY);
- boolean exceededTouchSlopX = xDiff > mScrollTouchSlop && xDiff > yDiff;
- boolean exceededTouchSlopY = yDiff > mScrollTouchSlop && yDiff > xDiff;
- boolean exceededTouchSlop, exceededPerpendicularTouchSlop;
- int pos, touchDown, offset, trackSize;
-
- if (mIsVertical) {
- exceededTouchSlop = exceededTouchSlopY;
- exceededPerpendicularTouchSlop = exceededTouchSlopX;
- pos = y;
- touchDown = mTouchDownY;
- offset = pos - mTrackRect.top;
- trackSize = mTrackRect.height();
- } else {
- exceededTouchSlop = exceededTouchSlopX;
- exceededPerpendicularTouchSlop = exceededTouchSlopY;
- pos = x;
- touchDown = mTouchDownX;
- offset = pos - mTrackRect.left;
- trackSize = mTrackRect.width();
- }
- // Do not start scrubbing when dragging in the perpendicular direction if we
- // haven't already started quickscrub
- if (!mDraggingActive && !mQuickScrubActive && exceededPerpendicularTouchSlop) {
- mHandler.removeCallbacksAndMessages(null);
- return false;
- }
- if (!mDragPositive) {
- offset -= mIsVertical ? mTrackRect.height() : mTrackRect.width();
+ if (mQuickStepStarted || !mAllowGestureDetection){
+ break;
+ }
+ int x = (int) event.getX();
+ int y = (int) event.getY();
+ int xDiff = Math.abs(x - mTouchDownX);
+ int yDiff = Math.abs(y - mTouchDownY);
+ boolean exceededTouchSlopX = xDiff > mScrollTouchSlop && xDiff > yDiff;
+ boolean exceededTouchSlopY = yDiff > mScrollTouchSlop && yDiff > xDiff;
+ boolean exceededTouchSlop, exceededPerpendicularTouchSlop;
+ int pos, touchDown, offset, trackSize;
+
+ if (mIsVertical) {
+ exceededTouchSlop = exceededTouchSlopY;
+ exceededPerpendicularTouchSlop = exceededTouchSlopX;
+ pos = y;
+ touchDown = mTouchDownY;
+ offset = pos - mTrackRect.top;
+ trackSize = mTrackRect.height();
+ } else {
+ exceededTouchSlop = exceededTouchSlopX;
+ exceededPerpendicularTouchSlop = exceededTouchSlopY;
+ pos = x;
+ touchDown = mTouchDownX;
+ offset = pos - mTrackRect.left;
+ trackSize = mTrackRect.width();
+ }
+ // Decide to start quickstep if dragging away from the navigation bar, otherwise in
+ // the parallel direction, decide to start quickscrub. Only one may run.
+ if (!mDraggingActive && !mQuickScrubActive && exceededPerpendicularTouchSlop) {
+ if (mNavigationBarView.isQuickStepSwipeUpEnabled()) {
+ startQuickStep(event);
}
+ break;
+ }
- // Control the button movement
- if (!mDraggingActive && exceededTouchSlop && !mRecentsAnimationStarted) {
- boolean allowDrag = !mDragPositive
- ? offset < 0 && pos < touchDown : offset >= 0 && pos > touchDown;
- if (allowDrag) {
- mDownOffset = offset;
- homeButton.setClickable(false);
- mDraggingActive = true;
- }
+ // Do not handle quick scrub/switch if disabled or hit target is not home button
+ if (!homePressed || !mNavigationBarView.isQuickScrubEnabled()) {
+ break;
+ }
+
+ if (!mDragPositive) {
+ offset -= mIsVertical ? mTrackRect.height() : mTrackRect.width();
+ }
+
+ // Control the button movement
+ if (!mDraggingActive && exceededTouchSlop) {
+ boolean allowDrag = !mDragPositive
+ ? offset < 0 && pos < touchDown : offset >= 0 && pos > touchDown;
+ if (allowDrag) {
+ mDownOffset = offset;
+ homeButton.abortCurrentGesture();
+ mDraggingActive = true;
}
- if (mDraggingActive && (mDragPositive && offset >= 0
- || !mDragPositive && offset <= 0)) {
- float scrubFraction =
- Utilities.clamp(Math.abs(offset) * 1f / trackSize, 0, 1);
- mTranslation = !mDragPositive
- ? Utilities.clamp(offset - mDownOffset, -trackSize, 0)
- : Utilities.clamp(offset - mDownOffset, 0, trackSize);
- if (mQuickScrubActive) {
- try {
- mOverviewEventSender.getProxy().onQuickScrubProgress(scrubFraction);
- if (DEBUG_OVERVIEW_PROXY) {
- Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to send progress of quick scrub.", e);
+ }
+ if (mDraggingActive && (mDragPositive && offset >= 0
+ || !mDragPositive && offset <= 0)) {
+ float scrubFraction = Utilities.clamp(Math.abs(offset) * 1f / trackSize, 0, 1);
+ mTranslation = !mDragPositive
+ ? Utilities.clamp(offset - mDownOffset, -trackSize, 0)
+ : Utilities.clamp(offset - mDownOffset, 0, trackSize);
+ if (mQuickScrubActive) {
+ try {
+ mOverviewEventSender.getProxy().onQuickScrubProgress(scrubFraction);
+ if (DEBUG_OVERVIEW_PROXY) {
+ Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction);
}
- } else {
- mTranslation /= SWITCH_STICKINESS;
- }
- if (mIsVertical) {
- mHomeButtonView.setTranslationY(mTranslation);
- } else {
- mHomeButtonView.setTranslationX(mTranslation);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to send progress of quick scrub.", e);
}
+ } else {
+ mTranslation /= SWITCH_STICKINESS;
+ }
+ if (mIsVertical) {
+ mHomeButtonView.setTranslationY(mTranslation);
+ } else {
+ mHomeButtonView.setTranslationX(mTranslation);
}
}
break;
@@ -324,11 +341,20 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
endQuickScrub(true /* animate */);
break;
}
- return mDraggingActive || mQuickScrubActive;
+
+ // Proxy motion events to launcher if not handled by quick scrub/switch
+ boolean handled = mDraggingActive || mQuickScrubActive;
+ if (!handled && mAllowGestureDetection) {
+ proxyMotionEvents(event);
+ }
+ return handled || mQuickStepStarted;
}
@Override
public void onDraw(Canvas canvas) {
+ if (mNavigationBarView.isQuickScrubEnabled()) {
+ return;
+ }
int color = (int) mTrackColorEvaluator.evaluate(mDarkIntensity, mLightTrackColor,
mDarkTrackColor);
mTrackPaint.setColor(color);
@@ -381,6 +407,31 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
}
}
+ @Override
+ public void onNavigationButtonLongPress(View v) {
+ mAllowGestureDetection = false;
+ mHandler.removeCallbacksAndMessages(null);
+ }
+
+ private void startQuickStep(MotionEvent event) {
+ mQuickStepStarted = true;
+ event.transform(mTransformGlobalMatrix);
+ try {
+ mOverviewEventSender.getProxy().onQuickStep(event);
+ if (DEBUG_OVERVIEW_PROXY) {
+ Log.d(TAG_OPS, "Quick Step Start");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to send quick step started.", e);
+ } finally {
+ event.transform(mTransformLocalMatrix);
+ }
+ mOverviewEventSender.notifyQuickStepStarted();
+ mNavigationBarView.getHomeButton().abortCurrentGesture();
+ cancelQuickSwitch();
+ mHandler.removeCallbacksAndMessages(null);
+ }
+
private void startQuickScrub() {
if (!mQuickScrubActive && mDraggingActive) {
mQuickScrubActive = true;
@@ -396,9 +447,6 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
} catch (RemoteException e) {
Log.e(TAG, "Failed to send start of quick scrub.", e);
}
- } else {
- // After long press do not allow quick scrub/switch
- mTouchDownX = -1;
}
}
@@ -421,11 +469,24 @@ public class QuickScrubController extends GestureDetector.SimpleOnGestureListene
mDraggingActive = false;
}
- public void setRecentsAnimationStarted(boolean started) {
- mRecentsAnimationStarted = started;
- if (started) {
- cancelQuickSwitch();
+ private boolean proxyMotionEvents(MotionEvent event) {
+ final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
+ event.transform(mTransformGlobalMatrix);
+ try {
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ overviewProxy.onPreMotionEvent(mNavigationBarView.getDownHitTarget());
+ }
+ overviewProxy.onMotionEvent(event);
+ if (DEBUG_OVERVIEW_PROXY) {
+ Log.d(TAG_OPS, "Send MotionEvent: " + event.toString());
+ }
+ return true;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback failed", e);
+ } finally {
+ event.transform(mTransformLocalMatrix);
}
+ return false;
}
public void cancelQuickSwitch() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index e4f142a992e9..2e45b120a75f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -232,6 +232,7 @@ import com.android.systemui.statusbar.policy.PreviewInflater;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.util.NotificationChannels;
import com.android.systemui.volume.VolumeComponent;
@@ -407,6 +408,7 @@ public class StatusBar extends SystemUI implements DemoMode,
protected NotificationEntryManager mEntryManager;
protected NotificationViewHierarchyManager mViewHierarchyManager;
protected AppOpsListener mAppOpsListener;
+ private ZenModeController mZenController;
/**
* Helper that is responsible for showing the right toast when a disallowed activity operation
@@ -626,6 +628,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mViewHierarchyManager = Dependency.get(NotificationViewHierarchyManager.class);
mAppOpsListener = Dependency.get(AppOpsListener.class);
mAppOpsListener.setUpWithPresenter(this, mEntryManager);
+ mZenController = Dependency.get(ZenModeController.class);
mColorExtractor = Dependency.get(SysuiColorExtractor.class);
mColorExtractor.addOnColorsChangedListener(this);
@@ -1166,6 +1169,7 @@ public class StatusBar extends SystemUI implements DemoMode,
}
mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
R.layout.status_bar_no_notifications, mStackScroller, false);
+ mEmptyShadeView.setText(R.string.empty_shade_text);
mStackScroller.setEmptyShadeView(mEmptyShadeView);
}
@@ -1498,6 +1502,9 @@ public class StatusBar extends SystemUI implements DemoMode,
return entry.row.getParent() instanceof NotificationStackScrollLayout;
}
+ public boolean areNotificationsHidden() {
+ return mZenController.areNotificationsHiddenInShade();
+ }
public void requestNotificationUpdate() {
mEntryManager.updateNotifications();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 3bcfd4b7f381..e5fefd34ffb7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -224,8 +224,10 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
case MotionEvent.ACTION_DOWN:
mDownTime = SystemClock.uptimeMillis();
mLongClicked = false;
- mTouchDownX = (int) ev.getX();
- mTouchDownY = (int) ev.getY();
+
+ // Use raw X and Y to detect gestures in case a parent changes the x and y values
+ mTouchDownX = (int) ev.getRawX();
+ mTouchDownY = (int) ev.getRawY();
if (mCode != 0) {
sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);
} else {
@@ -241,8 +243,8 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
break;
case MotionEvent.ACTION_MOVE:
- x = (int)ev.getX();
- y = (int)ev.getY();
+ x = (int)ev.getRawX();
+ y = (int)ev.getRawY();
boolean exceededTouchSlopX = Math.abs(x - mTouchDownX) > mTouchSlop;
boolean exceededTouchSlopY = Math.abs(y - mTouchDownY) > mTouchSlop;
if (exceededTouchSlopX || exceededTouchSlopY) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
index 8777aa6454bc..4ee805934522 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -35,6 +35,7 @@ public interface ZenModeController extends CallbackController<Callback> {
boolean isCountdownConditionSupported();
int getCurrentUser();
boolean isVolumeRestricted();
+ boolean areNotificationsHiddenInShade();
public static interface Callback {
default void onZenChanged(int zen) {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index 0fd244527540..a9da239ada9d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -33,13 +33,11 @@ import android.os.UserManager;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import android.service.notification.Condition;
-import android.service.notification.IConditionListener;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ZenRule;
-import android.support.annotation.VisibleForTesting;
import android.util.Log;
-import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.qs.GlobalSetting;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.util.Utils;
@@ -64,9 +62,9 @@ public class ZenModeControllerImpl extends CurrentUserTracker implements ZenMode
private final UserManager mUserManager;
private int mUserId;
- private boolean mRequesting;
private boolean mRegistered;
private ZenModeConfig mConfig;
+ private int mZenMode;
public ZenModeControllerImpl(Context context, Handler handler) {
super(context);
@@ -74,6 +72,7 @@ public class ZenModeControllerImpl extends CurrentUserTracker implements ZenMode
mModeSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE) {
@Override
protected void handleValueChanged(int value) {
+ updateZenMode(value);
fireZenChanged(value);
}
};
@@ -86,7 +85,9 @@ public class ZenModeControllerImpl extends CurrentUserTracker implements ZenMode
mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mConfig = mNoMan.getZenModeConfig();
mModeSetting.setListening(true);
+ updateZenMode(mModeSetting.getValue());
mConfigSetting.setListening(true);
+ updateZenModeConfig();
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mSetupObserver = new SetupObserver(handler);
mSetupObserver.register();
@@ -101,6 +102,15 @@ public class ZenModeControllerImpl extends CurrentUserTracker implements ZenMode
}
@Override
+ public boolean areNotificationsHiddenInShade() {
+ if (mZenMode != Global.ZEN_MODE_OFF) {
+ return (mConfig.suppressedVisualEffects & NotificationManager.Policy
+ .SUPPRESSED_EFFECT_NOTIFICATION_LIST) != 0;
+ }
+ return false;
+ }
+
+ @Override
public void addCallback(Callback callback) {
mCallbacks.add(callback);
}
@@ -186,10 +196,6 @@ public class ZenModeControllerImpl extends CurrentUserTracker implements ZenMode
Utils.safeForeach(mCallbacks, c -> c.onZenAvailableChanged(available));
}
- private void fireConditionsChanged(Condition[] conditions) {
- Utils.safeForeach(mCallbacks, c -> c.onConditionsChanged(conditions));
- }
-
private void fireManualRuleChanged(ZenRule rule) {
Utils.safeForeach(mCallbacks, c -> c.onManualRuleChanged(rule));
}
@@ -199,17 +205,13 @@ public class ZenModeControllerImpl extends CurrentUserTracker implements ZenMode
Utils.safeForeach(mCallbacks, c -> c.onConfigChanged(config));
}
- private void updateConditions(Condition[] conditions) {
- if (conditions == null || conditions.length == 0) return;
- for (Condition c : conditions) {
- if ((c.flags & Condition.FLAG_RELEVANT_NOW) == 0) continue;
- mConditions.put(c.id, c);
- }
- fireConditionsChanged(
- mConditions.values().toArray(new Condition[mConditions.values().size()]));
+ @VisibleForTesting
+ protected void updateZenMode(int mode) {
+ mZenMode = mode;
}
- private void updateZenModeConfig() {
+ @VisibleForTesting
+ protected void updateZenModeConfig() {
final ZenModeConfig config = mNoMan.getZenModeConfig();
if (Objects.equals(config, mConfig)) return;
final ZenRule oldRule = mConfig != null ? mConfig.manualRule : null;
@@ -220,16 +222,6 @@ public class ZenModeControllerImpl extends CurrentUserTracker implements ZenMode
fireManualRuleChanged(newRule);
}
- private final IConditionListener mListener = new IConditionListener.Stub() {
- @Override
- public void onConditionsReceived(Condition[] conditions) {
- if (DEBUG) Slog.d(TAG, "onConditionsReceived "
- + (conditions == null ? 0 : conditions.length) + " mRequesting=" + mRequesting);
- if (!mRequesting) return;
- updateConditions(conditions);
- }
- };
-
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 66fde7986b00..a85f4e2b53a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -104,7 +104,6 @@ import android.support.v4.graphics.ColorUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
@@ -3985,6 +3984,11 @@ public class NotificationStackScrollLayout extends ViewGroup
} else {
mEmptyShadeView.setInvisible();
}
+ if (mStatusBar.areNotificationsHidden()) {
+ mEmptyShadeView.setText(R.string.dnd_suppressing_shade_text);
+ } else {
+ mEmptyShadeView.setText(R.string.empty_shade_text);
+ }
mEmptyShadeView.setVisibility(newVisibility);
mEmptyShadeView.setWillBeGone(false);
updateContentHeight();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 91314fe38118..e94d6bd5ee99 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -897,6 +897,9 @@ public class VolumeDialogImpl implements VolumeDialog {
}
private String getStreamLabelH(StreamState ss) {
+ if (ss == null) {
+ return "";
+ }
if (ss.remoteLabel != null) {
return ss.remoteLabel;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index b6116e00bac1..5812da29b2ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -21,7 +21,7 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
-import androidx.app.slice.Slice;
+import androidx.slice.Slice;
import android.app.AlarmManager;
import android.content.ContentResolver;
@@ -45,10 +45,10 @@ import org.mockito.MockitoAnnotations;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
-import androidx.app.slice.SliceItem;
-import androidx.app.slice.SliceProvider;
-import androidx.app.slice.SliceSpecs;
-import androidx.app.slice.core.SliceQuery;
+import androidx.slice.SliceItem;
+import androidx.slice.SliceProvider;
+import androidx.slice.SliceSpecs;
+import androidx.slice.core.SliceQuery;
@SmallTest
@RunWith(AndroidTestingRunner.class)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java
index ec994a1a5650..5c347301bd8c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java
@@ -17,7 +17,7 @@ package com.android.systemui.statusbar.policy;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_NUM_STATUS_ICONS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_STATUS_ICONS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent
- .NOTIFICATION_SINCE_CREATE_MILLIS;
+ .RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.any;
@@ -119,9 +119,9 @@ public class IconLoggerImplTest extends SysuiTestCase {
verify(mMetricsLogger).write(argThat(maker -> {
if (IconLoggerImpl.MIN_LOG_INTERVAL >
- (long) maker.getTaggedData(NOTIFICATION_SINCE_CREATE_MILLIS)) {
+ (long) maker.getTaggedData(RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS)) {
Log.e("IconLoggerImplTest", "Invalid latency "
- + maker.getTaggedData(NOTIFICATION_SINCE_CREATE_MILLIS));
+ + maker.getTaggedData(RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS));
return false;
}
if (1 != (int) maker.getTaggedData(FIELD_NUM_STATUS_ICONS)) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
index 8124bf39328b..da8017e25525 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
@@ -14,11 +14,17 @@
package com.android.systemui.statusbar.policy;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import android.app.NotificationManager;
import android.os.Handler;
+import android.provider.Settings;
import android.service.notification.ZenModeConfig;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -27,8 +33,11 @@ import android.testing.TestableLooper.RunWithLooper;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.policy.ZenModeController.Callback;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -36,21 +45,64 @@ import org.junit.runner.RunWith;
public class ZenModeControllerImplTest extends SysuiTestCase {
private Callback mCallback;
+ @Mock
+ NotificationManager mNm;
+ @Mock
+ ZenModeConfig mConfig;
+
+ private ZenModeControllerImpl mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext.addMockSystemService(NotificationManager.class, mNm);
+ when(mNm.getZenModeConfig()).thenReturn(mConfig);
+
+ mController = new ZenModeControllerImpl(mContext, new Handler());
+ }
@Test
public void testRemoveDuringCallback() {
- ZenModeControllerImpl controller = new ZenModeControllerImpl(mContext, new Handler());
mCallback = new Callback() {
@Override
public void onConfigChanged(ZenModeConfig config) {
- controller.removeCallback(mCallback);
+ mController.removeCallback(mCallback);
}
};
- controller.addCallback(mCallback);
+ mController.addCallback(mCallback);
Callback mockCallback = mock(Callback.class);
- controller.addCallback(mockCallback);
- controller.fireConfigChanged(null);
+ mController.addCallback(mockCallback);
+ mController.fireConfigChanged(null);
verify(mockCallback).onConfigChanged(eq(null));
}
+ @Test
+ public void testAreNotificationsHiddenInShade_zenOffShadeSuppressed() {
+ mConfig.suppressedVisualEffects =
+ NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+ mController.updateZenMode(Settings.Global.ZEN_MODE_OFF);
+ mController.updateZenModeConfig();
+
+ assertFalse(mController.areNotificationsHiddenInShade());
+ }
+
+ @Test
+ public void testAreNotificationsHiddenInShade_zenOnShadeNotSuppressed() {
+ mConfig.suppressedVisualEffects =
+ NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+ mController.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ mController.updateZenModeConfig();
+
+ assertFalse(mController.areNotificationsHiddenInShade());
+ }
+
+ @Test
+ public void testAreNotificationsHiddenInShade_zenOnShadeSuppressed() {
+ mConfig.suppressedVisualEffects =
+ NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+ mController.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ mController.updateZenModeConfig();
+
+ assertTrue(mController.areNotificationsHiddenInShade());
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
index d9673d3552d8..6fa91ff07850 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
@@ -17,17 +17,16 @@
package com.android.systemui.statusbar.stack;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.annotation.UiThread;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.view.NotificationHeaderView;
-import android.view.View;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -72,4 +71,27 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
0.01 /* delta */);
}
+ @Test
+ public void updateEmptyView_dndSuppressing() {
+ EmptyShadeView view = mock(EmptyShadeView.class);
+ mStackScroller.setEmptyShadeView(view);
+ when(view.willBeGone()).thenReturn(true);
+ when(mBar.areNotificationsHidden()).thenReturn(true);
+
+ mStackScroller.updateEmptyShadeView(true);
+
+ verify(view).setText(R.string.dnd_suppressing_shade_text);
+ }
+
+ @Test
+ public void updateEmptyView_dndNotSuppressing() {
+ EmptyShadeView view = mock(EmptyShadeView.class);
+ mStackScroller.setEmptyShadeView(view);
+ when(view.willBeGone()).thenReturn(true);
+ when(mBar.areNotificationsHidden()).thenReturn(false);
+
+ mStackScroller.updateEmptyShadeView(true);
+
+ verify(view).setText(R.string.empty_shade_text);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java
index fb9bf7a15f60..86c43c998877 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java
@@ -77,4 +77,9 @@ public class FakeZenModeController extends BaseLeakChecker<Callback> implements
public boolean isVolumeRestricted() {
return false;
}
+
+ @Override
+ public boolean areNotificationsHiddenInShade() {
+ return false;
+ }
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index d89cc966bf29..e3be5d43a327 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5503,6 +5503,10 @@ message MetricsEvent {
// OS: P
ACTION_MANAGE_NOTIFICATIONS = 1358;
+ // This value should never appear in log outputs - it is reserved for
+ // internal platform metrics use.
+ RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS = 1359;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index b6e2dca3db5c..d6f6c6cf1fc3 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1398,7 +1398,7 @@ public class BackupManagerService implements BackupManagerServiceInterface {
// Returns the set of all applications that define an android:backupAgent attribute
private List<PackageInfo> allAgentPackages() {
// !!! TODO: cache this and regenerate only when necessary
- int flags = PackageManager.GET_SIGNATURES;
+ int flags = PackageManager.GET_SIGNING_CERTIFICATES;
List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags);
int N = packages.size();
for (int a = N - 1; a >= 0; a--) {
@@ -1643,7 +1643,7 @@ public class BackupManagerService implements BackupManagerServiceInterface {
}
try {
PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName,
- PackageManager.GET_SIGNATURES);
+ PackageManager.GET_SIGNING_CERTIFICATES);
if (!AppBackupUtils.appIsEligibleForBackup(packageInfo.applicationInfo,
mPackageManager)) {
BackupObserverUtils.sendBackupOnPackageResult(observer, packageName,
@@ -2353,7 +2353,8 @@ public class BackupManagerService implements BackupManagerServiceInterface {
if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName + " on " + transportName);
PackageInfo info;
try {
- info = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
+ info = mPackageManager.getPackageInfo(packageName,
+ PackageManager.GET_SIGNING_CERTIFICATES);
} catch (NameNotFoundException e) {
Slog.d(TAG, "No such package '" + packageName + "' - not clearing backup data");
return;
diff --git a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
index 3cf374faada4..dc28cd179bcb 100644
--- a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
+++ b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
@@ -23,6 +23,7 @@ import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
@@ -30,6 +31,7 @@ import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.util.Slog;
+import com.android.server.LocalServices;
import com.android.server.backup.utils.AppBackupUtils;
import java.io.BufferedInputStream;
@@ -154,7 +156,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
public static List<PackageInfo> getStorableApplications(PackageManager pm) {
List<PackageInfo> pkgs;
- pkgs = pm.getInstalledPackages(PackageManager.GET_SIGNATURES);
+ pkgs = pm.getInstalledPackages(PackageManager.GET_SIGNING_CERTIFICATES);
int N = pkgs.size();
for (int a = N-1; a >= 0; a--) {
PackageInfo pkg = pkgs.get(a);
@@ -235,10 +237,17 @@ public class PackageManagerBackupAgent extends BackupAgent {
if (home != null) {
try {
homeInfo = mPackageManager.getPackageInfo(home.getPackageName(),
- PackageManager.GET_SIGNATURES);
+ PackageManager.GET_SIGNING_CERTIFICATES);
homeInstaller = mPackageManager.getInstallerPackageName(home.getPackageName());
homeVersion = homeInfo.getLongVersionCode();
- homeSigHashes = BackupUtils.hashSignatureArray(homeInfo.signatures);
+ Signature[][] signingHistory = homeInfo.signingCertificateHistory;
+ if (signingHistory == null || signingHistory.length == 0) {
+ Slog.e(TAG, "Home app has no signing history");
+ } else {
+ // retrieve the newest sigs to back up
+ Signature[] homeInfoSignatures = signingHistory[signingHistory.length - 1];
+ homeSigHashes = BackupUtils.hashSignatureArray(homeInfoSignatures);
+ }
} catch (NameNotFoundException e) {
Slog.w(TAG, "Can't access preferred home info");
// proceed as though there were no preferred home set
@@ -252,10 +261,11 @@ public class PackageManagerBackupAgent extends BackupAgent {
// 2. the home app [or absence] we now use differs from the prior state,
// OR 3. it looks like we use the same home app + version as before, but
// the signatures don't match so we treat them as different apps.
+ PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
final boolean needHomeBackup = (homeVersion != mStoredHomeVersion)
|| !Objects.equals(home, mStoredHomeComponent)
|| (home != null
- && !BackupUtils.signaturesMatch(mStoredHomeSigHashes, homeInfo));
+ && !BackupUtils.signaturesMatch(mStoredHomeSigHashes, homeInfo, pmi));
if (needHomeBackup) {
if (DEBUG) {
Slog.i(TAG, "Home preference changed; backing up new state " + home);
@@ -304,7 +314,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
PackageInfo info = null;
try {
info = mPackageManager.getPackageInfo(packName,
- PackageManager.GET_SIGNATURES);
+ PackageManager.GET_SIGNING_CERTIFICATES);
} catch (NameNotFoundException e) {
// Weird; we just found it, and now are told it doesn't exist.
// Treat it as having been removed from the device.
@@ -323,9 +333,9 @@ public class PackageManagerBackupAgent extends BackupAgent {
continue;
}
}
-
- if (info.signatures == null || info.signatures.length == 0)
- {
+
+ Signature[][] signingHistory = info.signingCertificateHistory;
+ if (signingHistory == null || signingHistory.length == 0) {
Slog.w(TAG, "Not backing up package " + packName
+ " since it appears to have no signatures.");
continue;
@@ -347,8 +357,10 @@ public class PackageManagerBackupAgent extends BackupAgent {
} else {
outputBufferStream.writeInt(info.versionCode);
}
+ // retrieve the newest sigs to back up
+ Signature[] infoSignatures = signingHistory[signingHistory.length - 1];
writeSignatureHashArray(outputBufferStream,
- BackupUtils.hashSignatureArray(info.signatures));
+ BackupUtils.hashSignatureArray(infoSignatures));
if (DEBUG) {
Slog.v(TAG, "+ writing metadata for " + packName
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
index 2e2d3eb4ad21..821cca16bf60 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
@@ -129,7 +129,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor
try {
PackageInfo info = backupManagerService.getPackageManager().getPackageInfo(
pkgName,
- PackageManager.GET_SIGNATURES);
+ PackageManager.GET_SIGNING_CERTIFICATES);
set.put(pkgName, info);
} catch (NameNotFoundException e) {
Slog.w(TAG, "Unknown package " + pkgName + ", skipping");
@@ -240,7 +240,8 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor
// doAllApps supersedes the package set if any
if (mAllApps) {
- List<PackageInfo> allPackages = pm.getInstalledPackages(PackageManager.GET_SIGNATURES);
+ List<PackageInfo> allPackages = pm.getInstalledPackages(
+ PackageManager.GET_SIGNING_CERTIFICATES);
for (int i = 0; i < allPackages.size(); i++) {
PackageInfo pkg = allPackages.get(i);
// Exclude system apps if we've been asked to do so
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
index f9c366998ad2..2c2dd8528cb1 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
@@ -181,7 +181,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
for (String pkg : whichPackages) {
try {
PackageManager pm = backupManagerService.getPackageManager();
- PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
+ PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_SIGNING_CERTIFICATES);
mCurrentPackage = info;
if (!AppBackupUtils.appIsEligibleForBackup(info.applicationInfo, pm)) {
// Cull any packages that have indicated that backups are not permitted,
diff --git a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
index 0ba83cfeb361..11394e66a0f0 100644
--- a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
+++ b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
@@ -422,7 +422,8 @@ public class PerformBackupTask implements BackupRestoreTask {
// package's backup agent.
try {
PackageManager pm = backupManagerService.getPackageManager();
- mCurrentPackage = pm.getPackageInfo(request.packageName, PackageManager.GET_SIGNATURES);
+ mCurrentPackage = pm.getPackageInfo(request.packageName,
+ PackageManager.GET_SIGNING_CERTIFICATES);
if (!AppBackupUtils.appIsEligibleForBackup(mCurrentPackage.applicationInfo, pm)) {
// The manifest has changed but we had a stale backup request pending.
// This won't happen again because the app won't be requesting further
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index 0ca4f25093ce..c1a1c1dc10e7 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -36,11 +36,13 @@ import android.app.backup.IFullBackupRestoreObserver;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Slog;
+import com.android.server.LocalServices;
import com.android.server.backup.BackupRestoreTask;
import com.android.server.backup.FileMetadata;
import com.android.server.backup.KeyValueAdbRestoreEngine;
@@ -207,8 +209,11 @@ public class FullRestoreEngine extends RestoreEngine {
if (info.path.equals(BACKUP_MANIFEST_FILENAME)) {
Signature[] signatures = tarBackupReader.readAppManifestAndReturnSignatures(
info);
+ PackageManagerInternal pmi = LocalServices.getService(
+ PackageManagerInternal.class);
RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy(
- mBackupManagerService.getPackageManager(), allowApks, info, signatures);
+ mBackupManagerService.getPackageManager(), allowApks, info, signatures,
+ pmi);
mManifestSignatures.put(info.packageName, signatures);
mPackagePolicies.put(pkg, restorePolicy);
mPackageInstallers.put(pkg, info.installerPackageName);
diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
index e576b3c32859..dacde0b9af68 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
@@ -40,6 +40,7 @@ import android.app.backup.IFullBackupRestoreObserver;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
@@ -47,6 +48,7 @@ import android.os.RemoteException;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
import com.android.server.backup.BackupManagerService;
import com.android.server.backup.FileMetadata;
import com.android.server.backup.KeyValueAdbRestoreEngine;
@@ -470,9 +472,11 @@ public class PerformAdbRestoreTask implements Runnable {
if (info.path.equals(BACKUP_MANIFEST_FILENAME)) {
Signature[] signatures = tarBackupReader.readAppManifestAndReturnSignatures(
info);
+ PackageManagerInternal pmi = LocalServices.getService(
+ PackageManagerInternal.class);
RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy(
mBackupManagerService.getPackageManager(), allowApks,
- info, signatures);
+ info, signatures, pmi);
mManifestSignatures.put(info.packageName, signatures);
mPackagePolicies.put(pkg, restorePolicy);
mPackageInstallers.put(pkg, info.installerPackageName);
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 3caa1e7fab79..4b467e5a0399 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -43,6 +43,7 @@ import android.app.backup.RestoreDescription;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.os.Message;
@@ -57,6 +58,7 @@ import android.util.Slog;
import com.android.internal.backup.IBackupTransport;
import com.android.server.AppWidgetBackupBridge;
import com.android.server.EventLogTags;
+import com.android.server.LocalServices;
import com.android.server.backup.BackupRestoreTask;
import com.android.server.backup.BackupUtils;
import com.android.server.backup.PackageManagerBackupAgent;
@@ -504,7 +506,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
try {
mCurrentPackage = backupManagerService.getPackageManager().getPackageInfo(
- pkgName, PackageManager.GET_SIGNATURES);
+ pkgName, PackageManager.GET_SIGNING_CERTIFICATES);
} catch (NameNotFoundException e) {
// Whoops, we thought we could restore this package but it
// turns out not to be present. Skip it.
@@ -619,7 +621,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
}
Metadata metaInfo = mPmAgent.getRestoredMetadata(packageName);
- if (!BackupUtils.signaturesMatch(metaInfo.sigHashes, mCurrentPackage)) {
+ PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+ if (!BackupUtils.signaturesMatch(metaInfo.sigHashes, mCurrentPackage, pmi)) {
Slog.w(TAG, "Signature mismatch restoring " + packageName);
mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
BackupManagerMonitor.LOG_EVENT_ID_SIGNATURE_MISMATCH, mCurrentPackage,
diff --git a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
index 6780563120e3..5518374ebdbc 100644
--- a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
@@ -25,6 +25,7 @@ import android.app.backup.BackupTransport;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.os.Process;
import android.util.Slog;
@@ -37,6 +38,9 @@ import com.android.server.backup.transport.TransportClient;
* Utility methods wrapping operations on ApplicationInfo and PackageInfo.
*/
public class AppBackupUtils {
+
+ private static final boolean DEBUG = false;
+
/**
* Returns whether app is eligible for backup.
*
@@ -88,7 +92,8 @@ public class AppBackupUtils {
public static boolean appIsRunningAndEligibleForBackupWithTransport(
@Nullable TransportClient transportClient, String packageName, PackageManager pm) {
try {
- PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
+ PackageInfo packageInfo = pm.getPackageInfo(packageName,
+ PackageManager.GET_SIGNING_CERTIFICATES);
ApplicationInfo applicationInfo = packageInfo.applicationInfo;
if (!appIsEligibleForBackup(applicationInfo, pm)
|| appIsStopped(applicationInfo)
@@ -165,13 +170,19 @@ public class AppBackupUtils {
*
* <ul>
* <li>Source and target have at least one signature each
- * <li>Target contains all signatures in source
+ * <li>Target contains all signatures in source, and nothing more
* </ul>
*
+ * or if both source and target have exactly one signature, and they don't match, we check
+ * if the app was ever signed with source signature (i.e. app has rotated key)
+ * Note: key rotation is only supported for apps ever signed with one key, and those apps will
+ * not be allowed to be signed by more certificates in the future
+ *
* Note that if {@param target} is null we return false.
*/
- public static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) {
- if (target == null) {
+ public static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target,
+ PackageManagerInternal pmi) {
+ if (target == null || target.packageName == null) {
return false;
}
@@ -187,33 +198,52 @@ public class AppBackupUtils {
return true;
}
- Signature[] deviceSigs = target.signatures;
- if (MORE_DEBUG) {
- Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs + " device=" + deviceSigs);
+ // Don't allow unsigned apps on either end
+ if (ArrayUtils.isEmpty(storedSigs)) {
+ return false;
}
- // Don't allow unsigned apps on either end
- if (ArrayUtils.isEmpty(storedSigs) || ArrayUtils.isEmpty(deviceSigs)) {
+ Signature[][] deviceHistorySigs = target.signingCertificateHistory;
+ if (ArrayUtils.isEmpty(deviceHistorySigs)) {
+ Slog.w(TAG, "signingCertificateHistory is empty, app was either unsigned or the flag" +
+ " PackageManager#GET_SIGNING_CERTIFICATES was not specified");
return false;
}
- // Signatures can be added over time, so the target-device apk needs to contain all the
- // source-device apk signatures, but not necessarily the other way around.
- int nStored = storedSigs.length;
- int nDevice = deviceSigs.length;
-
- for (int i = 0; i < nStored; i++) {
- boolean match = false;
- for (int j = 0; j < nDevice; j++) {
- if (storedSigs[i].equals(deviceSigs[j])) {
- match = true;
- break;
+ if (DEBUG) {
+ Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs + " device=" + deviceHistorySigs);
+ }
+
+ final int nStored = storedSigs.length;
+ if (nStored == 1) {
+ // if the app is only signed with one sig, it's possible it has rotated its key
+ // (the checks with signing history are delegated to PackageManager)
+ // TODO(b/73988180): address the case that app has declared restoreAnyVersion and is
+ // restoring from higher version to lower after having rotated the key (i.e. higher
+ // version has different sig than lower version that we want to restore to)
+ return pmi.isDataRestoreSafe(storedSigs[0], target.packageName);
+ } else {
+ // the app couldn't have rotated keys, since it was signed with multiple sigs - do
+ // a check to see if we find a match for all stored sigs
+ // since app hasn't rotated key, we only need to check with deviceHistorySigs[0]
+ Signature[] deviceSigs = deviceHistorySigs[0];
+ int nDevice = deviceSigs.length;
+
+ // ensure that each stored sig matches an on-device sig
+ for (int i = 0; i < nStored; i++) {
+ boolean match = false;
+ for (int j = 0; j < nDevice; j++) {
+ if (storedSigs[i].equals(deviceSigs[j])) {
+ match = true;
+ break;
+ }
+ }
+ if (!match) {
+ return false;
}
}
- if (!match) {
- return false;
- }
+ // we have found a match for all stored sigs
+ return true;
}
- return true;
}
}
diff --git a/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java b/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java
index d2ab09996d68..994d5a967298 100644
--- a/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java
@@ -104,11 +104,16 @@ public class FullBackupUtils {
printer.println((installerName != null) ? installerName : "");
printer.println(withApk ? "1" : "0");
- if (pkg.signatures == null) {
+
+ // write the signature block
+ Signature[][] signingHistory = pkg.signingCertificateHistory;
+ if (signingHistory == null) {
printer.println("0");
} else {
- printer.println(Integer.toString(pkg.signatures.length));
- for (Signature sig : pkg.signatures) {
+ // retrieve the newest sigs to write
+ Signature[] signatures = signingHistory[signingHistory.length - 1];
+ printer.println(Integer.toString(signatures.length));
+ for (Signature sig : signatures) {
printer.println(sig.toCharsString());
}
}
diff --git a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java
index 10f06954f17f..df7e6d45ba0f 100644
--- a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java
@@ -30,6 +30,7 @@ import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.Session;
import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.os.Bundle;
import android.os.IBinder;
@@ -37,6 +38,7 @@ import android.os.Process;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
import com.android.server.backup.FileMetadata;
import com.android.server.backup.restore.RestoreDeleteObserver;
import com.android.server.backup.restore.RestorePolicy;
@@ -142,9 +144,8 @@ public class RestoreUtils {
uninstall = true;
} else {
try {
- PackageInfo pkg = packageManager.getPackageInfo(
- info.packageName,
- PackageManager.GET_SIGNATURES);
+ PackageInfo pkg = packageManager.getPackageInfo(info.packageName,
+ PackageManager.GET_SIGNING_CERTIFICATES);
if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP)
== 0) {
Slog.w(TAG, "Restore stream contains apk of package "
@@ -154,7 +155,9 @@ public class RestoreUtils {
} else {
// So far so good -- do the signatures match the manifest?
Signature[] sigs = manifestSignatures.get(info.packageName);
- if (AppBackupUtils.signaturesMatch(sigs, pkg)) {
+ PackageManagerInternal pmi = LocalServices.getService(
+ PackageManagerInternal.class);
+ if (AppBackupUtils.signaturesMatch(sigs, pkg, pmi)) {
// If this is a system-uid app without a declared backup agent,
// don't restore any of the file data.
if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
diff --git a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
index cc26ff8b5090..6dd5284879f0 100644
--- a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
+++ b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
@@ -50,6 +50,7 @@ import android.app.backup.IBackupManagerMonitor;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.os.Bundle;
import android.os.Process;
@@ -385,7 +386,8 @@ public class TarBackupReader {
* @return a restore policy constant.
*/
public RestorePolicy chooseRestorePolicy(PackageManager packageManager,
- boolean allowApks, FileMetadata info, Signature[] signatures) {
+ boolean allowApks, FileMetadata info, Signature[] signatures,
+ PackageManagerInternal pmi) {
if (signatures == null) {
return RestorePolicy.IGNORE;
}
@@ -395,7 +397,7 @@ public class TarBackupReader {
// Okay, got the manifest info we need...
try {
PackageInfo pkgInfo = packageManager.getPackageInfo(
- info.packageName, PackageManager.GET_SIGNATURES);
+ info.packageName, PackageManager.GET_SIGNING_CERTIFICATES);
// Fall through to IGNORE if the app explicitly disallows backup
final int flags = pkgInfo.applicationInfo.flags;
if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
@@ -411,7 +413,7 @@ public class TarBackupReader {
// such packages are signed with the platform cert instead of
// the app developer's cert, so they're different on every
// device.
- if (AppBackupUtils.signaturesMatch(signatures, pkgInfo)) {
+ if (AppBackupUtils.signaturesMatch(signatures, pkgInfo, pmi)) {
if ((pkgInfo.applicationInfo.flags
& ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) {
Slog.i(TAG, "Package has restoreAnyVersion; taking data");
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 62e82a064db2..38968712f4c8 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -65,7 +65,6 @@ import com.android.server.am.BatteryStatsService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
@@ -164,14 +163,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
private int[] mDataActivity;
+ // Connection state of default APN type data (i.e. internet) of phones
private int[] mDataConnectionState;
- private ArrayList<String>[] mConnectedApns;
-
- private LinkProperties[] mDataConnectionLinkProperties;
-
- private NetworkCapabilities[] mDataConnectionNetworkCapabilities;
-
private Bundle[] mCellLocation;
private int[] mDataConnectionNetworkType;
@@ -323,9 +317,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
mBatteryStats = BatteryStatsService.getService();
int numPhones = TelephonyManager.getDefault().getPhoneCount();
- if (DBG) log("TelephonyRegistor: ctor numPhones=" + numPhones);
+ if (DBG) log("TelephonyRegistry: ctor numPhones=" + numPhones);
mNumPhones = numPhones;
- mConnectedApns = new ArrayList[numPhones];
mCallState = new int[numPhones];
mDataActivity = new int[numPhones];
mDataConnectionState = new int[numPhones];
@@ -339,8 +332,6 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
mMessageWaiting = new boolean[numPhones];
mCallForwarding = new boolean[numPhones];
mCellLocation = new Bundle[numPhones];
- mDataConnectionLinkProperties = new LinkProperties[numPhones];
- mDataConnectionNetworkCapabilities = new NetworkCapabilities[numPhones];
mCellInfo = new ArrayList<List<CellInfo>>();
mPhysicalChannelConfigs = new ArrayList<List<PhysicalChannelConfig>>();
for (int i = 0; i < numPhones; i++) {
@@ -358,7 +349,6 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
mCellLocation[i] = new Bundle();
mCellInfo.add(i, null);
mPhysicalChannelConfigs.add(i, null);
- mConnectedApns[i] = new ArrayList<String>();
}
// Note that location can be null for non-phone builds like
@@ -1219,36 +1209,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
int phoneId = SubscriptionManager.getPhoneId(subId);
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
- boolean modified = false;
- if (state == TelephonyManager.DATA_CONNECTED) {
- if (!mConnectedApns[phoneId].contains(apnType)) {
- mConnectedApns[phoneId].add(apnType);
- if (mDataConnectionState[phoneId] != state) {
- mDataConnectionState[phoneId] = state;
- modified = true;
- }
- }
- } else {
- if (mConnectedApns[phoneId].remove(apnType)) {
- if (mConnectedApns[phoneId].isEmpty()) {
- mDataConnectionState[phoneId] = state;
- modified = true;
- } else {
- // leave mDataConnectionState as is and
- // send out the new status for the APN in question.
- }
- }
- }
- mDataConnectionLinkProperties[phoneId] = linkProperties;
- mDataConnectionNetworkCapabilities[phoneId] = networkCapabilities;
- if (mDataConnectionNetworkType[phoneId] != networkType) {
- mDataConnectionNetworkType[phoneId] = networkType;
- // need to tell registered listeners about the new network type
- modified = true;
- }
- if (modified) {
- String str = "onDataConnectionStateChanged(" + mDataConnectionState[phoneId]
- + ", " + mDataConnectionNetworkType[phoneId] + ")";
+ // We only call the callback when the change is for default APN type.
+ if (PhoneConstants.APN_TYPE_DEFAULT.equals(apnType)
+ && (mDataConnectionState[phoneId] != state
+ || mDataConnectionNetworkType[phoneId] != networkType)) {
+ String str = "onDataConnectionStateChanged(" + state
+ + ", " + networkType + ")";
log(str);
mLocalLog.log(str);
for (Record r : mRecords) {
@@ -1259,15 +1225,16 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (DBG) {
log("Notify data connection state changed on sub: " + subId);
}
- r.callback.onDataConnectionStateChanged(
- mDataConnectionState[phoneId],
- mDataConnectionNetworkType[phoneId]);
+ r.callback.onDataConnectionStateChanged(state, networkType);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
}
}
handleRemoveListLocked();
+
+ mDataConnectionState[phoneId] = state;
+ mDataConnectionNetworkType[phoneId] = networkType;
}
mPreciseDataConnectionState = new PreciseDataConnectionState(state, networkType,
apnType, apn, reason, linkProperties, "");
@@ -1503,14 +1470,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
pw.println("mCallForwarding=" + mCallForwarding[i]);
pw.println("mDataActivity=" + mDataActivity[i]);
pw.println("mDataConnectionState=" + mDataConnectionState[i]);
- pw.println("mDataConnectionLinkProperties=" + mDataConnectionLinkProperties[i]);
- pw.println("mDataConnectionNetworkCapabilities=" +
- mDataConnectionNetworkCapabilities[i]);
pw.println("mCellLocation=" + mCellLocation[i]);
pw.println("mCellInfo=" + mCellInfo.get(i));
pw.decreaseIndent();
}
- pw.println("mConnectedApns=" + Arrays.toString(mConnectedApns));
pw.println("mPreciseDataConnectionState=" + mPreciseDataConnectionState);
pw.println("mPreciseCallState=" + mPreciseCallState);
pw.println("mCarrierNetworkChangeState=" + mCarrierNetworkChangeState);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 26f83f560c5c..eb4e32e47489 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3390,10 +3390,15 @@ public final class ActiveServices {
return;
}
+ app = r.app;
+ if (app != null && app.debugging) {
+ // The app's being debugged; let it ride
+ return;
+ }
+
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "Service foreground-required timeout for " + r);
}
- app = r.app;
r.fgWaiting = false;
stopServiceLocked(r);
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 47425752d0c5..2c4eac0e391b 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -4590,7 +4590,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
ActivityOptions.abort(options);
} else {
- updateTransitLocked(TRANSIT_TASK_TO_FRONT, starting, options);
+ updateTransitLocked(TRANSIT_TASK_TO_FRONT, r, options);
}
// If a new task is moved to the front, then mark the existing top activity as supporting
// picture-in-picture while paused only if the task would not be considered an oerlay on top
diff --git a/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
index d7d18a99b66f..690d985ef096 100644
--- a/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
@@ -43,6 +43,7 @@ class GlobalSettingsToPropertiesMapper {
{Settings.Global.FPS_DEVISOR, ThreadedRenderer.DEBUG_FPS_DIVISOR},
{Settings.Global.DISPLAY_PANEL_LPM, "sys.display_panel_lpm"},
{Settings.Global.SYS_UIDCPUPOWER, "sys.uidcpupower"},
+ {Settings.Global.SYS_TRACED, "persist.traced.enable"},
};
diff --git a/services/core/java/com/android/server/backup/BackupUtils.java b/services/core/java/com/android/server/backup/BackupUtils.java
index e5d564dec459..d817534551f7 100644
--- a/services/core/java/com/android/server/backup/BackupUtils.java
+++ b/services/core/java/com/android/server/backup/BackupUtils.java
@@ -18,9 +18,12 @@ package com.android.server.backup;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.util.Slog;
+import com.android.internal.util.ArrayUtils;
+
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
@@ -30,13 +33,13 @@ import java.util.List;
public class BackupUtils {
private static final String TAG = "BackupUtils";
- private static final boolean DEBUG = false; // STOPSHIP if true
+ private static final boolean DEBUG = false;
- public static boolean signaturesMatch(ArrayList<byte[]> storedSigHashes, PackageInfo target) {
- if (target == null) {
+ public static boolean signaturesMatch(ArrayList<byte[]> storedSigHashes, PackageInfo target,
+ PackageManagerInternal pmi) {
+ if (target == null || target.packageName == null) {
return false;
}
-
// If the target resides on the system partition, we allow it to restore
// data from the like-named package in a restore set even if the signatures
// do not match. (Unlike general applications, those flashed to the system
@@ -47,48 +50,53 @@ public class BackupUtils {
return true;
}
- // Allow unsigned apps, but not signed on one device and unsigned on the other
- // !!! TODO: is this the right policy?
- Signature[] deviceSigs = target.signatures;
- if (DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigHashes
- + " device=" + deviceSigs);
- if ((storedSigHashes == null || storedSigHashes.size() == 0)
- && (deviceSigs == null || deviceSigs.length == 0)) {
- return true;
- }
- if (storedSigHashes == null || deviceSigs == null) {
+ // Don't allow unsigned apps on either end
+ if (ArrayUtils.isEmpty(storedSigHashes)) {
return false;
}
- // !!! TODO: this demands that every stored signature match one
- // that is present on device, and does not demand the converse.
- // Is this this right policy?
- final int nStored = storedSigHashes.size();
- final int nDevice = deviceSigs.length;
+ Signature[][] deviceHistorySigs = target.signingCertificateHistory;
+ if (ArrayUtils.isEmpty(deviceHistorySigs)) {
+ Slog.w(TAG, "signingCertificateHistory is empty, app was either unsigned or the flag" +
+ " PackageManager#GET_SIGNING_CERTIFICATES was not specified");
+ return false;
+ }
- // hash each on-device signature
- ArrayList<byte[]> deviceHashes = new ArrayList<byte[]>(nDevice);
- for (int i = 0; i < nDevice; i++) {
- deviceHashes.add(hashSignature(deviceSigs[i]));
+ if (DEBUG) {
+ Slog.v(TAG, "signaturesMatch(): stored=" + storedSigHashes
+ + " device=" + deviceHistorySigs);
}
- // now ensure that each stored sig (hash) matches an on-device sig (hash)
- for (int n = 0; n < nStored; n++) {
- boolean match = false;
- final byte[] storedHash = storedSigHashes.get(n);
- for (int i = 0; i < nDevice; i++) {
- if (Arrays.equals(storedHash, deviceHashes.get(i))) {
- match = true;
- break;
+ final int nStored = storedSigHashes.size();
+ if (nStored == 1) {
+ // if the app is only signed with one sig, it's possible it has rotated its key
+ // the checks with signing history are delegated to PackageManager
+ // TODO(b/73988180): address the case that app has declared restoreAnyVersion and is
+ // restoring from higher version to lower after having rotated the key (i.e. higher
+ // version has different sig than lower version that we want to restore to)
+ return pmi.isDataRestoreSafe(storedSigHashes.get(0), target.packageName);
+ } else {
+ // the app couldn't have rotated keys, since it was signed with multiple sigs - do
+ // a check to see if we find a match for all stored sigs
+ // since app hasn't rotated key, we only need to check with deviceHistorySigs[0]
+ ArrayList<byte[]> deviceHashes = hashSignatureArray(deviceHistorySigs[0]);
+ int nDevice = deviceHashes.size();
+ // ensure that each stored sig matches an on-device sig
+ for (int i = 0; i < nStored; i++) {
+ boolean match = false;
+ for (int j = 0; j < nDevice; j++) {
+ if (Arrays.equals(storedSigHashes.get(i), deviceHashes.get(j))) {
+ match = true;
+ break;
+ }
+ }
+ if (!match) {
+ return false;
}
}
- // match is false when no on-device sig matched one of the stored ones
- if (!match) {
- return false;
- }
+ // we have found a match for all stored sigs
+ return true;
}
-
- return true;
}
public static byte[] hashSignature(byte[] signature) {
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 3a8e291f7976..240592528565 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -45,7 +45,7 @@ abstract class DisplayDevice {
private Rect mCurrentDisplayRect;
// The display device owns its surface, but it should only set it
- // within a transaction from performTraversalInTransactionLocked.
+ // within a transaction from performTraversalLocked.
private Surface mCurrentSurface;
// DEBUG STATE: Last device info which was written to the log, or null if none.
@@ -122,7 +122,7 @@ abstract class DisplayDevice {
/**
* Gives the display device a chance to update its properties while in a transaction.
*/
- public void performTraversalInTransactionLocked() {
+ public void performTraversalLocked(SurfaceControl.Transaction t) {
}
/**
@@ -140,7 +140,7 @@ abstract class DisplayDevice {
/**
* Sets the mode, if supported.
*/
- public void requestDisplayModesInTransactionLocked(int colorMode, int modeId) {
+ public void requestDisplayModesLocked(int colorMode, int modeId) {
}
public void onOverlayChangedLocked() {
@@ -149,10 +149,10 @@ abstract class DisplayDevice {
/**
* Sets the display layer stack while in a transaction.
*/
- public final void setLayerStackInTransactionLocked(int layerStack) {
+ public final void setLayerStackLocked(SurfaceControl.Transaction t, int layerStack) {
if (mCurrentLayerStack != layerStack) {
mCurrentLayerStack = layerStack;
- SurfaceControl.setDisplayLayerStack(mDisplayToken, layerStack);
+ t.setDisplayLayerStack(mDisplayToken, layerStack);
}
}
@@ -166,7 +166,7 @@ abstract class DisplayDevice {
* mapped to. displayRect is specified post-orientation, that is
* it uses the orientation seen by the end-user
*/
- public final void setProjectionInTransactionLocked(int orientation,
+ public final void setProjectionLocked(SurfaceControl.Transaction t, int orientation,
Rect layerStackRect, Rect displayRect) {
if (mCurrentOrientation != orientation
|| mCurrentLayerStackRect == null
@@ -185,7 +185,7 @@ abstract class DisplayDevice {
}
mCurrentDisplayRect.set(displayRect);
- SurfaceControl.setDisplayProjection(mDisplayToken,
+ t.setDisplayProjection(mDisplayToken,
orientation, layerStackRect, displayRect);
}
}
@@ -193,10 +193,10 @@ abstract class DisplayDevice {
/**
* Sets the display surface while in a transaction.
*/
- public final void setSurfaceInTransactionLocked(Surface surface) {
+ public final void setSurfaceLocked(SurfaceControl.Transaction t, Surface surface) {
if (mCurrentSurface != surface) {
mCurrentSurface = surface;
- SurfaceControl.setDisplaySurface(mDisplayToken, surface);
+ t.setDisplaySurface(mDisplayToken, surface);
}
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index a5c1fe299e4e..9861ea735570 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -74,6 +74,7 @@ import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.Surface;
+import android.view.SurfaceControl;
import com.android.internal.util.Preconditions;
import com.android.server.AnimationThread;
@@ -457,14 +458,14 @@ public final class DisplayManagerService extends SystemService {
}
@VisibleForTesting
- void performTraversalInTransactionFromWindowManagerInternal() {
+ void performTraversalInternal(SurfaceControl.Transaction t) {
synchronized (mSyncRoot) {
if (!mPendingTraversal) {
return;
}
mPendingTraversal = false;
- performTraversalInTransactionLocked();
+ performTraversalLocked(t);
}
// List is self-synchronized copy-on-write.
@@ -1056,7 +1057,7 @@ public final class DisplayManagerService extends SystemService {
return changed;
}
- private void performTraversalInTransactionLocked() {
+ private void performTraversalLocked(SurfaceControl.Transaction t) {
// Clear all viewports before configuring displays so that we can keep
// track of which ones we have configured.
clearViewportsLocked();
@@ -1065,8 +1066,8 @@ public final class DisplayManagerService extends SystemService {
final int count = mDisplayDevices.size();
for (int i = 0; i < count; i++) {
DisplayDevice device = mDisplayDevices.get(i);
- configureDisplayInTransactionLocked(device);
- device.performTraversalInTransactionLocked();
+ configureDisplayLocked(t, device);
+ device.performTraversalLocked(t);
}
// Tell the input system about these new viewports.
@@ -1150,7 +1151,7 @@ public final class DisplayManagerService extends SystemService {
mVirtualTouchViewports.clear();
}
- private void configureDisplayInTransactionLocked(DisplayDevice device) {
+ private void configureDisplayLocked(SurfaceControl.Transaction t, DisplayDevice device) {
final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0;
@@ -1175,7 +1176,7 @@ public final class DisplayManagerService extends SystemService {
+ device.getDisplayDeviceInfoLocked());
return;
}
- display.configureDisplayInTransactionLocked(device, info.state == Display.STATE_OFF);
+ display.configureDisplayLocked(t, device, info.state == Display.STATE_OFF);
// Update the viewports if needed.
if (!mDefaultViewport.valid
@@ -1233,7 +1234,7 @@ public final class DisplayManagerService extends SystemService {
mHandler.sendMessage(msg);
}
- // Requests that performTraversalsInTransactionFromWindowManager be called at a
+ // Requests that performTraversals be called at a
// later time to apply changes to surfaces and displays.
private void scheduleTraversalLocked(boolean inTraversal) {
if (!mPendingTraversal && mWindowManagerInternal != null) {
@@ -2031,8 +2032,8 @@ public final class DisplayManagerService extends SystemService {
}
@Override
- public void performTraversalInTransactionFromWindowManager() {
- performTraversalInTransactionFromWindowManagerInternal();
+ public void performTraversal(SurfaceControl.Transaction t) {
+ performTraversalInternal(t);
}
@Override
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 0d8ec6d23089..5ca9abc8355d 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -584,10 +584,9 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
@Override
- public void requestDisplayModesInTransactionLocked(
- int colorMode, int modeId) {
- if (requestModeInTransactionLocked(modeId) ||
- requestColorModeInTransactionLocked(colorMode)) {
+ public void requestDisplayModesLocked(int colorMode, int modeId) {
+ if (requestModeLocked(modeId) ||
+ requestColorModeLocked(colorMode)) {
updateDeviceInfoLocked();
}
}
@@ -597,7 +596,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
updateDeviceInfoLocked();
}
- public boolean requestModeInTransactionLocked(int modeId) {
+ public boolean requestModeLocked(int modeId) {
if (modeId == 0) {
modeId = mDefaultModeId;
} else if (mSupportedModes.indexOfKey(modeId) < 0) {
@@ -623,7 +622,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return true;
}
- public boolean requestColorModeInTransactionLocked(int colorMode) {
+ public boolean requestColorModeLocked(int colorMode) {
if (mActiveColorMode == colorMode) {
return false;
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index e582fdf63472..23ee56b24b19 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -21,6 +21,7 @@ import android.hardware.display.DisplayManagerInternal;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.Surface;
+import android.view.SurfaceControl;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -304,17 +305,18 @@ final class LogicalDisplay {
* @param device The display device to modify.
* @param isBlanked True if the device is being blanked.
*/
- public void configureDisplayInTransactionLocked(DisplayDevice device,
+ public void configureDisplayLocked(SurfaceControl.Transaction t,
+ DisplayDevice device,
boolean isBlanked) {
// Set the layer stack.
- device.setLayerStackInTransactionLocked(isBlanked ? BLANK_LAYER_STACK : mLayerStack);
+ device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack);
// Set the color mode and mode.
if (device == mPrimaryDisplayDevice) {
- device.requestDisplayModesInTransactionLocked(
+ device.requestDisplayModesLocked(
mRequestedColorMode, mRequestedModeId);
} else {
- device.requestDisplayModesInTransactionLocked(0, 0); // Revert to default.
+ device.requestDisplayModesLocked(0, 0); // Revert to default.
}
// Only grab the display info now as it may have been changed based on the requests above.
@@ -377,7 +379,7 @@ final class LogicalDisplay {
mTempDisplayRect.right += mDisplayOffsetX;
mTempDisplayRect.top += mDisplayOffsetY;
mTempDisplayRect.bottom += mDisplayOffsetY;
- device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect);
+ device.setProjectionLocked(t, orientation, mTempLayerStackRect, mTempDisplayRect);
}
/**
diff --git a/services/core/java/com/android/server/display/OWNERS b/services/core/java/com/android/server/display/OWNERS
index 83614219a3b5..98e32997e587 100644
--- a/services/core/java/com/android/server/display/OWNERS
+++ b/services/core/java/com/android/server/display/OWNERS
@@ -1,3 +1,5 @@
michaelwr@google.com
+hackbod@google.com
+ogunwale@google.com
-per-file ColorDisplayService.java=christyfranks@google.com \ No newline at end of file
+per-file ColorDisplayService.java=christyfranks@google.com
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 27327d4eb100..e65637f04975 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -271,12 +271,12 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
}
@Override
- public void performTraversalInTransactionLocked() {
+ public void performTraversalLocked(SurfaceControl.Transaction t) {
if (mSurfaceTexture != null) {
if (mSurface == null) {
mSurface = new Surface(mSurfaceTexture);
}
- setSurfaceInTransactionLocked(mSurface);
+ setSurfaceLocked(t, mSurface);
}
}
@@ -315,7 +315,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
}
@Override
- public void requestDisplayModesInTransactionLocked(int color, int id) {
+ public void requestDisplayModesLocked(int color, int id) {
int index = -1;
if (id == 0) {
// Use the default.
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index f86d57634bff..6111c23f252c 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -269,12 +269,12 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
}
@Override
- public void performTraversalInTransactionLocked() {
+ public void performTraversalLocked(SurfaceControl.Transaction t) {
if ((mPendingChanges & PENDING_RESIZE) != 0) {
- SurfaceControl.setDisplaySize(getDisplayTokenLocked(), mWidth, mHeight);
+ t.setDisplaySize(getDisplayTokenLocked(), mWidth, mHeight);
}
if ((mPendingChanges & PENDING_SURFACE_CHANGE) != 0) {
- setSurfaceInTransactionLocked(mSurface);
+ setSurfaceLocked(t, mSurface);
}
mPendingChanges = 0;
}
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index 329337933956..e8d6ad455fbf 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -620,9 +620,9 @@ final class WifiDisplayAdapter extends DisplayAdapter {
}
@Override
- public void performTraversalInTransactionLocked() {
+ public void performTraversalLocked(SurfaceControl.Transaction t) {
if (mSurface != null) {
- setSurfaceInTransactionLocked(mSurface);
+ setSurfaceLocked(t, mSurface);
}
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
index 1bd5f42e535f..5bfdf41a6654 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
@@ -45,6 +45,7 @@ import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertPath;
+import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -295,17 +296,23 @@ public class KeySyncTask implements Runnable {
// If application keys are not updated, snapshot will not be created on next unlock.
mRecoverableKeyStoreDb.setShouldCreateSnapshot(mUserId, recoveryAgentUid, false);
- mRecoverySnapshotStorage.put(recoveryAgentUid, new KeyChainSnapshot.Builder()
+ KeyChainSnapshot.Builder keyChainSnapshotBuilder = new KeyChainSnapshot.Builder()
.setSnapshotVersion(getSnapshotVersion(recoveryAgentUid, recreateCurrentVersion))
.setMaxAttempts(TRUSTED_HARDWARE_MAX_ATTEMPTS)
.setCounterId(counterId)
.setTrustedHardwarePublicKey(SecureBox.encodePublicKey(publicKey))
- .setTrustedHardwareCertPath(certPath)
.setServerParams(vaultHandle)
.setKeyChainProtectionParams(metadataList)
.setWrappedApplicationKeys(createApplicationKeyEntries(encryptedApplicationKeys))
- .setEncryptedRecoveryKeyBlob(encryptedRecoveryKey)
- .build());
+ .setEncryptedRecoveryKeyBlob(encryptedRecoveryKey);
+ try {
+ keyChainSnapshotBuilder.setTrustedHardwareCertPath(certPath);
+ } catch(CertificateException e) {
+ // Should not happen, as it's just deserialized from bytes stored in the db
+ Log.wtf(TAG, "Cannot serialize CertPath when calling setTrustedHardwareCertPath", e);
+ return;
+ }
+ mRecoverySnapshotStorage.put(recoveryAgentUid, keyChainSnapshotBuilder.build());
mSnapshotListenersStorage.recoverySnapshotAvailable(recoveryAgentUid);
}
diff --git a/services/core/java/com/android/server/media/OWNERS b/services/core/java/com/android/server/media/OWNERS
index 755c1d6f8aff..8adea0e85d12 100644
--- a/services/core/java/com/android/server/media/OWNERS
+++ b/services/core/java/com/android/server/media/OWNERS
@@ -1,3 +1,4 @@
lajos@google.com
elaurent@google.com
sungsoo@google.com
+jaewan@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 108247844c64..5430d44504a0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -176,6 +176,7 @@ import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.PackageParser.ParseFlags;
import android.content.pm.PackageParser.ServiceIntentInfo;
+import android.content.pm.PackageParser.SigningDetails;
import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
import android.content.pm.PackageStats;
import android.content.pm.PackageUserState;
@@ -23383,6 +23384,36 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
@Override
+ public boolean isDataRestoreSafe(byte[] restoringFromSigHash, String packageName) {
+ SigningDetails sd = getSigningDetails(packageName);
+ if (sd == null) {
+ return false;
+ }
+ return sd.hasSha256Certificate(restoringFromSigHash,
+ SigningDetails.CertCapabilities.INSTALLED_DATA);
+ }
+
+ @Override
+ public boolean isDataRestoreSafe(Signature restoringFromSig, String packageName) {
+ SigningDetails sd = getSigningDetails(packageName);
+ if (sd == null) {
+ return false;
+ }
+ return sd.hasCertificate(restoringFromSig,
+ SigningDetails.CertCapabilities.INSTALLED_DATA);
+ }
+
+ private SigningDetails getSigningDetails(@NonNull String packageName) {
+ synchronized (mPackages) {
+ PackageParser.Package p = mPackages.get(packageName);
+ if (p == null) {
+ return null;
+ }
+ return p.mSigningDetails;
+ }
+ }
+
+ @Override
public int getPermissionFlagsTEMP(String permName, String packageName, int userId) {
return PackageManagerService.this.getPermissionFlags(permName, packageName, userId);
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
index 520ed2526b17..eeaa3330dee4 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
@@ -18,10 +18,13 @@ package com.android.server.pm;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.ShortcutInfo;
+import android.content.pm.Signature;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
import com.android.server.backup.BackupUtils;
import libcore.util.HexEncoding;
@@ -137,7 +140,8 @@ class ShortcutPackageInfo {
//@DisabledReason
public int canRestoreTo(ShortcutService s, PackageInfo currentPackage, boolean anyVersionOkay) {
- if (!BackupUtils.signaturesMatch(mSigHashes, currentPackage)) {
+ PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+ if (!BackupUtils.signaturesMatch(mSigHashes, currentPackage, pmi)) {
Slog.w(TAG, "Can't restore: Package signature mismatch");
return ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH;
}
@@ -159,13 +163,15 @@ class ShortcutPackageInfo {
public static ShortcutPackageInfo generateForInstalledPackageForTest(
ShortcutService s, String packageName, @UserIdInt int packageUserId) {
final PackageInfo pi = s.getPackageInfoWithSignatures(packageName, packageUserId);
- if (pi.signatures == null || pi.signatures.length == 0) {
+ // retrieve the newest sigs
+ Signature[][] signingHistory = pi.signingCertificateHistory;
+ if (signingHistory == null || signingHistory.length == 0) {
Slog.e(TAG, "Can't get signatures: package=" + packageName);
return null;
}
+ Signature[] signatures = signingHistory[signingHistory.length - 1];
final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.getLongVersionCode(),
- pi.lastUpdateTime, BackupUtils.hashSignatureArray(pi.signatures),
- /* shadow=*/ false);
+ pi.lastUpdateTime, BackupUtils.hashSignatureArray(signatures), /* shadow=*/ false);
ret.mBackupSourceBackupAllowed = s.shouldBackupApp(pi);
ret.mBackupSourceVersionCode = pi.getLongVersionCode();
@@ -185,7 +191,15 @@ class ShortcutPackageInfo {
Slog.w(TAG, "Package not found: " + pkg.getPackageName());
return;
}
- mSigHashes = BackupUtils.hashSignatureArray(pi.signatures);
+ // retrieve the newest sigs
+ Signature[][] signingHistory = pi.signingCertificateHistory;
+ if (signingHistory == null || signingHistory.length == 0) {
+ Slog.w(TAG, "Not refreshing signature for " + pkg.getPackageName()
+ + " since it appears to have no signature history.");
+ return;
+ }
+ Signature[] signatures = signingHistory[signingHistory.length - 1];
+ mSigHashes = BackupUtils.hashSignatureArray(signatures);
}
public void saveToXml(ShortcutService s, XmlSerializer out, boolean forBackup)
@@ -221,7 +235,6 @@ class ShortcutPackageInfo {
public void loadFromXml(XmlPullParser parser, boolean fromBackup)
throws IOException, XmlPullParserException {
-
// Don't use the version code from the backup file.
final long versionCode = ShortcutService.parseLongAttribute(parser, ATTR_VERSION,
ShortcutInfo.VERSION_CODE_UNKNOWN);
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 265cc8ebe4d3..15b461729495 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -3121,7 +3121,8 @@ public class ShortcutService extends IShortcutService.Stub {
try {
return mIPackageManager.getPackageInfo(
packageName, PACKAGE_MATCH_FLAGS
- | (getSignatures ? PackageManager.GET_SIGNATURES : 0), userId);
+ | (getSignatures ? PackageManager.GET_SIGNING_CERTIFICATES : 0),
+ userId);
} catch (RemoteException e) {
// Shouldn't happen.
Slog.wtf(TAG, "RemoteException", e);
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index b2f153a74699..fef615d651b1 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1092,7 +1092,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
mService.registerAppFreezeListener(this);
mService.mAppsFreezingScreen++;
if (mService.mAppsFreezingScreen == 1) {
- mService.startFreezingDisplayLocked(false, 0, 0, getDisplayContent());
+ mService.startFreezingDisplayLocked(0, 0, getDisplayContent());
mService.mH.removeMessages(H.APP_FREEZE_TIMEOUT);
mService.mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000);
}
diff --git a/services/core/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java
index f19cd0ff96f7..1977e126a8a0 100644
--- a/services/core/java/com/android/server/wm/BlackFrame.java
+++ b/services/core/java/com/android/server/wm/BlackFrame.java
@@ -41,7 +41,7 @@ public class BlackFrame {
final int layer;
final SurfaceControl surface;
- BlackSurface(int layer,
+ BlackSurface(SurfaceControl.Transaction transaction, int layer,
int l, int t, int r, int b, DisplayContent dc) throws OutOfResourcesException {
left = l;
top = t;
@@ -56,24 +56,24 @@ public class BlackFrame {
.setParent(null) // TODO: Work-around for b/69259549
.build();
- surface.setAlpha(1);
- surface.setLayer(layer);
- surface.show();
+ transaction.setAlpha(surface, 1);
+ transaction.setLayer(surface, layer);
+ transaction.show(surface);
if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM,
" BLACK " + surface + ": CREATE layer=" + layer);
}
- void setAlpha(float alpha) {
- surface.setAlpha(alpha);
+ void setAlpha(SurfaceControl.Transaction t, float alpha) {
+ t.setAlpha(surface, alpha);
}
- void setMatrix(Matrix matrix) {
+ void setMatrix(SurfaceControl.Transaction t, Matrix matrix) {
mTmpMatrix.setTranslate(left, top);
mTmpMatrix.postConcat(matrix);
mTmpMatrix.getValues(mTmpFloats);
- surface.setPosition(mTmpFloats[Matrix.MTRANS_X],
+ t.setPosition(surface, mTmpFloats[Matrix.MTRANS_X],
mTmpFloats[Matrix.MTRANS_Y]);
- surface.setMatrix(
+ t.setMatrix(surface,
mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
if (false) {
@@ -87,8 +87,8 @@ public class BlackFrame {
}
}
- void clearMatrix() {
- surface.setMatrix(1, 0, 0, 1);
+ void clearMatrix(SurfaceControl.Transaction t) {
+ t.setMatrix(surface, 1, 0, 0, 1);
}
}
@@ -113,7 +113,8 @@ public class BlackFrame {
}
}
- public BlackFrame(Rect outer, Rect inner, int layer, DisplayContent dc,
+ public BlackFrame(SurfaceControl.Transaction t,
+ Rect outer, Rect inner, int layer, DisplayContent dc,
boolean forceDefaultOrientation) throws OutOfResourcesException {
boolean success = false;
@@ -125,19 +126,19 @@ public class BlackFrame {
mInnerRect = new Rect(inner);
try {
if (outer.top < inner.top) {
- mBlackSurfaces[0] = new BlackSurface(layer,
+ mBlackSurfaces[0] = new BlackSurface(t, layer,
outer.left, outer.top, inner.right, inner.top, dc);
}
if (outer.left < inner.left) {
- mBlackSurfaces[1] = new BlackSurface(layer,
+ mBlackSurfaces[1] = new BlackSurface(t, layer,
outer.left, inner.top, inner.left, outer.bottom, dc);
}
if (outer.bottom > inner.bottom) {
- mBlackSurfaces[2] = new BlackSurface(layer,
+ mBlackSurfaces[2] = new BlackSurface(t, layer,
inner.left, inner.bottom, outer.right, outer.bottom, dc);
}
if (outer.right > inner.right) {
- mBlackSurfaces[3] = new BlackSurface(layer,
+ mBlackSurfaces[3] = new BlackSurface(t, layer,
inner.right, outer.top, outer.right, inner.bottom, dc);
}
success = true;
@@ -161,36 +162,36 @@ public class BlackFrame {
}
}
- public void hide() {
+ public void hide(SurfaceControl.Transaction t) {
if (mBlackSurfaces != null) {
for (int i=0; i<mBlackSurfaces.length; i++) {
if (mBlackSurfaces[i] != null) {
- mBlackSurfaces[i].surface.hide();
+ t.hide(mBlackSurfaces[i].surface);
}
}
}
}
- public void setAlpha(float alpha) {
+ public void setAlpha(SurfaceControl.Transaction t, float alpha) {
for (int i=0; i<mBlackSurfaces.length; i++) {
if (mBlackSurfaces[i] != null) {
- mBlackSurfaces[i].setAlpha(alpha);
+ mBlackSurfaces[i].setAlpha(t, alpha);
}
}
}
- public void setMatrix(Matrix matrix) {
+ public void setMatrix(SurfaceControl.Transaction t, Matrix matrix) {
for (int i=0; i<mBlackSurfaces.length; i++) {
if (mBlackSurfaces[i] != null) {
- mBlackSurfaces[i].setMatrix(matrix);
+ mBlackSurfaces[i].setMatrix(t, matrix);
}
}
}
- public void clearMatrix() {
+ public void clearMatrix(SurfaceControl.Transaction t) {
for (int i=0; i<mBlackSurfaces.length; i++) {
if (mBlackSurfaces[i] != null) {
- mBlackSurfaces[i].clearMatrix();
+ mBlackSurfaces[i].clearMatrix(t);
}
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2dce9133d094..59babcfe0371 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -258,7 +258,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
* Current rotation of the display.
* Constants as per {@link android.view.Surface.Rotation}.
*
- * @see #updateRotationUnchecked(boolean)
+ * @see #updateRotationUnchecked()
*/
private int mRotation = 0;
@@ -274,7 +274,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
* Flag indicating that the application is receiving an orientation that has different metrics
* than it expected. E.g. Portrait instead of Landscape.
*
- * @see #updateRotationUnchecked(boolean)
+ * @see #updateRotationUnchecked()
*/
private boolean mAltOrientation = false;
@@ -926,7 +926,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
* Returns true if the rotation has been changed. In this case YOU MUST CALL
* {@link WindowManagerService#sendNewConfiguration(int)} TO UNFREEZE THE SCREEN.
*/
- boolean updateRotationUnchecked(boolean inTransaction) {
+ boolean updateRotationUnchecked() {
if (mService.mDeferredRotationPauseCount > 0) {
// Rotation updates have been paused temporarily. Defer the update until
// updates have been resumed.
@@ -1030,7 +1030,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mService.mPolicy.selectRotationAnimationLw(anim);
if (!rotateSeamlessly) {
- mService.startFreezingDisplayLocked(inTransaction, anim[0], anim[1], this);
+ mService.startFreezingDisplayLocked(anim[0], anim[1], this);
// startFreezingDisplayLocked can reset the ScreenRotationAnimation.
screenRotationAnimation = mService.mAnimator.getScreenRotationAnimationLocked(
mDisplayId);
@@ -1041,9 +1041,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// to their rotated state independently and without a freeze required.
screenRotationAnimation = null;
- // We have to reset this in case a window was removed before it
- // finished seamless rotation.
- mService.mSeamlessRotationCount = 0;
+ mService.startSeamlessRotation();
}
// We need to update our screen size information to match the new rotation. If the rotation
@@ -1053,40 +1051,27 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// #computeScreenConfiguration() later.
updateDisplayAndOrientation(getConfiguration().uiMode);
- if (!inTransaction) {
- if (SHOW_TRANSACTIONS) {
- Slog.i(TAG_WM, ">>> OPEN TRANSACTION setRotationUnchecked");
+ // NOTE: We disable the rotation in the emulator because
+ // it doesn't support hardware OpenGL emulation yet.
+ if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
+ && screenRotationAnimation.hasScreenshot()) {
+ if (screenRotationAnimation.setRotation(getPendingTransaction(), rotation,
+ MAX_ANIMATION_DURATION, mService.getTransitionAnimationScaleLocked(),
+ mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight)) {
+ mService.scheduleAnimationLocked();
}
- mService.openSurfaceTransaction();
}
- try {
- // NOTE: We disable the rotation in the emulator because
- // it doesn't support hardware OpenGL emulation yet.
- if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
- && screenRotationAnimation.hasScreenshot()) {
- if (screenRotationAnimation.setRotationInTransaction(rotation,
- MAX_ANIMATION_DURATION, mService.getTransitionAnimationScaleLocked(),
- mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight)) {
- mService.scheduleAnimationLocked();
- }
- }
- if (rotateSeamlessly) {
- forAllWindows(w -> {
- w.mWinAnimator.seamlesslyRotateWindow(oldRotation, rotation);
- }, true /* traverseTopToBottom */);
- }
-
- mService.mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
- } finally {
- if (!inTransaction) {
- mService.closeSurfaceTransaction("setRotationUnchecked");
- if (SHOW_LIGHT_TRANSACTIONS) {
- Slog.i(TAG_WM, "<<< CLOSE TRANSACTION setRotationUnchecked");
- }
- }
+ if (rotateSeamlessly) {
+ forAllWindows(w -> {
+ w.mWinAnimator.seamlesslyRotateWindow(getPendingTransaction(),
+ oldRotation, rotation);
+ }, true /* traverseTopToBottom */);
}
+ mService.mDisplayManagerInternal.performTraversal(getPendingTransaction());
+ scheduleAnimation();
+
forAllWindows(w -> {
if (w.mHasSurface && !rotateSeamlessly) {
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Set mOrientationChanging of " + w);
@@ -2808,7 +2793,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
if (isDefaultDisplay && (pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) {
if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
- if (mService.updateOrientationFromAppTokensLocked(true, mDisplayId)) {
+ if (mService.updateOrientationFromAppTokensLocked(mDisplayId)) {
setLayoutNeeded();
mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, mDisplayId).sendToTarget();
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index f32c275b61f1..32ae52375fd5 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -37,6 +37,7 @@ import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.DisplayInfo;
+import android.view.SurfaceControl;
import android.view.WindowManager;
import com.android.internal.util.ArrayUtils;
@@ -128,6 +129,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
private final Handler mHandler;
private String mCloseSystemDialogsReason;
+
+ // Only a seperate transaction until we seperate the apply surface changes
+ // transaction from the global transaction.
+ private final SurfaceControl.Transaction mDisplayTransaction = new SurfaceControl.Transaction();
+
private final Consumer<WindowState> mCloseSystemDialogsConsumer = w -> {
if (w.mHasSurface) {
try {
@@ -725,7 +731,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
// TODO(multi-display): Update rotation for different displays separately.
final int displayId = defaultDisplay.getDisplayId();
- if (defaultDisplay.updateRotationUnchecked(false /* inTransaction */)) {
+ if (defaultDisplay.updateRotationUnchecked()) {
mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayId).sendToTarget();
} else {
mUpdateRotation = false;
@@ -735,7 +741,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
// PhoneWindowManager.
final DisplayContent vrDisplay = mService.mVr2dDisplayId != INVALID_DISPLAY
? getDisplayContent(mService.mVr2dDisplayId) : null;
- if (vrDisplay != null && vrDisplay.updateRotationUnchecked(false /* inTransaction */)) {
+ if (vrDisplay != null && vrDisplay.updateRotationUnchecked()) {
mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, mService.mVr2dDisplayId)
.sendToTarget();
}
@@ -835,7 +841,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
// Give the display manager a chance to adjust properties like display rotation if it needs
// to.
- mService.mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
+ mService.mDisplayManagerInternal.performTraversal(mDisplayTransaction);
+ SurfaceControl.mergeToGlobalTransaction(mDisplayTransaction);
}
/**
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 5a39de5c3242..ad2fabb70299 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -224,8 +224,7 @@ class ScreenRotationAnimation {
}
public ScreenRotationAnimation(Context context, DisplayContent displayContent,
- boolean inTransaction, boolean forceDefaultOrientation,
- boolean isSecure, WindowManagerService service) {
+ boolean forceDefaultOrientation, boolean isSecure, WindowManagerService service) {
mService = service;
mContext = context;
mDisplayContent = displayContent;
@@ -260,52 +259,39 @@ class ScreenRotationAnimation {
mOriginalWidth = originalWidth;
mOriginalHeight = originalHeight;
- if (!inTransaction) {
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
- ">>> OPEN TRANSACTION ScreenRotationAnimation");
- mService.openSurfaceTransaction();
- }
-
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
try {
- try {
- mSurfaceControl = displayContent.makeOverlay()
- .setName("ScreenshotSurface")
- .setSize(mWidth, mHeight)
- .setSecure(isSecure)
- .build();
-
- // capture a screenshot into the surface we just created
- Surface sur = new Surface();
- sur.copyFrom(mSurfaceControl);
- // TODO(multidisplay): we should use the proper display
- SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay(
- SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), sur);
- mSurfaceControl.setLayer(SCREEN_FREEZE_LAYER_SCREENSHOT);
- mSurfaceControl.setAlpha(0);
- mSurfaceControl.show();
- sur.destroy();
- } catch (OutOfResourcesException e) {
- Slog.w(TAG, "Unable to allocate freeze surface", e);
- }
-
- if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM,
- " FREEZE " + mSurfaceControl + ": CREATE");
-
- setRotationInTransaction(originalRotation);
- } finally {
- if (!inTransaction) {
- mService.closeSurfaceTransaction("ScreenRotationAnimation");
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
- "<<< CLOSE TRANSACTION ScreenRotationAnimation");
- }
- }
+ mSurfaceControl = displayContent.makeOverlay()
+ .setName("ScreenshotSurface")
+ .setSize(mWidth, mHeight)
+ .setSecure(isSecure)
+ .build();
+
+ // capture a screenshot into the surface we just created
+ Surface sur = new Surface();
+ sur.copyFrom(mSurfaceControl);
+ // TODO(multidisplay): we should use the proper display
+ SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay(
+ SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), sur);
+ t.setLayer(mSurfaceControl, SCREEN_FREEZE_LAYER_SCREENSHOT);
+ t.setAlpha(mSurfaceControl, 0);
+ t.show(mSurfaceControl);
+ sur.destroy();
+ } catch (OutOfResourcesException e) {
+ Slog.w(TAG, "Unable to allocate freeze surface", e);
+ }
+
+ if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM,
+ " FREEZE " + mSurfaceControl + ": CREATE");
+ setRotation(t, originalRotation);
+ t.apply();
}
boolean hasScreenshot() {
return mSurfaceControl != null;
}
- private void setSnapshotTransformInTransaction(Matrix matrix, float alpha) {
+ private void setSnapshotTransform(SurfaceControl.Transaction t, Matrix matrix, float alpha) {
if (mSurfaceControl != null) {
matrix.getValues(mTmpFloats);
float x = mTmpFloats[Matrix.MTRANS_X];
@@ -315,11 +301,11 @@ class ScreenRotationAnimation {
x -= mCurrentDisplayRect.left;
y -= mCurrentDisplayRect.top;
}
- mSurfaceControl.setPosition(x, y);
- mSurfaceControl.setMatrix(
+ t.setPosition(mSurfaceControl, x, y);
+ t.setMatrix(mSurfaceControl,
mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
- mSurfaceControl.setAlpha(alpha);
+ t.setAlpha(mSurfaceControl, alpha);
if (DEBUG_TRANSFORMS) {
float[] srcPnts = new float[] { 0, 0, mWidth, mHeight };
float[] dstPnts = new float[4];
@@ -353,8 +339,7 @@ class ScreenRotationAnimation {
}
}
- // Must be called while in a transaction.
- private void setRotationInTransaction(int rotation) {
+ private void setRotation(SurfaceControl.Transaction t, int rotation) {
mCurRotation = rotation;
// Compute the transformation matrix that must be applied
@@ -364,15 +349,14 @@ class ScreenRotationAnimation {
createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
if (DEBUG_STATE) Slog.v(TAG, "**** ROTATION: " + delta);
- setSnapshotTransformInTransaction(mSnapshotInitialMatrix, 1.0f);
+ setSnapshotTransform(t, mSnapshotInitialMatrix, 1.0f);
}
- // Must be called while in a transaction.
- public boolean setRotationInTransaction(int rotation,
+ public boolean setRotation(SurfaceControl.Transaction t, int rotation,
long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight) {
- setRotationInTransaction(rotation);
+ setRotation(t, rotation);
if (TWO_PHASE_ANIMATION) {
- return startAnimation(maxAnimationDuration, animationScale,
+ return startAnimation(t, maxAnimationDuration, animationScale,
finalWidth, finalHeight, false, 0, 0);
}
@@ -383,7 +367,7 @@ class ScreenRotationAnimation {
/**
* Returns true if animating.
*/
- private boolean startAnimation(long maxAnimationDuration,
+ private boolean startAnimation(SurfaceControl.Transaction t, long maxAnimationDuration,
float animationScale, int finalWidth, int finalHeight, boolean dismissing,
int exitAnim, int enterAnim) {
if (mSurfaceControl == null) {
@@ -542,11 +526,6 @@ class ScreenRotationAnimation {
final int layerStack = mDisplayContent.getDisplay().getLayerStack();
if (USE_CUSTOM_BLACK_FRAME && mCustomBlackFrame == null) {
- if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
- TAG_WM,
- ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
- mService.openSurfaceTransaction();
-
// Compute the transformation matrix that must be applied
// the the black frame to make it stay in the initial position
// before the new screen rotation. This is different than the
@@ -559,24 +538,15 @@ class ScreenRotationAnimation {
Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1,
mOriginalWidth*2, mOriginalHeight*2);
Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
- mCustomBlackFrame = new BlackFrame(outer, inner,
+ mCustomBlackFrame = new BlackFrame(t, outer, inner,
SCREEN_FREEZE_LAYER_CUSTOM, mDisplayContent, false);
- mCustomBlackFrame.setMatrix(mFrameInitialMatrix);
+ mCustomBlackFrame.setMatrix(t, mFrameInitialMatrix);
} catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
- } finally {
- mService.closeSurfaceTransaction("ScreenRotationAnimation.startAnimation");
- if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
- TAG_WM,
- "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
}
}
if (!customAnim && mExitingBlackFrame == null) {
- if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
- TAG_WM,
- ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
- mService.openSurfaceTransaction();
try {
// Compute the transformation matrix that must be applied
// the the black frame to make it stay in the initial position
@@ -599,38 +569,23 @@ class ScreenRotationAnimation {
mOriginalWidth*2, mOriginalHeight*2);
inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
}
- mExitingBlackFrame = new BlackFrame(outer, inner,
+ mExitingBlackFrame = new BlackFrame(t, outer, inner,
SCREEN_FREEZE_LAYER_EXIT, mDisplayContent, mForceDefaultOrientation);
- mExitingBlackFrame.setMatrix(mFrameInitialMatrix);
+ mExitingBlackFrame.setMatrix(t, mFrameInitialMatrix);
} catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
- } finally {
- mService.closeSurfaceTransaction("ScreenRotationAnimation.startAnimation");
- if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
- TAG_WM,
- "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
}
}
if (customAnim && mEnteringBlackFrame == null) {
- if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
- TAG_WM,
- ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
- mService.openSurfaceTransaction();
-
try {
Rect outer = new Rect(-finalWidth*1, -finalHeight*1,
finalWidth*2, finalHeight*2);
Rect inner = new Rect(0, 0, finalWidth, finalHeight);
- mEnteringBlackFrame = new BlackFrame(outer, inner,
+ mEnteringBlackFrame = new BlackFrame(t, outer, inner,
SCREEN_FREEZE_LAYER_ENTER, mDisplayContent, false);
} catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
- } finally {
- mService.closeSurfaceTransaction("ScreenRotationAnimation.startAnimation");
- if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
- TAG_WM,
- "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
}
}
@@ -640,7 +595,7 @@ class ScreenRotationAnimation {
/**
* Returns true if animating.
*/
- public boolean dismiss(long maxAnimationDuration,
+ public boolean dismiss(SurfaceControl.Transaction t, long maxAnimationDuration,
float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
if (DEBUG_STATE) Slog.v(TAG, "Dismiss!");
if (mSurfaceControl == null) {
@@ -648,7 +603,7 @@ class ScreenRotationAnimation {
return false;
}
if (!mStarted) {
- startAnimation(maxAnimationDuration, animationScale, finalWidth, finalHeight,
+ startAnimation(t, maxAnimationDuration, animationScale, finalWidth, finalHeight,
true, exitAnim, enterAnim);
}
if (!mStarted) {
@@ -919,7 +874,7 @@ class ScreenRotationAnimation {
return more;
}
- void updateSurfacesInTransaction() {
+ void updateSurfaces(SurfaceControl.Transaction t) {
if (!mStarted) {
return;
}
@@ -927,28 +882,28 @@ class ScreenRotationAnimation {
if (mSurfaceControl != null) {
if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) {
if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, hiding screenshot surface");
- mSurfaceControl.hide();
+ t.hide(mSurfaceControl);
}
}
if (mCustomBlackFrame != null) {
if (!mMoreStartFrame && !mMoreFinishFrame && !mMoreRotateFrame) {
if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding black frame");
- mCustomBlackFrame.hide();
+ mCustomBlackFrame.hide(t);
} else {
- mCustomBlackFrame.setMatrix(mFrameTransformation.getMatrix());
+ mCustomBlackFrame.setMatrix(t, mFrameTransformation.getMatrix());
}
}
if (mExitingBlackFrame != null) {
if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) {
if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding exiting frame");
- mExitingBlackFrame.hide();
+ mExitingBlackFrame.hide(t);
} else {
mExitFrameFinalMatrix.setConcat(mExitTransformation.getMatrix(), mFrameInitialMatrix);
- mExitingBlackFrame.setMatrix(mExitFrameFinalMatrix);
+ mExitingBlackFrame.setMatrix(t, mExitFrameFinalMatrix);
if (mForceDefaultOrientation) {
- mExitingBlackFrame.setAlpha(mExitTransformation.getAlpha());
+ mExitingBlackFrame.setAlpha(t, mExitTransformation.getAlpha());
}
}
}
@@ -956,13 +911,13 @@ class ScreenRotationAnimation {
if (mEnteringBlackFrame != null) {
if (!mMoreStartEnter && !mMoreFinishEnter && !mMoreRotateEnter) {
if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding entering frame");
- mEnteringBlackFrame.hide();
+ mEnteringBlackFrame.hide(t);
} else {
- mEnteringBlackFrame.setMatrix(mEnterTransformation.getMatrix());
+ mEnteringBlackFrame.setMatrix(t, mEnterTransformation.getMatrix());
}
}
- setSnapshotTransformInTransaction(mSnapshotFinalMatrix, mExitTransformation.getAlpha());
+ setSnapshotTransform(t, mSnapshotFinalMatrix, mExitTransformation.getAlpha());
}
public boolean stepAnimationLocked(long now) {
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index ab1019779b0b..793ffce2466e 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -30,6 +30,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
import android.view.Choreographer;
+import android.view.SurfaceControl;
import com.android.server.AnimationThread;
import com.android.server.policy.WindowManagerPolicy;
@@ -94,6 +95,8 @@ public class WindowAnimator {
private final ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>();
private boolean mInExecuteAfterPrepareSurfacesRunnables;
+ private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+
WindowAnimator(final WindowManagerService service) {
mService = service;
mContext = service.mContext;
@@ -203,7 +206,7 @@ public class WindowAnimator {
final ScreenRotationAnimation screenRotationAnimation =
mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation;
if (screenRotationAnimation != null) {
- screenRotationAnimation.updateSurfacesInTransaction();
+ screenRotationAnimation.updateSurfaces(mTransaction);
}
orAnimating(dc.getDockedDividerController().animate(mCurrentTime));
//TODO (multidisplay): Magnification is supported only for the default display.
@@ -219,6 +222,8 @@ public class WindowAnimator {
if (mService.mWatermark != null) {
mService.mWatermark.drawIfNeeded();
}
+
+ SurfaceControl.mergeToGlobalTransaction(mTransaction);
} catch (RuntimeException e) {
Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
} finally {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 82fbb51b0e29..be009d2af8ff 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -667,11 +667,18 @@ public class WindowManagerService extends IWindowManager.Stub
WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
SettingsObserver mSettingsObserver;
- // A count of the windows which are 'seamlessly rotated', e.g. a surface
- // at an old orientation is being transformed. We freeze orientation updates
- // while any windows are seamlessly rotated, so we need to track when this
- // hits zero so we can apply deferred orientation updates.
- int mSeamlessRotationCount = 0;
+ /**
+ * A count of the windows which are 'seamlessly rotated', e.g. a surface
+ * at an old orientation is being transformed. We freeze orientation updates
+ * while any windows are seamlessly rotated, so we need to track when this
+ * hits zero so we can apply deferred orientation updates.
+ */
+ private int mSeamlessRotationCount = 0;
+ /**
+ * True in the interval from starting seamless rotation until the last rotated
+ * window draws in the new orientation.
+ */
+ private boolean mRotatingSeamlessly = false;
private final class SettingsObserver extends ContentObserver {
private final Uri mDisplayInversionEnabledUri =
@@ -809,6 +816,8 @@ public class WindowManagerService extends IWindowManager.Stub
SurfaceBuilderFactory mSurfaceBuilderFactory = SurfaceControl.Builder::new;
TransactionFactory mTransactionFactory = SurfaceControl.Transaction::new;
+ private final SurfaceControl.Transaction mTransaction = mTransactionFactory.make();
+
static void boostPriorityForLockedSection() {
sThreadPriorityBooster.boost();
}
@@ -1487,7 +1496,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (localLOGV || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addWindow: New client "
+ client.asBinder() + ": window=" + win + " Callers=" + Debug.getCallers(5));
- if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false, displayId)) {
+ if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(displayId)) {
reportNewConfig = true;
}
}
@@ -2049,7 +2058,7 @@ public class WindowManagerService extends IWindowManager.Stub
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
"relayoutWindow: updateOrientationFromAppTokens");
- configChanged = updateOrientationFromAppTokensLocked(false, displayId);
+ configChanged = updateOrientationFromAppTokensLocked(displayId);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (toBeDisplayed && win.mIsWallpaper) {
@@ -2340,7 +2349,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
Configuration config = null;
- if (updateOrientationFromAppTokensLocked(false, displayId)) {
+ if (updateOrientationFromAppTokensLocked(displayId)) {
// If we changed the orientation but mOrientationChangeComplete is already true,
// we used seamless rotation, and we don't need to freeze the screen.
if (freezeThisOneIfNeeded != null && !mRoot.mOrientationChangeComplete) {
@@ -2367,7 +2376,7 @@ public class WindowManagerService extends IWindowManager.Stub
int anim[] = new int[2];
mPolicy.selectRotationAnimationLw(anim);
- startFreezingDisplayLocked(false, anim[0], anim[1], displayContent);
+ startFreezingDisplayLocked(anim[0], anim[1], displayContent);
config = new Configuration(mTempConfiguration);
}
}
@@ -2387,7 +2396,7 @@ public class WindowManagerService extends IWindowManager.Stub
* tokens.
* @see android.view.IWindowManager#updateOrientationFromAppTokens(Configuration, IBinder, int)
*/
- boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId) {
+ boolean updateOrientationFromAppTokensLocked(int displayId) {
long ident = Binder.clearCallingIdentity();
try {
final DisplayContent dc = mRoot.getDisplayContent(displayId);
@@ -2400,7 +2409,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (dc.isDefaultDisplay) {
mPolicy.setCurrentOrientationLw(req);
}
- if (dc.updateRotationUnchecked(inTransaction)) {
+ if (dc.updateRotationUnchecked()) {
// changed
return true;
}
@@ -2873,7 +2882,7 @@ public class WindowManagerService extends IWindowManager.Stub
mClientFreezingScreen = true;
final long origId = Binder.clearCallingIdentity();
try {
- startFreezingDisplayLocked(false, exitAnim, enterAnim);
+ startFreezingDisplayLocked(exitAnim, enterAnim);
mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
mH.sendEmptyMessageDelayed(H.CLIENT_FREEZE_TIMEOUT, 5000);
} finally {
@@ -3774,8 +3783,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (mDeferredRotationPauseCount == 0) {
// TODO(multi-display): Update rotation for different displays separately.
final DisplayContent displayContent = getDefaultDisplayContentLocked();
- final boolean changed = displayContent.updateRotationUnchecked(
- false /* inTransaction */);
+ final boolean changed = displayContent.updateRotationUnchecked();
if (changed) {
mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayContent.getDisplayId())
.sendToTarget();
@@ -3800,8 +3808,7 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized (mWindowMap) {
final DisplayContent displayContent = getDefaultDisplayContentLocked();
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation: display");
- rotationChanged = displayContent.updateRotationUnchecked(
- false /* inTransaction */);
+ rotationChanged = displayContent.updateRotationUnchecked();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (!rotationChanged || forceRelayout) {
displayContent.setLayoutNeeded();
@@ -5326,8 +5333,7 @@ public class WindowManagerService extends IWindowManager.Stub
displayContent.setLayoutNeeded();
final int displayId = displayContent.getDisplayId();
- boolean configChanged = updateOrientationFromAppTokensLocked(false /* inTransaction */,
- displayId);
+ boolean configChanged = updateOrientationFromAppTokensLocked(displayId);
final Configuration currentDisplayConfig = displayContent.getConfiguration();
mTempConfiguration.setTo(currentDisplayConfig);
displayContent.computeScreenConfiguration(mTempConfiguration);
@@ -5335,7 +5341,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (configChanged) {
mWaitingForConfig = true;
- startFreezingDisplayLocked(false /* inTransaction */, 0 /* exitAnim */,
+ startFreezingDisplayLocked(0 /* exitAnim */,
0 /* enterAnim */, displayContent);
mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayId).sendToTarget();
}
@@ -5651,14 +5657,14 @@ public class WindowManagerService extends IWindowManager.Stub
return false;
}
- void startFreezingDisplayLocked(boolean inTransaction, int exitAnim, int enterAnim) {
- startFreezingDisplayLocked(inTransaction, exitAnim, enterAnim,
+ void startFreezingDisplayLocked(int exitAnim, int enterAnim) {
+ startFreezingDisplayLocked(exitAnim, enterAnim,
getDefaultDisplayContentLocked());
}
- void startFreezingDisplayLocked(boolean inTransaction, int exitAnim, int enterAnim,
+ void startFreezingDisplayLocked(int exitAnim, int enterAnim,
DisplayContent displayContent) {
- if (mDisplayFrozen) {
+ if (mDisplayFrozen || mRotatingSeamlessly) {
return;
}
@@ -5669,8 +5675,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (DEBUG_ORIENTATION) Slog.d(TAG_WM,
- "startFreezingDisplayLocked: inTransaction=" + inTransaction
- + " exitAnim=" + exitAnim + " enterAnim=" + enterAnim
+ "startFreezingDisplayLocked: exitAnim="
+ + exitAnim + " enterAnim=" + enterAnim
+ " called by " + Debug.getCallers(8));
mScreenFrozenLock.acquire();
@@ -5714,7 +5720,7 @@ public class WindowManagerService extends IWindowManager.Stub
displayContent.updateDisplayInfo();
screenRotationAnimation = new ScreenRotationAnimation(mContext, displayContent,
- inTransaction, mPolicy.isDefaultOrientationForced(), isSecure,
+ mPolicy.isDefaultOrientationForced(), isSecure,
this);
mAnimator.setScreenRotationAnimationLocked(mFrozenDisplayId,
screenRotationAnimation);
@@ -5777,9 +5783,10 @@ public class WindowManagerService extends IWindowManager.Stub
if (!mPolicy.validateRotationAnimationLw(mExitAnimId, mEnterAnimId, false)) {
mExitAnimId = mEnterAnimId = 0;
}
- if (screenRotationAnimation.dismiss(MAX_ANIMATION_DURATION,
+ if (screenRotationAnimation.dismiss(mTransaction, MAX_ANIMATION_DURATION,
getTransitionAnimationScaleLocked(), displayInfo.logicalWidth,
displayInfo.logicalHeight, mExitAnimId, mEnterAnimId)) {
+ mTransaction.apply();
scheduleAnimationLocked();
} else {
screenRotationAnimation.kill();
@@ -5802,7 +5809,7 @@ public class WindowManagerService extends IWindowManager.Stub
// to avoid inconsistent states. However, something interesting
// could have actually changed during that time so re-evaluate it
// now to catch that.
- configChanged = updateOrientationFromAppTokensLocked(false, displayId);
+ configChanged = updateOrientationFromAppTokensLocked(displayId);
// A little kludge: a lot could have happened while the
// display was frozen, so now that we are coming back we
@@ -5816,8 +5823,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (updateRotation) {
if (DEBUG_ORIENTATION) Slog.d(TAG_WM, "Performing post-rotate rotation");
- configChanged |= displayContent.updateRotationUnchecked(
- false /* inTransaction */);
+ configChanged |= displayContent.updateRotationUnchecked();
}
if (configChanged) {
@@ -7027,8 +7033,10 @@ public class WindowManagerService extends IWindowManager.Stub
if (DEBUG_ORIENTATION) {
Slog.i(TAG, "Performing post-rotate rotation after seamless rotation");
}
+ finishSeamlessRotation();
+
final DisplayContent displayContent = w.getDisplayContent();
- if (displayContent.updateRotationUnchecked(false /* inTransaction */)) {
+ if (displayContent.updateRotationUnchecked()) {
mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayContent.getDisplayId())
.sendToTarget();
}
@@ -7439,6 +7447,18 @@ public class WindowManagerService extends IWindowManager.Stub
.sendToTarget();
}
+ void startSeamlessRotation() {
+ // We are careful to reset this in case a window was removed before it finished
+ // seamless rotation.
+ mSeamlessRotationCount = 0;
+
+ mRotatingSeamlessly = true;
+ }
+
+ void finishSeamlessRotation() {
+ mRotatingSeamlessly = false;
+ }
+
/**
* Called when the state of lock task mode changes. This should be used to disable immersive
* mode confirmation.
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 68bb530fdf25..8866fe59b9f8 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2015,7 +2015,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
removeImmediately();
// Removing a visible window will effect the computed orientation
// So just update orientation if needed.
- if (wasVisible && mService.updateOrientationFromAppTokensLocked(false, displayId)) {
+ if (wasVisible && mService.updateOrientationFromAppTokensLocked(displayId)) {
mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayId).sendToTarget();
}
mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 13f05e088cb1..46a9961e1bc1 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1415,7 +1415,8 @@ class WindowStateAnimator {
}
}
- void seamlesslyRotateWindow(int oldRotation, int newRotation) {
+ void seamlesslyRotateWindow(SurfaceControl.Transaction t,
+ int oldRotation, int newRotation) {
final WindowState w = mWin;
if (!w.isVisibleNow() || w.mIsWallpaper) {
return;
@@ -1456,11 +1457,9 @@ class WindowStateAnimator {
float DsDy = mService.mTmpFloats[Matrix.MSCALE_Y];
float nx = mService.mTmpFloats[Matrix.MTRANS_X];
float ny = mService.mTmpFloats[Matrix.MTRANS_Y];
- mSurfaceController.setPositionInTransaction(nx, ny, false);
- mSurfaceController.setMatrixInTransaction(DsDx * w.mHScale,
- DtDx * w.mVScale,
- DtDy * w.mHScale,
- DsDy * w.mVScale, false);
+ mSurfaceController.setPosition(t, nx, ny, false);
+ mSurfaceController.setMatrix(t, DsDx * w.mHScale, DtDx * w.mVScale, DtDy
+ * w.mHScale, DsDy * w.mVScale, false);
}
/** The force-scaled state for a given window can persist past
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 9d6f8f78c272..f6c0a54c74ca 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -242,6 +242,11 @@ class WindowSurfaceController {
}
void setPositionInTransaction(float left, float top, boolean recoveringMemory) {
+ setPosition(null, left, top, recoveringMemory);
+ }
+
+ void setPosition(SurfaceControl.Transaction t, float left, float top,
+ boolean recoveringMemory) {
final boolean surfaceMoved = mSurfaceX != left || mSurfaceY != top;
if (surfaceMoved) {
mSurfaceX = left;
@@ -251,7 +256,11 @@ class WindowSurfaceController {
if (SHOW_TRANSACTIONS) logSurface(
"POS (setPositionInTransaction) @ (" + left + "," + top + ")", null);
- mSurfaceControl.setPosition(left, top);
+ if (t == null) {
+ mSurfaceControl.setPosition(left, top);
+ } else {
+ t.setPosition(mSurfaceControl, left, top);
+ }
} catch (RuntimeException e) {
Slog.w(TAG, "Error positioning surface of " + this
+ " pos=(" + left + "," + top + ")", e);
@@ -268,6 +277,11 @@ class WindowSurfaceController {
void setMatrixInTransaction(float dsdx, float dtdx, float dtdy, float dsdy,
boolean recoveringMemory) {
+ setMatrix(null, dsdx, dtdx, dtdy, dsdy, false);
+ }
+
+ void setMatrix(SurfaceControl.Transaction t, float dsdx, float dtdx,
+ float dtdy, float dsdy, boolean recoveringMemory) {
final boolean matrixChanged = mLastDsdx != dsdx || mLastDtdx != dtdx ||
mLastDtdy != dtdy || mLastDsdy != dsdy;
if (!matrixChanged) {
@@ -282,8 +296,11 @@ class WindowSurfaceController {
try {
if (SHOW_TRANSACTIONS) logSurface(
"MATRIX [" + dsdx + "," + dtdx + "," + dtdy + "," + dsdy + "]", null);
- mSurfaceControl.setMatrix(
- dsdx, dtdx, dtdy, dsdy);
+ if (t == null) {
+ mSurfaceControl.setMatrix(dsdx, dtdx, dtdy, dsdy);
+ } else {
+ t.setMatrix(mSurfaceControl, dsdx, dtdx, dtdy, dsdy);
+ }
} catch (RuntimeException e) {
// If something goes wrong with the surface (such
// as running out of memory), don't take down the
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java
index 86c83d6707b6..d37db20f05b7 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java
@@ -18,9 +18,14 @@ package com.android.server.backup.utils;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.os.Process;
import android.platform.test.annotations.Presubmit;
@@ -30,6 +35,7 @@ import android.support.test.runner.AndroidJUnit4;
import com.android.server.backup.BackupManagerService;
import com.android.server.backup.testutils.PackageManagerStub;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,7 +51,14 @@ public class AppBackupUtilsTest {
private static final Signature SIGNATURE_3 = generateSignature((byte) 3);
private static final Signature SIGNATURE_4 = generateSignature((byte) 4);
- private final PackageManagerStub mPackageManagerStub = new PackageManagerStub();
+ private PackageManagerStub mPackageManagerStub;
+ private PackageManagerInternal mMockPackageManagerInternal;
+
+ @Before
+ public void setUp() throws Exception {
+ mPackageManagerStub = new PackageManagerStub();
+ mMockPackageManagerInternal = mock(PackageManagerInternal.class);
+ }
@Test
public void appIsEligibleForBackup_backupNotAllowed_returnsFalse() throws Exception {
@@ -358,7 +371,8 @@ public class AppBackupUtilsTest {
@Test
public void signaturesMatch_targetIsNull_returnsFalse() throws Exception {
- boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, null);
+ boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, null,
+ mMockPackageManagerInternal);
assertThat(result).isFalse();
}
@@ -366,10 +380,12 @@ public class AppBackupUtilsTest {
@Test
public void signaturesMatch_systemApplication_returnsTrue() throws Exception {
PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
- boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo);
+ boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo,
+ mMockPackageManagerInternal);
assertThat(result).isTrue();
}
@@ -378,10 +394,12 @@ public class AppBackupUtilsTest {
public void signaturesMatch_disallowsUnsignedApps_storedSignatureNull_returnsFalse()
throws Exception {
PackageInfo packageInfo = new PackageInfo();
- packageInfo.signatures = new Signature[] {SIGNATURE_1};
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}};
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(null, packageInfo);
+ boolean result = AppBackupUtils.signaturesMatch(null, packageInfo,
+ mMockPackageManagerInternal);
assertThat(result).isFalse();
}
@@ -390,10 +408,12 @@ public class AppBackupUtilsTest {
public void signaturesMatch_disallowsUnsignedApps_storedSignatureEmpty_returnsFalse()
throws Exception {
PackageInfo packageInfo = new PackageInfo();
- packageInfo.signatures = new Signature[] {SIGNATURE_1};
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}};
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo);
+ boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo,
+ mMockPackageManagerInternal);
assertThat(result).isFalse();
}
@@ -404,11 +424,12 @@ public class AppBackupUtilsTest {
signaturesMatch_disallowsUnsignedApps_targetSignatureEmpty_returnsFalse()
throws Exception {
PackageInfo packageInfo = new PackageInfo();
- packageInfo.signatures = new Signature[0];
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[0][0];
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1},
- packageInfo);
+ boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, packageInfo,
+ mMockPackageManagerInternal);
assertThat(result).isFalse();
}
@@ -418,11 +439,12 @@ public class AppBackupUtilsTest {
signaturesMatch_disallowsUnsignedApps_targetSignatureNull_returnsFalse()
throws Exception {
PackageInfo packageInfo = new PackageInfo();
- packageInfo.signatures = null;
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = null;
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1},
- packageInfo);
+ boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, packageInfo,
+ mMockPackageManagerInternal);
assertThat(result).isFalse();
}
@@ -431,10 +453,11 @@ public class AppBackupUtilsTest {
public void signaturesMatch_disallowsUnsignedApps_bothSignaturesNull_returnsFalse()
throws Exception {
PackageInfo packageInfo = new PackageInfo();
- packageInfo.signatures = null;
+ packageInfo.signingCertificateHistory = null;
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(null, packageInfo);
+ boolean result = AppBackupUtils.signaturesMatch(null, packageInfo,
+ mMockPackageManagerInternal);
assertThat(result).isFalse();
}
@@ -443,10 +466,12 @@ public class AppBackupUtilsTest {
public void signaturesMatch_disallowsUnsignedApps_bothSignaturesEmpty_returnsFalse()
throws Exception {
PackageInfo packageInfo = new PackageInfo();
- packageInfo.signatures = new Signature[0];
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[0][0];
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo);
+ boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo,
+ mMockPackageManagerInternal);
assertThat(result).isFalse();
}
@@ -458,11 +483,15 @@ public class AppBackupUtilsTest {
Signature signature3Copy = new Signature(SIGNATURE_3.toByteArray());
PackageInfo packageInfo = new PackageInfo();
- packageInfo.signatures = new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3};
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {
+ {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}
+ };
packageInfo.applicationInfo = new ApplicationInfo();
boolean result = AppBackupUtils.signaturesMatch(
- new Signature[]{signature3Copy, signature1Copy, signature2Copy}, packageInfo);
+ new Signature[] {signature3Copy, signature1Copy, signature2Copy}, packageInfo,
+ mMockPackageManagerInternal);
assertThat(result).isTrue();
}
@@ -473,11 +502,15 @@ public class AppBackupUtilsTest {
Signature signature2Copy = new Signature(SIGNATURE_2.toByteArray());
PackageInfo packageInfo = new PackageInfo();
- packageInfo.signatures = new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3};
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {
+ {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}
+ };
packageInfo.applicationInfo = new ApplicationInfo();
boolean result = AppBackupUtils.signaturesMatch(
- new Signature[]{signature2Copy, signature1Copy}, packageInfo);
+ new Signature[]{signature2Copy, signature1Copy}, packageInfo,
+ mMockPackageManagerInternal);
assertThat(result).isTrue();
}
@@ -488,11 +521,15 @@ public class AppBackupUtilsTest {
Signature signature2Copy = new Signature(SIGNATURE_2.toByteArray());
PackageInfo packageInfo = new PackageInfo();
- packageInfo.signatures = new Signature[]{signature1Copy, signature2Copy};
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {
+ {signature1Copy, signature2Copy}
+ };
packageInfo.applicationInfo = new ApplicationInfo();
boolean result = AppBackupUtils.signaturesMatch(
- new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}, packageInfo);
+ new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}, packageInfo,
+ mMockPackageManagerInternal);
assertThat(result).isFalse();
}
@@ -503,11 +540,77 @@ public class AppBackupUtilsTest {
Signature signature2Copy = new Signature(SIGNATURE_2.toByteArray());
PackageInfo packageInfo = new PackageInfo();
- packageInfo.signatures = new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3};
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {
+ {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}
+ };
packageInfo.applicationInfo = new ApplicationInfo();
boolean result = AppBackupUtils.signaturesMatch(
- new Signature[]{signature1Copy, signature2Copy, SIGNATURE_4}, packageInfo);
+ new Signature[]{signature1Copy, signature2Copy, SIGNATURE_4}, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void signaturesMatch_singleStoredSignatureNoRotation_returnsTrue()
+ throws Exception {
+ Signature signature1Copy = new Signature(SIGNATURE_1.toByteArray());
+
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}};
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(signature1Copy,
+ packageInfo.packageName);
+
+ boolean result = AppBackupUtils.signaturesMatch(new Signature[] {signature1Copy},
+ packageInfo, mMockPackageManagerInternal);
+
+ assertThat(result).isTrue();
+ }
+
+ @Test
+ public void signaturesMatch_singleStoredSignatureWithRotationAssumeDataCapability_returnsTrue()
+ throws Exception {
+ Signature signature1Copy = new Signature(SIGNATURE_1.toByteArray());
+
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}, {SIGNATURE_2}};
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ // we know signature1Copy is in history, and we want to assume it has
+ // SigningDetails.CertCapabilities.INSTALLED_DATA capability
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(signature1Copy,
+ packageInfo.packageName);
+
+ boolean result = AppBackupUtils.signaturesMatch(new Signature[] {signature1Copy},
+ packageInfo, mMockPackageManagerInternal);
+
+ assertThat(result).isTrue();
+ }
+
+ @Test
+ public void
+ signaturesMatch_singleStoredSignatureWithRotationAssumeNoDataCapability_returnsFalse()
+ throws Exception {
+ Signature signature1Copy = new Signature(SIGNATURE_1.toByteArray());
+
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}, {SIGNATURE_2}};
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ // we know signature1Copy is in history, but we want to assume it does not have
+ // SigningDetails.CertCapabilities.INSTALLED_DATA capability
+ doReturn(false).when(mMockPackageManagerInternal).isDataRestoreSafe(signature1Copy,
+ packageInfo.packageName);
+
+ boolean result = AppBackupUtils.signaturesMatch(new Signature[] {signature1Copy},
+ packageInfo, mMockPackageManagerInternal);
assertThat(result).isFalse();
}
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
index 0cdf04bda2d0..5f052ceb2e26 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
@@ -28,6 +28,9 @@ import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSION_OF_BA
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -37,6 +40,7 @@ import android.app.backup.IBackupManagerMonitor;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.os.Bundle;
import android.os.Process;
@@ -79,6 +83,7 @@ public class TarBackupReaderTest {
@Mock private BytesReadListener mBytesReadListenerMock;
@Mock private IBackupManagerMonitor mBackupManagerMonitorMock;
+ @Mock private PackageManagerInternal mMockPackageManagerInternal;
private final PackageManagerStub mPackageManagerStub = new PackageManagerStub();
private Context mContext;
@@ -139,7 +144,8 @@ public class TarBackupReaderTest {
Signature[] signatures = tarBackupReader.readAppManifestAndReturnSignatures(
fileMetadata);
RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy(
- mPackageManagerStub, false /* allowApks */, fileMetadata, signatures);
+ mPackageManagerStub, false /* allowApks */, fileMetadata, signatures,
+ mMockPackageManagerInternal);
assertThat(restorePolicy).isEqualTo(RestorePolicy.IGNORE);
assertThat(fileMetadata.packageName).isEqualTo(TEST_PACKAGE_NAME);
@@ -152,7 +158,8 @@ public class TarBackupReaderTest {
signatures = tarBackupReader.readAppManifestAndReturnSignatures(
fileMetadata);
restorePolicy = tarBackupReader.chooseRestorePolicy(
- mPackageManagerStub, false /* allowApks */, fileMetadata, signatures);
+ mPackageManagerStub, false /* allowApks */, fileMetadata, signatures,
+ mMockPackageManagerInternal);
assertThat(restorePolicy).isEqualTo(RestorePolicy.IGNORE);
assertThat(fileMetadata.packageName).isEqualTo(TEST_PACKAGE_NAME);
@@ -214,7 +221,8 @@ public class TarBackupReaderTest {
mBytesReadListenerMock, mBackupManagerMonitorMock);
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- true /* allowApks */, new FileMetadata(), null /* signatures */);
+ true /* allowApks */, new FileMetadata(), null /* signatures */,
+ mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
verifyZeroInteractions(mBackupManagerMonitorMock);
@@ -234,7 +242,8 @@ public class TarBackupReaderTest {
PackageManagerStub.sPackageInfo = null;
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- true /* allowApks */, info, new Signature[0] /* signatures */);
+ true /* allowApks */, info, new Signature[0] /* signatures */,
+ mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.ACCEPT_IF_APK);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -258,7 +267,8 @@ public class TarBackupReaderTest {
PackageManagerStub.sPackageInfo = null;
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- true /* allowApks */, info, new Signature[0] /* signatures */);
+ true /* allowApks */, info, new Signature[0] /* signatures */,
+ mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.ACCEPT_IF_APK);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -283,7 +293,8 @@ public class TarBackupReaderTest {
PackageManagerStub.sPackageInfo = null;
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */);
+ false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */,
+ mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -307,7 +318,8 @@ public class TarBackupReaderTest {
PackageManagerStub.sPackageInfo = packageInfo;
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */);
+ false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */,
+ mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -333,7 +345,8 @@ public class TarBackupReaderTest {
PackageManagerStub.sPackageInfo = packageInfo;
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */);
+ false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */,
+ mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -358,11 +371,11 @@ public class TarBackupReaderTest {
packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID;
packageInfo.applicationInfo.backupAgentName = null;
- packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_2};
+ packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_2}};
PackageManagerStub.sPackageInfo = packageInfo;
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- false /* allowApks */, new FileMetadata(), signatures);
+ false /* allowApks */, new FileMetadata(), signatures, mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -383,16 +396,19 @@ public class TarBackupReaderTest {
Signature[] signatures = new Signature[]{FAKE_SIGNATURE_1};
PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.flags |=
ApplicationInfo.FLAG_ALLOW_BACKUP | ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
packageInfo.applicationInfo.uid = Process.SYSTEM_UID;
packageInfo.applicationInfo.backupAgentName = "backup.agent";
- packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1};
+ packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}};
PackageManagerStub.sPackageInfo = packageInfo;
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
+ packageInfo.packageName);
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- false /* allowApks */, new FileMetadata(), signatures);
+ false /* allowApks */, new FileMetadata(), signatures, mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.ACCEPT);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -412,16 +428,19 @@ public class TarBackupReaderTest {
Signature[] signatures = new Signature[]{FAKE_SIGNATURE_1};
PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.flags |=
ApplicationInfo.FLAG_ALLOW_BACKUP | ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID;
packageInfo.applicationInfo.backupAgentName = null;
- packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1};
+ packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}};
PackageManagerStub.sPackageInfo = packageInfo;
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
+ packageInfo.packageName);
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- false /* allowApks */, new FileMetadata(), signatures);
+ false /* allowApks */, new FileMetadata(), signatures, mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.ACCEPT);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -444,17 +463,20 @@ public class TarBackupReaderTest {
info.version = 1;
PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
packageInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID;
packageInfo.applicationInfo.backupAgentName = null;
- packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1};
+ packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}};
packageInfo.versionCode = 2;
PackageManagerStub.sPackageInfo = packageInfo;
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
+ packageInfo.packageName);
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- false /* allowApks */, info, signatures);
+ false /* allowApks */, info, signatures, mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.ACCEPT);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -479,17 +501,20 @@ public class TarBackupReaderTest {
info.hasApk = true;
PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
packageInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID;
packageInfo.applicationInfo.backupAgentName = null;
- packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1};
+ packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}};
packageInfo.versionCode = 1;
PackageManagerStub.sPackageInfo = packageInfo;
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
+ packageInfo.packageName);
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- true /* allowApks */, info, signatures);
+ true /* allowApks */, info, signatures, mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.ACCEPT_IF_APK);
verifyNoMoreInteractions(mBackupManagerMonitorMock);
@@ -510,17 +535,20 @@ public class TarBackupReaderTest {
info.version = 2;
PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
packageInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID;
packageInfo.applicationInfo.backupAgentName = null;
- packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1};
+ packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}};
packageInfo.versionCode = 1;
PackageManagerStub.sPackageInfo = packageInfo;
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
+ packageInfo.packageName);
RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
- false /* allowApks */, info, signatures);
+ false /* allowApks */, info, signatures, mMockPackageManagerInternal);
assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index 1211f00b1252..2f2afd71706c 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -44,6 +44,7 @@ import java.util.List;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.mock;
@SmallTest
public class DisplayManagerServiceTest extends AndroidTestCase {
@@ -123,7 +124,7 @@ public class DisplayManagerServiceTest extends AndroidTestCase {
"Test Virtual Display", width, height, dpi, null /* surface */, flags /* flags */,
uniqueId);
- displayManager.performTraversalInTransactionFromWindowManagerInternal();
+ displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
// flush the handler
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
@@ -161,7 +162,7 @@ public class DisplayManagerServiceTest extends AndroidTestCase {
"Test Virtual Display", width, height, dpi, null /* surface */, flags /* flags */,
uniqueId);
- displayManager.performTraversalInTransactionFromWindowManagerInternal();
+ displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
// flush the handler
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 51d27fe016f0..197475032ea8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -1015,7 +1015,8 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
| ApplicationInfo.FLAG_ALLOW_BACKUP;
pi.versionCode = version;
pi.applicationInfo.versionCode = version;
- pi.signatures = genSignatures(signatures);
+ pi.signatures = null;
+ pi.signingCertificateHistory = new Signature[][] {genSignatures(signatures)};
return pi;
}
@@ -1103,7 +1104,8 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
!mDisabledPackages.contains(PackageWithUser.of(userId, packageName));
if (getSignatures) {
- ret.signatures = pi.signatures;
+ ret.signatures = null;
+ ret.signingCertificateHistory = pi.signingCertificateHistory;
}
return ret;
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 845e05d28465..7815004c18f9 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -62,6 +62,7 @@ import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -3987,6 +3988,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
if (!nowBackupAllowed) {
pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP;
}
+
+ doReturn(expected != DISABLED_REASON_SIGNATURE_MISMATCH).when(
+ mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class), anyString());
+
assertEquals(expected, spi.canRestoreTo(mService, pi, anyVersionOk));
}
@@ -4959,6 +4964,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_3)));
assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_P0, LAUNCHER_1)));
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class),
+ anyString());
+
installPackage(USER_0, CALLING_PACKAGE_1);
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertWith(getCallerVisibleShortcuts())
@@ -5151,6 +5159,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
protected void checkBackupAndRestore_publisherNotRestored(
int package1DisabledReason) {
+ doReturn(package1DisabledReason != ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH).when(
+ mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class),
+ eq(CALLING_PACKAGE_1));
+
installPackage(USER_0, CALLING_PACKAGE_1);
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertEquals(0, mManager.getDynamicShortcuts().size());
@@ -5159,6 +5171,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
assertFalse(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, USER_0)
.getPackageInfo().isShadow());
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(
+ any(byte[].class), anyString());
installPackage(USER_0, CALLING_PACKAGE_2);
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
@@ -5276,7 +5290,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
addPackage(LAUNCHER_1, LAUNCHER_UID_1, 10, "sigx"); // different signature
- checkBackupAndRestore_launcherNotRestored();
+ checkBackupAndRestore_launcherNotRestored(true);
}
public void testBackupAndRestore_launcherNoLongerBackupTarget() {
@@ -5285,10 +5299,13 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
updatePackageInfo(LAUNCHER_1,
pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
- checkBackupAndRestore_launcherNotRestored();
+ checkBackupAndRestore_launcherNotRestored(false);
}
- protected void checkBackupAndRestore_launcherNotRestored() {
+ protected void checkBackupAndRestore_launcherNotRestored(boolean differentSignatures) {
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(
+ any(byte[].class), anyString());
+
installPackage(USER_0, CALLING_PACKAGE_1);
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertEquals(0, mManager.getDynamicShortcuts().size());
@@ -5307,6 +5324,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
"s1", "s2", "s3");
});
+ doReturn(!differentSignatures).when(mMockPackageManagerInternal).isDataRestoreSafe(
+ any(byte[].class), eq(LAUNCHER_1));
+
// Now we try to restore launcher 1. Then we realize it's not restorable, so L1 has no pinned
// shortcuts.
installPackage(USER_0, LAUNCHER_1);
@@ -5333,6 +5353,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
"s2");
});
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(
+ any(byte[].class), anyString());
+
installPackage(USER_0, LAUNCHER_2);
runWithCaller(LAUNCHER_2, USER_0, () -> {
assertShortcutIds(assertAllPinned(
@@ -5388,6 +5411,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
}
protected void checkBackupAndRestore_publisherAndLauncherNotRestored() {
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class),
+ anyString());
installPackage(USER_0, CALLING_PACKAGE_1);
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertEquals(0, mManager.getDynamicShortcuts().size());
@@ -5501,6 +5526,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_3)));
assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_P0, LAUNCHER_1)));
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class),
+ anyString());
+
installPackage(USER_0, CALLING_PACKAGE_1);
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertWith(getCallerVisibleShortcuts())
@@ -5586,6 +5614,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
.areAllDisabled();
});
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(
+ any(byte[].class), anyString());
backupAndRestore();
// When re-installing the app, the manifest shortcut should be re-published.
@@ -5695,6 +5725,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
.haveIds("s1", "ms1");
});
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class),
+ anyString());
// Backup and *without restarting the service, just call applyRestore()*.
{
int prevUid = mInjectedCallingUid;
@@ -5768,6 +5800,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
list("ms1", "ms2", "ms3", "ms4", "s1", "s2"), HANDLE_USER_0);
});
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(
+ any(byte[].class), anyString());
+
backupAndRestore();
// Lower the version and remove the manifest shortcuts.
@@ -5994,6 +6029,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "22222");
addPackage(LAUNCHER_1, LAUNCHER_UID_1, 10, "11111");
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(
+ any(byte[].class), anyString());
+
runWithSystemUid(() -> mService.applyRestore(payload, USER_0));
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java
index 29c98dcf5228..cd7feea08caa 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java
@@ -76,11 +76,13 @@ public class ShortcutManagerTest5 extends BaseShortcutManagerTest {
mMyPackage, mMyUserId, /*signature*/ false);
assertEquals(mMyPackage, pi.packageName);
assertNull(pi.signatures);
+ assertNull(pi.signingCertificateHistory);
pi = mShortcutService.getPackageInfo(
mMyPackage, mMyUserId, /*signature*/ true);
assertEquals(mMyPackage, pi.packageName);
- assertNotNull(pi.signatures);
+ assertNull(pi.signatures);
+ assertNotNull(pi.signingCertificateHistory);
pi = mShortcutService.getPackageInfo(
"no.such.package", mMyUserId, /*signature*/ true);
diff --git a/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java
index c016e6104755..1ac7cb86f867 100644
--- a/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java
@@ -15,73 +15,309 @@
*/
package com.android.server.pm.backup;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser.Package;
import android.content.pm.Signature;
-import android.test.AndroidTestCase;
import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.server.backup.BackupUtils;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.ArrayList;
import java.util.Arrays;
@SmallTest
-public class BackupUtilsTest extends AndroidTestCase {
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class BackupUtilsTest {
+
+ private static final Signature SIGNATURE_1 = generateSignature((byte) 1);
+ private static final Signature SIGNATURE_2 = generateSignature((byte) 2);
+ private static final Signature SIGNATURE_3 = generateSignature((byte) 3);
+ private static final Signature SIGNATURE_4 = generateSignature((byte) 4);
+ private static final byte[] SIGNATURE_HASH_1 = BackupUtils.hashSignature(SIGNATURE_1);
+ private static final byte[] SIGNATURE_HASH_2 = BackupUtils.hashSignature(SIGNATURE_2);
+ private static final byte[] SIGNATURE_HASH_3 = BackupUtils.hashSignature(SIGNATURE_3);
+ private static final byte[] SIGNATURE_HASH_4 = BackupUtils.hashSignature(SIGNATURE_4);
- private Signature[] genSignatures(String... signatures) {
- final Signature[] sigs = new Signature[signatures.length];
- for (int i = 0; i < signatures.length; i++){
- sigs[i] = new Signature(signatures[i].getBytes());
- }
- return sigs;
+ private PackageManagerInternal mMockPackageManagerInternal;
+
+ @Before
+ public void setUp() throws Exception {
+ mMockPackageManagerInternal = mock(PackageManagerInternal.class);
}
- private PackageInfo genPackage(String... signatures) {
- final PackageInfo pi = new PackageInfo();
- pi.packageName = "package";
- pi.applicationInfo = new ApplicationInfo();
- pi.signatures = genSignatures(signatures);
+ @Test
+ public void signaturesMatch_targetIsNull_returnsFalse() throws Exception {
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, null,
+ mMockPackageManagerInternal);
- return pi;
+ assertThat(result).isFalse();
}
- public void testSignaturesMatch() {
- final ArrayList<byte[]> stored1 = BackupUtils.hashSignatureArray(Arrays.asList(
- "abc".getBytes()));
- final ArrayList<byte[]> stored2 = BackupUtils.hashSignatureArray(Arrays.asList(
- "abc".getBytes(), "def".getBytes()));
+ @Test
+ public void signaturesMatch_systemApplication_returnsTrue() throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.applicationInfo = new ApplicationInfo();
+ packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isTrue();
+ }
+
+ @Test
+ public void signaturesMatch_disallowsUnsignedApps_storedSignatureNull_returnsFalse()
+ throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}};
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ boolean result = BackupUtils.signaturesMatch(null, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void signaturesMatch_disallowsUnsignedApps_storedSignatureEmpty_returnsFalse()
+ throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}};
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isFalse();
+ }
+
+
+ @Test
+ public void
+ signaturesMatch_disallowsUnsignedApps_targetSignatureEmpty_returnsFalse()
+ throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[0][0];
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void
+ signaturesMatch_disallowsUnsignedApps_targetSignatureNull_returnsFalse()
+ throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = null;
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void signaturesMatch_disallowsUnsignedApps_bothSignaturesNull_returnsFalse()
+ throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = null;
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ boolean result = BackupUtils.signaturesMatch(null, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void signaturesMatch_disallowsUnsignedApps_bothSignaturesEmpty_returnsFalse()
+ throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[0][0];
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void signaturesMatch_equalSignatures_returnsTrue() throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {
+ {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}
+ };
+ packageInfo.applicationInfo = new ApplicationInfo();
- PackageInfo pi;
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ storedSigHashes.add(SIGNATURE_HASH_2);
+ storedSigHashes.add(SIGNATURE_HASH_3);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
- // False for null package.
- assertFalse(BackupUtils.signaturesMatch(stored1, null));
+ assertThat(result).isTrue();
+ }
- // If it's a system app, signatures don't matter.
- pi = genPackage("xyz");
- pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
- assertTrue(BackupUtils.signaturesMatch(stored1, pi));
+ @Test
+ public void signaturesMatch_extraSignatureInTarget_returnsTrue() throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {
+ {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}
+ };
+ packageInfo.applicationInfo = new ApplicationInfo();
- // Non system apps.
- assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("abc")));
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ storedSigHashes.add(SIGNATURE_HASH_2);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
- // Superset is okay.
- assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("abc", "xyz")));
- assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("xyz", "abc")));
+ assertThat(result).isTrue();
+ }
- assertFalse(BackupUtils.signaturesMatch(stored1, genPackage("xyz")));
- assertFalse(BackupUtils.signaturesMatch(stored1, genPackage("xyz", "def")));
+ @Test
+ public void signaturesMatch_extraSignatureInStored_returnsFalse() throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1, SIGNATURE_2}};
+ packageInfo.applicationInfo = new ApplicationInfo();
- assertTrue(BackupUtils.signaturesMatch(stored2, genPackage("def", "abc")));
- assertTrue(BackupUtils.signaturesMatch(stored2, genPackage("x", "def", "abc", "y")));
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ storedSigHashes.add(SIGNATURE_HASH_2);
+ storedSigHashes.add(SIGNATURE_HASH_3);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
- // Subset is not okay.
- assertFalse(BackupUtils.signaturesMatch(stored2, genPackage("abc")));
- assertFalse(BackupUtils.signaturesMatch(stored2, genPackage("def")));
+ assertThat(result).isFalse();
}
+ @Test
+ public void signaturesMatch_oneNonMatchingSignature_returnsFalse() throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {
+ {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}
+ };
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ storedSigHashes.add(SIGNATURE_HASH_2);
+ storedSigHashes.add(SIGNATURE_HASH_4);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ public void signaturesMatch_singleStoredSignatureNoRotation_returnsTrue()
+ throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}};
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1,
+ packageInfo.packageName);
+
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isTrue();
+ }
+
+ @Test
+ public void signaturesMatch_singleStoredSignatureWithRotationAssumeDataCapability_returnsTrue()
+ throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}, {SIGNATURE_2}};
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ // we know SIGNATURE_1 is in history, and we want to assume it has
+ // SigningDetails.CertCapabilities.INSTALLED_DATA capability
+ doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1,
+ packageInfo.packageName);
+
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isTrue();
+ }
+
+ @Test
+ public void
+ signaturesMatch_singleStoredSignatureWithRotationAssumeNoDataCapability_returnsFalse()
+ throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test";
+ packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}, {SIGNATURE_2}};
+ packageInfo.applicationInfo = new ApplicationInfo();
+
+ // we know SIGNATURE_1 is in history, but we want to assume it does not have
+ // SigningDetails.CertCapabilities.INSTALLED_DATA capability
+ doReturn(false).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1,
+ packageInfo.packageName);
+
+ ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+ storedSigHashes.add(SIGNATURE_HASH_1);
+ boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+ mMockPackageManagerInternal);
+
+ assertThat(result).isFalse();
+ }
+
+ @Test
public void testHashSignature() {
final byte[] sig1 = "abc".getBytes();
final byte[] sig2 = "def".getBytes();
@@ -115,4 +351,10 @@ public class BackupUtilsTest extends AndroidTestCase {
MoreAsserts.assertEquals(hash2a, listA.get(1));
MoreAsserts.assertEquals(hash2a, listB.get(1));
}
+
+ private static Signature generateSignature(byte i) {
+ byte[] signatureBytes = new byte[256];
+ signatureBytes[0] = i;
+ return new Signature(signatureBytes);
+ }
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 7add893e3ff4..4a0027b7fd77 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -5183,7 +5183,7 @@ public class TelephonyManager {
ITelephony telephony = getITelephony();
if (telephony == null)
return null;
- return telephony.getForbiddenPlmns(subId, appType);
+ return telephony.getForbiddenPlmns(subId, appType, mContext.getOpPackageName());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index afbb94776641..7c7700bb9a7d 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1444,13 +1444,12 @@ interface ITelephony {
* Returns a list of Forbidden PLMNs from the specified SIM App
* Returns null if the query fails.
*
- *
- * <p>Requires that the calling app has READ_PRIVILEGED_PHONE_STATE
+ * <p>Requires that the calling app has READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE
*
* @param subId subscription ID used for authentication
* @param appType the icc application type, like {@link #APPTYPE_USIM}
*/
- String[] getForbiddenPlmns(int subId, int appType);
+ String[] getForbiddenPlmns(int subId, int appType, String callingPackage);
/**
* Check if phone is in emergency callback mode
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index a3a30807986e..ee7084ad86c0 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -25,6 +25,7 @@ package com.android.internal.telephony;
*/
import android.os.SystemProperties;
+import android.telephony.TelephonyManager;
/**
* {@hide}
@@ -162,8 +163,8 @@ public interface RILConstants {
int NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA = 20; /* TD-SCDMA, GSM/WCDMA and LTE */
int NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 21; /*TD-SCDMA,EvDo,CDMA,GSM/WCDMA*/
int NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 22; /* TD-SCDMA/LTE/GSM/WCDMA, CDMA, and EvDo */
- int PREFERRED_NETWORK_MODE = SystemProperties.getInt("ro.telephony.default_network",
- NETWORK_MODE_WCDMA_PREF);
+ int PREFERRED_NETWORK_MODE = Integer.parseInt(TelephonyManager.getTelephonyProperty(0,
+ "ro.telephony.default_network", Integer.toString(NETWORK_MODE_WCDMA_PREF)));
int BAND_MODE_UNSPECIFIED = 0; //"unspecified" (selected by baseband automatically)
int BAND_MODE_EURO = 1; //"EURO band" (GSM-900 / DCS-1800 / WCDMA-IMT-2000)
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 93fa5987aa9c..6865f77fa717 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -86,9 +86,6 @@ public class WifiConfiguration implements Parcelable {
/** WPA is not used; plaintext or static WEP could be used. */
public static final int NONE = 0;
/** WPA pre-shared key (requires {@code preSharedKey} to be specified). */
- /** @deprecated Due to security and performance limitations, use of WPA-1 networks
- * is discouraged. WPA-2 (RSN) should be used instead. */
- @Deprecated
public static final int WPA_PSK = 1;
/** WPA using EAP authentication. Generally used with an external authentication server. */
public static final int WPA_EAP = 2;
@@ -122,7 +119,7 @@ public class WifiConfiguration implements Parcelable {
public static final String varName = "key_mgmt";
- public static final String[] strings = { "NONE", /* deprecated */ "WPA_PSK", "WPA_EAP",
+ public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP",
"IEEE8021X", "WPA2_PSK", "OSEN", "FT_PSK", "FT_EAP" };
}
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
index eca840644fc6..ebf60076bd02 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
@@ -133,7 +133,8 @@ public class DiscoverySessionCallback {
* match filter. For {@link PublishConfig#PUBLISH_TYPE_SOLICITED},
* {@link SubscribeConfig#SUBSCRIBE_TYPE_ACTIVE} discovery sessions this
* is the subscriber's match filter.
- * @param distanceMm The measured distance to the Publisher in mm.
+ * @param distanceMm The measured distance to the Publisher in mm. Note: the measured distance
+ * may be negative for very close devices.
*/
public void onServiceDiscoveredWithinRange(PeerHandle peerHandle,
byte[] serviceSpecificInfo, List<byte[]> matchFilter, int distanceMm) {
diff --git a/wifi/java/android/net/wifi/rtt/RangingResult.java b/wifi/java/android/net/wifi/rtt/RangingResult.java
index 4705e1d4913f..7fe85be80964 100644
--- a/wifi/java/android/net/wifi/rtt/RangingResult.java
+++ b/wifi/java/android/net/wifi/rtt/RangingResult.java
@@ -147,6 +147,8 @@ public final class RangingResult implements Parcelable {
* @return The distance (in mm) to the device specified by {@link #getMacAddress()} or
* {@link #getPeerHandle()}.
* <p>
+ * Note: the measured distance may be negative for very close devices.
+ * <p>
* Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an
* exception.
*/