diff options
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. */ |