Merge "Fixed some activity visiblility issues in picture-in-picutre mode"
diff --git a/Android.mk b/Android.mk
index c1c74ea..b95ab2e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -345,6 +345,7 @@
media/java/android/media/IMediaRouterService.aidl \
media/java/android/media/IMediaScannerListener.aidl \
media/java/android/media/IMediaScannerService.aidl \
+ media/java/android/media/IRecordingConfigDispatcher.aidl \
media/java/android/media/IRemoteDisplayCallback.aidl \
media/java/android/media/IRemoteDisplayProvider.aidl \
media/java/android/media/IRemoteVolumeController.aidl \
diff --git a/api/current.txt b/api/current.txt
index 47d3207..629d832 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20371,8 +20371,6 @@
field public static final java.lang.String MIMETYPE_TEXT_CEA_608 = "text/cea-608";
field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt";
field public static final java.lang.String MIMETYPE_VIDEO_AVC = "video/avc";
- field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_AVC = "video/dolby-avc";
- field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_HEVC = "video/dolby-hevc";
field public static final java.lang.String MIMETYPE_VIDEO_H263 = "video/3gpp";
field public static final java.lang.String MIMETYPE_VIDEO_HEVC = "video/hevc";
field public static final java.lang.String MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
@@ -49554,6 +49552,8 @@
public class InternalError extends java.lang.VirtualMachineError {
ctor public InternalError();
ctor public InternalError(java.lang.String);
+ ctor public InternalError(java.lang.String, java.lang.Throwable);
+ ctor public InternalError(java.lang.Throwable);
}
public class InterruptedException extends java.lang.Exception {
@@ -50326,6 +50326,8 @@
public abstract class VirtualMachineError extends java.lang.Error {
ctor public VirtualMachineError();
ctor public VirtualMachineError(java.lang.String);
+ ctor public VirtualMachineError(java.lang.String, java.lang.Throwable);
+ ctor public VirtualMachineError(java.lang.Throwable);
}
public final class Void {
@@ -54068,6 +54070,7 @@
method public static java.security.cert.CertPathBuilder getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
method public static java.security.cert.CertPathBuilder getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
method public final java.security.Provider getProvider();
+ method public final java.security.cert.CertPathChecker getRevocationChecker();
}
public class CertPathBuilderException extends java.security.GeneralSecurityException {
@@ -54085,6 +54088,13 @@
public abstract class CertPathBuilderSpi {
ctor public CertPathBuilderSpi();
method public abstract java.security.cert.CertPathBuilderResult engineBuild(java.security.cert.CertPathParameters) throws java.security.cert.CertPathBuilderException, java.security.InvalidAlgorithmParameterException;
+ method public java.security.cert.CertPathChecker engineGetRevocationChecker();
+ }
+
+ public abstract interface CertPathChecker {
+ method public abstract void check(java.security.cert.Certificate) throws java.security.cert.CertPathValidatorException;
+ method public abstract void init(boolean) throws java.security.cert.CertPathValidatorException;
+ method public abstract boolean isForwardCheckingSupported();
}
public abstract interface CertPathParameters implements java.lang.Cloneable {
@@ -54099,6 +54109,7 @@
method public static java.security.cert.CertPathValidator getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
method public static java.security.cert.CertPathValidator getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
method public final java.security.Provider getProvider();
+ method public final java.security.cert.CertPathChecker getRevocationChecker();
method public final java.security.cert.CertPathValidatorResult validate(java.security.cert.CertPath, java.security.cert.CertPathParameters) throws java.security.cert.CertPathValidatorException, java.security.InvalidAlgorithmParameterException;
}
@@ -54135,6 +54146,7 @@
public abstract class CertPathValidatorSpi {
ctor public CertPathValidatorSpi();
+ method public java.security.cert.CertPathChecker engineGetRevocationChecker();
method public abstract java.security.cert.CertPathValidatorResult engineValidate(java.security.cert.CertPath, java.security.cert.CertPathParameters) throws java.security.cert.CertPathValidatorException, java.security.InvalidAlgorithmParameterException;
}
@@ -54293,9 +54305,10 @@
method public java.security.cert.CertPath getCertPath();
}
- public abstract class PKIXCertPathChecker implements java.lang.Cloneable {
+ public abstract class PKIXCertPathChecker implements java.security.cert.CertPathChecker java.lang.Cloneable {
ctor protected PKIXCertPathChecker();
method public abstract void check(java.security.cert.Certificate, java.util.Collection<java.lang.String>) throws java.security.cert.CertPathValidatorException;
+ method public void check(java.security.cert.Certificate) throws java.security.cert.CertPathValidatorException;
method public java.lang.Object clone();
method public abstract java.util.Set<java.lang.String> getSupportedExtensions();
method public abstract void init(boolean) throws java.security.cert.CertPathValidatorException;
@@ -54355,6 +54368,30 @@
enum_constant public static final java.security.cert.PKIXReason UNRECOGNIZED_CRIT_EXT;
}
+ public abstract class PKIXRevocationChecker extends java.security.cert.PKIXCertPathChecker {
+ ctor protected PKIXRevocationChecker();
+ method public java.util.List<java.security.cert.Extension> getOcspExtensions();
+ method public java.net.URI getOcspResponder();
+ method public java.security.cert.X509Certificate getOcspResponderCert();
+ method public java.util.Map<java.security.cert.X509Certificate, byte[]> getOcspResponses();
+ method public java.util.Set<java.security.cert.PKIXRevocationChecker.Option> getOptions();
+ method public abstract java.util.List<java.security.cert.CertPathValidatorException> getSoftFailExceptions();
+ method public void setOcspExtensions(java.util.List<java.security.cert.Extension>);
+ method public void setOcspResponder(java.net.URI);
+ method public void setOcspResponderCert(java.security.cert.X509Certificate);
+ method public void setOcspResponses(java.util.Map<java.security.cert.X509Certificate, byte[]>);
+ method public void setOptions(java.util.Set<java.security.cert.PKIXRevocationChecker.Option>);
+ }
+
+ public static final class PKIXRevocationChecker.Option extends java.lang.Enum {
+ method public static java.security.cert.PKIXRevocationChecker.Option valueOf(java.lang.String);
+ method public static final java.security.cert.PKIXRevocationChecker.Option[] values();
+ enum_constant public static final java.security.cert.PKIXRevocationChecker.Option NO_FALLBACK;
+ enum_constant public static final java.security.cert.PKIXRevocationChecker.Option ONLY_END_ENTITY;
+ enum_constant public static final java.security.cert.PKIXRevocationChecker.Option PREFER_CRLS;
+ enum_constant public static final java.security.cert.PKIXRevocationChecker.Option SOFT_FAIL;
+ }
+
public abstract interface PolicyNode {
method public abstract java.util.Iterator<? extends java.security.cert.PolicyNode> getChildren();
method public abstract int getDepth();
@@ -54514,6 +54551,7 @@
method public javax.security.auth.x500.X500Principal getSubjectX500Principal();
method public abstract byte[] getTBSCertificate() throws java.security.cert.CertificateEncodingException;
method public abstract int getVersion();
+ method public void verify(java.security.PublicKey, java.security.Provider) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.SignatureException;
}
public abstract interface X509Extension {
diff --git a/api/system-current.txt b/api/system-current.txt
index bf8e0e7..6a36ce0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -21670,8 +21670,6 @@
field public static final java.lang.String MIMETYPE_TEXT_CEA_608 = "text/cea-608";
field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt";
field public static final java.lang.String MIMETYPE_VIDEO_AVC = "video/avc";
- field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_AVC = "video/dolby-avc";
- field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_HEVC = "video/dolby-hevc";
field public static final java.lang.String MIMETYPE_VIDEO_H263 = "video/3gpp";
field public static final java.lang.String MIMETYPE_VIDEO_HEVC = "video/hevc";
field public static final java.lang.String MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
@@ -52221,6 +52219,8 @@
public class InternalError extends java.lang.VirtualMachineError {
ctor public InternalError();
ctor public InternalError(java.lang.String);
+ ctor public InternalError(java.lang.String, java.lang.Throwable);
+ ctor public InternalError(java.lang.Throwable);
}
public class InterruptedException extends java.lang.Exception {
@@ -52993,6 +52993,8 @@
public abstract class VirtualMachineError extends java.lang.Error {
ctor public VirtualMachineError();
ctor public VirtualMachineError(java.lang.String);
+ ctor public VirtualMachineError(java.lang.String, java.lang.Throwable);
+ ctor public VirtualMachineError(java.lang.Throwable);
}
public final class Void {
@@ -56735,6 +56737,7 @@
method public static java.security.cert.CertPathBuilder getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
method public static java.security.cert.CertPathBuilder getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
method public final java.security.Provider getProvider();
+ method public final java.security.cert.CertPathChecker getRevocationChecker();
}
public class CertPathBuilderException extends java.security.GeneralSecurityException {
@@ -56752,6 +56755,13 @@
public abstract class CertPathBuilderSpi {
ctor public CertPathBuilderSpi();
method public abstract java.security.cert.CertPathBuilderResult engineBuild(java.security.cert.CertPathParameters) throws java.security.cert.CertPathBuilderException, java.security.InvalidAlgorithmParameterException;
+ method public java.security.cert.CertPathChecker engineGetRevocationChecker();
+ }
+
+ public abstract interface CertPathChecker {
+ method public abstract void check(java.security.cert.Certificate) throws java.security.cert.CertPathValidatorException;
+ method public abstract void init(boolean) throws java.security.cert.CertPathValidatorException;
+ method public abstract boolean isForwardCheckingSupported();
}
public abstract interface CertPathParameters implements java.lang.Cloneable {
@@ -56766,6 +56776,7 @@
method public static java.security.cert.CertPathValidator getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
method public static java.security.cert.CertPathValidator getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
method public final java.security.Provider getProvider();
+ method public final java.security.cert.CertPathChecker getRevocationChecker();
method public final java.security.cert.CertPathValidatorResult validate(java.security.cert.CertPath, java.security.cert.CertPathParameters) throws java.security.cert.CertPathValidatorException, java.security.InvalidAlgorithmParameterException;
}
@@ -56802,6 +56813,7 @@
public abstract class CertPathValidatorSpi {
ctor public CertPathValidatorSpi();
+ method public java.security.cert.CertPathChecker engineGetRevocationChecker();
method public abstract java.security.cert.CertPathValidatorResult engineValidate(java.security.cert.CertPath, java.security.cert.CertPathParameters) throws java.security.cert.CertPathValidatorException, java.security.InvalidAlgorithmParameterException;
}
@@ -56960,9 +56972,10 @@
method public java.security.cert.CertPath getCertPath();
}
- public abstract class PKIXCertPathChecker implements java.lang.Cloneable {
+ public abstract class PKIXCertPathChecker implements java.security.cert.CertPathChecker java.lang.Cloneable {
ctor protected PKIXCertPathChecker();
method public abstract void check(java.security.cert.Certificate, java.util.Collection<java.lang.String>) throws java.security.cert.CertPathValidatorException;
+ method public void check(java.security.cert.Certificate) throws java.security.cert.CertPathValidatorException;
method public java.lang.Object clone();
method public abstract java.util.Set<java.lang.String> getSupportedExtensions();
method public abstract void init(boolean) throws java.security.cert.CertPathValidatorException;
@@ -57022,6 +57035,30 @@
enum_constant public static final java.security.cert.PKIXReason UNRECOGNIZED_CRIT_EXT;
}
+ public abstract class PKIXRevocationChecker extends java.security.cert.PKIXCertPathChecker {
+ ctor protected PKIXRevocationChecker();
+ method public java.util.List<java.security.cert.Extension> getOcspExtensions();
+ method public java.net.URI getOcspResponder();
+ method public java.security.cert.X509Certificate getOcspResponderCert();
+ method public java.util.Map<java.security.cert.X509Certificate, byte[]> getOcspResponses();
+ method public java.util.Set<java.security.cert.PKIXRevocationChecker.Option> getOptions();
+ method public abstract java.util.List<java.security.cert.CertPathValidatorException> getSoftFailExceptions();
+ method public void setOcspExtensions(java.util.List<java.security.cert.Extension>);
+ method public void setOcspResponder(java.net.URI);
+ method public void setOcspResponderCert(java.security.cert.X509Certificate);
+ method public void setOcspResponses(java.util.Map<java.security.cert.X509Certificate, byte[]>);
+ method public void setOptions(java.util.Set<java.security.cert.PKIXRevocationChecker.Option>);
+ }
+
+ public static final class PKIXRevocationChecker.Option extends java.lang.Enum {
+ method public static java.security.cert.PKIXRevocationChecker.Option valueOf(java.lang.String);
+ method public static final java.security.cert.PKIXRevocationChecker.Option[] values();
+ enum_constant public static final java.security.cert.PKIXRevocationChecker.Option NO_FALLBACK;
+ enum_constant public static final java.security.cert.PKIXRevocationChecker.Option ONLY_END_ENTITY;
+ enum_constant public static final java.security.cert.PKIXRevocationChecker.Option PREFER_CRLS;
+ enum_constant public static final java.security.cert.PKIXRevocationChecker.Option SOFT_FAIL;
+ }
+
public abstract interface PolicyNode {
method public abstract java.util.Iterator<? extends java.security.cert.PolicyNode> getChildren();
method public abstract int getDepth();
@@ -57181,6 +57218,7 @@
method public javax.security.auth.x500.X500Principal getSubjectX500Principal();
method public abstract byte[] getTBSCertificate() throws java.security.cert.CertificateEncodingException;
method public abstract int getVersion();
+ method public void verify(java.security.PublicKey, java.security.Provider) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.SignatureException;
}
public abstract interface X509Extension {
diff --git a/api/test-current.txt b/api/test-current.txt
index 6eba6bd..21b101f 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -20379,8 +20379,6 @@
field public static final java.lang.String MIMETYPE_TEXT_CEA_608 = "text/cea-608";
field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt";
field public static final java.lang.String MIMETYPE_VIDEO_AVC = "video/avc";
- field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_AVC = "video/dolby-avc";
- field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_HEVC = "video/dolby-hevc";
field public static final java.lang.String MIMETYPE_VIDEO_H263 = "video/3gpp";
field public static final java.lang.String MIMETYPE_VIDEO_HEVC = "video/hevc";
field public static final java.lang.String MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
@@ -49570,6 +49568,8 @@
public class InternalError extends java.lang.VirtualMachineError {
ctor public InternalError();
ctor public InternalError(java.lang.String);
+ ctor public InternalError(java.lang.String, java.lang.Throwable);
+ ctor public InternalError(java.lang.Throwable);
}
public class InterruptedException extends java.lang.Exception {
@@ -50342,6 +50342,8 @@
public abstract class VirtualMachineError extends java.lang.Error {
ctor public VirtualMachineError();
ctor public VirtualMachineError(java.lang.String);
+ ctor public VirtualMachineError(java.lang.String, java.lang.Throwable);
+ ctor public VirtualMachineError(java.lang.Throwable);
}
public final class Void {
@@ -54084,6 +54086,7 @@
method public static java.security.cert.CertPathBuilder getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
method public static java.security.cert.CertPathBuilder getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
method public final java.security.Provider getProvider();
+ method public final java.security.cert.CertPathChecker getRevocationChecker();
}
public class CertPathBuilderException extends java.security.GeneralSecurityException {
@@ -54101,6 +54104,13 @@
public abstract class CertPathBuilderSpi {
ctor public CertPathBuilderSpi();
method public abstract java.security.cert.CertPathBuilderResult engineBuild(java.security.cert.CertPathParameters) throws java.security.cert.CertPathBuilderException, java.security.InvalidAlgorithmParameterException;
+ method public java.security.cert.CertPathChecker engineGetRevocationChecker();
+ }
+
+ public abstract interface CertPathChecker {
+ method public abstract void check(java.security.cert.Certificate) throws java.security.cert.CertPathValidatorException;
+ method public abstract void init(boolean) throws java.security.cert.CertPathValidatorException;
+ method public abstract boolean isForwardCheckingSupported();
}
public abstract interface CertPathParameters implements java.lang.Cloneable {
@@ -54115,6 +54125,7 @@
method public static java.security.cert.CertPathValidator getInstance(java.lang.String, java.lang.String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
method public static java.security.cert.CertPathValidator getInstance(java.lang.String, java.security.Provider) throws java.security.NoSuchAlgorithmException;
method public final java.security.Provider getProvider();
+ method public final java.security.cert.CertPathChecker getRevocationChecker();
method public final java.security.cert.CertPathValidatorResult validate(java.security.cert.CertPath, java.security.cert.CertPathParameters) throws java.security.cert.CertPathValidatorException, java.security.InvalidAlgorithmParameterException;
}
@@ -54151,6 +54162,7 @@
public abstract class CertPathValidatorSpi {
ctor public CertPathValidatorSpi();
+ method public java.security.cert.CertPathChecker engineGetRevocationChecker();
method public abstract java.security.cert.CertPathValidatorResult engineValidate(java.security.cert.CertPath, java.security.cert.CertPathParameters) throws java.security.cert.CertPathValidatorException, java.security.InvalidAlgorithmParameterException;
}
@@ -54309,9 +54321,10 @@
method public java.security.cert.CertPath getCertPath();
}
- public abstract class PKIXCertPathChecker implements java.lang.Cloneable {
+ public abstract class PKIXCertPathChecker implements java.security.cert.CertPathChecker java.lang.Cloneable {
ctor protected PKIXCertPathChecker();
method public abstract void check(java.security.cert.Certificate, java.util.Collection<java.lang.String>) throws java.security.cert.CertPathValidatorException;
+ method public void check(java.security.cert.Certificate) throws java.security.cert.CertPathValidatorException;
method public java.lang.Object clone();
method public abstract java.util.Set<java.lang.String> getSupportedExtensions();
method public abstract void init(boolean) throws java.security.cert.CertPathValidatorException;
@@ -54371,6 +54384,30 @@
enum_constant public static final java.security.cert.PKIXReason UNRECOGNIZED_CRIT_EXT;
}
+ public abstract class PKIXRevocationChecker extends java.security.cert.PKIXCertPathChecker {
+ ctor protected PKIXRevocationChecker();
+ method public java.util.List<java.security.cert.Extension> getOcspExtensions();
+ method public java.net.URI getOcspResponder();
+ method public java.security.cert.X509Certificate getOcspResponderCert();
+ method public java.util.Map<java.security.cert.X509Certificate, byte[]> getOcspResponses();
+ method public java.util.Set<java.security.cert.PKIXRevocationChecker.Option> getOptions();
+ method public abstract java.util.List<java.security.cert.CertPathValidatorException> getSoftFailExceptions();
+ method public void setOcspExtensions(java.util.List<java.security.cert.Extension>);
+ method public void setOcspResponder(java.net.URI);
+ method public void setOcspResponderCert(java.security.cert.X509Certificate);
+ method public void setOcspResponses(java.util.Map<java.security.cert.X509Certificate, byte[]>);
+ method public void setOptions(java.util.Set<java.security.cert.PKIXRevocationChecker.Option>);
+ }
+
+ public static final class PKIXRevocationChecker.Option extends java.lang.Enum {
+ method public static java.security.cert.PKIXRevocationChecker.Option valueOf(java.lang.String);
+ method public static final java.security.cert.PKIXRevocationChecker.Option[] values();
+ enum_constant public static final java.security.cert.PKIXRevocationChecker.Option NO_FALLBACK;
+ enum_constant public static final java.security.cert.PKIXRevocationChecker.Option ONLY_END_ENTITY;
+ enum_constant public static final java.security.cert.PKIXRevocationChecker.Option PREFER_CRLS;
+ enum_constant public static final java.security.cert.PKIXRevocationChecker.Option SOFT_FAIL;
+ }
+
public abstract interface PolicyNode {
method public abstract java.util.Iterator<? extends java.security.cert.PolicyNode> getChildren();
method public abstract int getDepth();
@@ -54530,6 +54567,7 @@
method public javax.security.auth.x500.X500Principal getSubjectX500Principal();
method public abstract byte[] getTBSCertificate() throws java.security.cert.CertificateEncodingException;
method public abstract int getVersion();
+ method public void verify(java.security.PublicKey, java.security.Provider) throws java.security.cert.CertificateException, java.security.InvalidKeyException, java.security.NoSuchAlgorithmException, java.security.SignatureException;
}
public abstract interface X509Extension {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 81e00ff..4e55c89 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2015,7 +2015,7 @@
private static final String ONE_COUNT_COLUMN_HEADER = "%21s %8s";
// Formatting for checkin service - update version if row format changes
- private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 3;
+ private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 4;
static void printRow(PrintWriter pw, String format, Object...objs) {
pw.println(String.format(format, objs));
@@ -2091,6 +2091,25 @@
pw.print(memInfo.otherPrivateClean); pw.print(',');
pw.print(memInfo.getTotalPrivateClean()); pw.print(',');
+ // Heap info - swapped out
+ pw.print(memInfo.nativeSwappedOut); pw.print(',');
+ pw.print(memInfo.dalvikSwappedOut); pw.print(',');
+ pw.print(memInfo.otherSwappedOut); pw.print(',');
+ pw.print(memInfo.getTotalSwappedOut()); pw.print(',');
+
+ // Heap info - swapped out pss
+ if (memInfo.hasSwappedOutPss) {
+ pw.print(memInfo.nativeSwappedOutPss); pw.print(',');
+ pw.print(memInfo.dalvikSwappedOutPss); pw.print(',');
+ pw.print(memInfo.otherSwappedOutPss); pw.print(',');
+ pw.print(memInfo.getTotalSwappedOutPss()); pw.print(',');
+ } else {
+ pw.print("N/A,");
+ pw.print("N/A,");
+ pw.print("N/A,");
+ pw.print("N/A,");
+ }
+
// Heap info - other areas
for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
pw.print(Debug.MemoryInfo.getOtherLabel(i)); pw.print(',');
@@ -2100,6 +2119,12 @@
pw.print(memInfo.getOtherSharedClean(i)); pw.print(',');
pw.print(memInfo.getOtherPrivateDirty(i)); pw.print(',');
pw.print(memInfo.getOtherPrivateClean(i)); pw.print(',');
+ pw.print(memInfo.getOtherSwappedOut(i)); pw.print(',');
+ if (memInfo.hasSwappedOutPss) {
+ pw.print(memInfo.getOtherSwappedOutPss(i)); pw.print(',');
+ } else {
+ pw.print("N/A,");
+ }
}
return;
}
@@ -2107,35 +2132,44 @@
if (!dumpSummaryOnly) {
if (dumpFullInfo) {
printRow(pw, HEAP_FULL_COLUMN, "", "Pss", "Pss", "Shared", "Private",
- "Shared", "Private", "Swapped", "Heap", "Heap", "Heap");
+ "Shared", "Private", memInfo.hasSwappedOutPss ? "SwapPss" : "Swap",
+ "Heap", "Heap", "Heap");
printRow(pw, HEAP_FULL_COLUMN, "", "Total", "Clean", "Dirty", "Dirty",
- "Clean", "Clean", "Dirty", "Size", "Alloc", "Free");
+ "Clean", "Clean", "Dirty",
+ "Size", "Alloc", "Free");
printRow(pw, HEAP_FULL_COLUMN, "", "------", "------", "------", "------",
"------", "------", "------", "------", "------", "------");
printRow(pw, HEAP_FULL_COLUMN, "Native Heap", memInfo.nativePss,
memInfo.nativeSwappablePss, memInfo.nativeSharedDirty,
memInfo.nativePrivateDirty, memInfo.nativeSharedClean,
- memInfo.nativePrivateClean, memInfo.nativeSwappedOut,
+ memInfo.nativePrivateClean, memInfo.hasSwappedOutPss ?
+ memInfo.nativeSwappedOut : memInfo.nativeSwappedOutPss,
nativeMax, nativeAllocated, nativeFree);
printRow(pw, HEAP_FULL_COLUMN, "Dalvik Heap", memInfo.dalvikPss,
memInfo.dalvikSwappablePss, memInfo.dalvikSharedDirty,
memInfo.dalvikPrivateDirty, memInfo.dalvikSharedClean,
- memInfo.dalvikPrivateClean, memInfo.dalvikSwappedOut,
+ memInfo.dalvikPrivateClean, memInfo.hasSwappedOutPss ?
+ memInfo.dalvikSwappedOut : memInfo.dalvikSwappedOutPss,
dalvikMax, dalvikAllocated, dalvikFree);
} else {
printRow(pw, HEAP_COLUMN, "", "Pss", "Private",
- "Private", "Swapped", "Heap", "Heap", "Heap");
+ "Private", memInfo.hasSwappedOutPss ? "SwapPss" : "Swap",
+ "Heap", "Heap", "Heap");
printRow(pw, HEAP_COLUMN, "", "Total", "Dirty",
"Clean", "Dirty", "Size", "Alloc", "Free");
printRow(pw, HEAP_COLUMN, "", "------", "------", "------",
"------", "------", "------", "------", "------");
printRow(pw, HEAP_COLUMN, "Native Heap", memInfo.nativePss,
memInfo.nativePrivateDirty,
- memInfo.nativePrivateClean, memInfo.nativeSwappedOut,
+ memInfo.nativePrivateClean,
+ memInfo.hasSwappedOutPss ? memInfo.nativeSwappedOutPss :
+ memInfo.nativeSwappedOut,
nativeMax, nativeAllocated, nativeFree);
printRow(pw, HEAP_COLUMN, "Dalvik Heap", memInfo.dalvikPss,
memInfo.dalvikPrivateDirty,
- memInfo.dalvikPrivateClean, memInfo.dalvikSwappedOut,
+ memInfo.dalvikPrivateClean,
+ memInfo.hasSwappedOutPss ? memInfo.dalvikSwappedOutPss :
+ memInfo.dalvikSwappedOut,
dalvikMax, dalvikAllocated, dalvikFree);
}
@@ -2146,6 +2180,7 @@
int otherSharedClean = memInfo.otherSharedClean;
int otherPrivateClean = memInfo.otherPrivateClean;
int otherSwappedOut = memInfo.otherSwappedOut;
+ int otherSwappedOutPss = memInfo.otherSwappedOutPss;
for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
final int myPss = memInfo.getOtherPss(i);
@@ -2155,16 +2190,22 @@
final int mySharedClean = memInfo.getOtherSharedClean(i);
final int myPrivateClean = memInfo.getOtherPrivateClean(i);
final int mySwappedOut = memInfo.getOtherSwappedOut(i);
+ final int mySwappedOutPss = memInfo.getOtherSwappedOutPss(i);
if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
- || mySharedClean != 0 || myPrivateClean != 0 || mySwappedOut != 0) {
+ || mySharedClean != 0 || myPrivateClean != 0
+ || (memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut) != 0) {
if (dumpFullInfo) {
printRow(pw, HEAP_FULL_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
- mySharedClean, myPrivateClean, mySwappedOut, "", "", "");
+ mySharedClean, myPrivateClean,
+ memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut,
+ "", "", "");
} else {
printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
myPss, myPrivateDirty,
- myPrivateClean, mySwappedOut, "", "", "");
+ myPrivateClean,
+ memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut,
+ "", "", "");
}
otherPss -= myPss;
otherSwappablePss -= mySwappablePss;
@@ -2173,26 +2214,32 @@
otherSharedClean -= mySharedClean;
otherPrivateClean -= myPrivateClean;
otherSwappedOut -= mySwappedOut;
+ otherSwappedOutPss -= mySwappedOutPss;
}
}
if (dumpFullInfo) {
printRow(pw, HEAP_FULL_COLUMN, "Unknown", otherPss, otherSwappablePss,
otherSharedDirty, otherPrivateDirty, otherSharedClean, otherPrivateClean,
- otherSwappedOut, "", "", "");
+ memInfo.hasSwappedOutPss ? otherSwappedOutPss : otherSwappedOut,
+ "", "", "");
printRow(pw, HEAP_FULL_COLUMN, "TOTAL", memInfo.getTotalPss(),
memInfo.getTotalSwappablePss(),
memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
memInfo.getTotalSharedClean(), memInfo.getTotalPrivateClean(),
- memInfo.getTotalSwappedOut(), nativeMax+dalvikMax,
- nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
+ memInfo.hasSwappedOutPss ? memInfo.getTotalSwappedOut() :
+ memInfo.getTotalSwappedOutPss(),
+ nativeMax+dalvikMax, nativeAllocated+dalvikAllocated,
+ nativeFree+dalvikFree);
} else {
printRow(pw, HEAP_COLUMN, "Unknown", otherPss,
- otherPrivateDirty, otherPrivateClean, otherSwappedOut,
+ otherPrivateDirty, otherPrivateClean,
+ memInfo.hasSwappedOutPss ? otherSwappedOutPss : otherSwappedOut,
"", "", "");
printRow(pw, HEAP_COLUMN, "TOTAL", memInfo.getTotalPss(),
memInfo.getTotalPrivateDirty(),
memInfo.getTotalPrivateClean(),
+ memInfo.hasSwappedOutPss ? memInfo.getTotalSwappedOutPss() :
memInfo.getTotalSwappedOut(),
nativeMax+dalvikMax,
nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
@@ -2211,16 +2258,22 @@
final int mySharedClean = memInfo.getOtherSharedClean(i);
final int myPrivateClean = memInfo.getOtherPrivateClean(i);
final int mySwappedOut = memInfo.getOtherSwappedOut(i);
+ final int mySwappedOutPss = memInfo.getOtherSwappedOutPss(i);
if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
- || mySharedClean != 0 || myPrivateClean != 0) {
+ || mySharedClean != 0 || myPrivateClean != 0
+ || (memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut) != 0) {
if (dumpFullInfo) {
printRow(pw, HEAP_FULL_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
- mySharedClean, myPrivateClean, mySwappedOut, "", "", "");
+ mySharedClean, myPrivateClean,
+ memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut,
+ "", "", "");
} else {
printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
myPss, myPrivateDirty,
- myPrivateClean, mySwappedOut, "", "", "");
+ myPrivateClean,
+ memInfo.hasSwappedOutPss ? mySwappedOutPss : mySwappedOut,
+ "", "", "");
}
}
}
@@ -2246,9 +2299,15 @@
printRow(pw, ONE_COUNT_COLUMN,
"System:", memInfo.getSummarySystem());
pw.println(" ");
- printRow(pw, TWO_COUNT_COLUMNS,
- "TOTAL:", memInfo.getSummaryTotalPss(),
- "TOTAL SWAP (KB):", memInfo.getSummaryTotalSwap());
+ if (memInfo.hasSwappedOutPss) {
+ printRow(pw, TWO_COUNT_COLUMNS,
+ "TOTAL:", memInfo.getSummaryTotalPss(),
+ "TOTAL SWAP PSS:", memInfo.getSummaryTotalSwapPss());
+ } else {
+ printRow(pw, TWO_COUNT_COLUMNS,
+ "TOTAL:", memInfo.getSummaryTotalPss(),
+ "TOTAL SWAP (KB):", memInfo.getSummaryTotalSwap());
+ }
}
public void registerOnActivityPausedListener(Activity activity,
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 38abac7..5113e19 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4413,6 +4413,15 @@
final PackageParser parser = new PackageParser();
final File apkFile = new File(archiveFilePath);
try {
+ if ((flags & (MATCH_ENCRYPTION_UNAWARE | MATCH_ENCRYPTION_AWARE)) != 0) {
+ // Caller expressed an explicit opinion about what encryption
+ // aware/unaware components they want to see, so fall through and
+ // give them what they want
+ } else {
+ // Caller expressed no opinion, so match everything
+ flags |= MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
+ }
+
PackageParser.Package pkg = parser.parseMonolithicPackage(apkFile, 0);
if ((flags & GET_SIGNATURES) != 0) {
parser.collectCertificates(pkg, 0);
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index f642f08..2826882 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1258,6 +1258,10 @@
*/
@CallSuper
public boolean onEvaluateInputViewShown() {
+ if (mSettingsObserver == null) {
+ Log.w(TAG, "onEvaluateInputViewShown: mSettingsObserver must not be null here.");
+ return false;
+ }
if (mSettingsObserver.shouldShowImeWithHardKeyboard()) {
return true;
}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index fdd34f5..e58744b 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -130,6 +130,9 @@
/** The dirty dalvik pages that have been swapped out. */
/** @hide We may want to expose this, eventually. */
public int dalvikSwappedOut;
+ /** The dirty dalvik pages that have been swapped out, proportional. */
+ /** @hide We may want to expose this, eventually. */
+ public int dalvikSwappedOutPss;
/** The proportional set size for the native heap. */
public int nativePss;
@@ -149,6 +152,9 @@
/** The dirty native pages that have been swapped out. */
/** @hide We may want to expose this, eventually. */
public int nativeSwappedOut;
+ /** The dirty native pages that have been swapped out, proportional. */
+ /** @hide We may want to expose this, eventually. */
+ public int nativeSwappedOutPss;
/** The proportional set size for everything else. */
public int otherPss;
@@ -168,6 +174,13 @@
/** The dirty pages used by anyting else that have been swapped out. */
/** @hide We may want to expose this, eventually. */
public int otherSwappedOut;
+ /** The dirty pages used by anyting else that have been swapped out, proportional. */
+ /** @hide We may want to expose this, eventually. */
+ public int otherSwappedOutPss;
+
+ /** Whether the kernel reports proportional swap usage */
+ /** @hide */
+ public boolean hasSwappedOutPss;
/** @hide */
public static final int HEAP_UNKNOWN = 0;
@@ -235,7 +248,7 @@
public static final int NUM_DVK_STATS = 8;
/** @hide */
- public static final int NUM_CATEGORIES = 7;
+ public static final int NUM_CATEGORIES = 8;
/** @hide */
public static final int offsetPss = 0;
@@ -251,6 +264,8 @@
public static final int offsetSharedClean = 5;
/** @hide */
public static final int offsetSwappedOut = 6;
+ /** @hide */
+ public static final int offsetSwappedOutPss = 7;
private int[] otherStats = new int[(NUM_OTHER_STATS+NUM_DVK_STATS)*NUM_CATEGORIES];
@@ -261,7 +276,7 @@
* Return total PSS memory usage in kB.
*/
public int getTotalPss() {
- return dalvikPss + nativePss + otherPss;
+ return dalvikPss + nativePss + otherPss + getTotalSwappedOutPss();
}
/**
@@ -274,7 +289,8 @@
}
/**
- * Return total PSS memory usage in kB.
+ * Return total PSS memory usage in kB mapping a file of one of the following extension:
+ * .so, .jar, .apk, .ttf, .dex, .odex, .oat, .art .
*/
public int getTotalSwappablePss() {
return dalvikSwappablePss + nativeSwappablePss + otherSwappablePss;
@@ -316,6 +332,14 @@
return dalvikSwappedOut + nativeSwappedOut + otherSwappedOut;
}
+ /**
+ * Return total swapped out memory in kB, proportional.
+ * @hide
+ */
+ public int getTotalSwappedOutPss() {
+ return dalvikSwappedOutPss + nativeSwappedOutPss + otherSwappedOutPss;
+ }
+
/** @hide */
public int getOtherPss(int which) {
return otherStats[which*NUM_CATEGORIES + offsetPss];
@@ -359,6 +383,11 @@
}
/** @hide */
+ public int getOtherSwappedOutPss(int which) {
+ return otherStats[which*NUM_CATEGORIES + offsetSwappedOutPss];
+ }
+
+ /** @hide */
public static String getOtherLabel(int which) {
switch (which) {
case OTHER_DALVIK_OTHER: return "Dalvik Other";
@@ -632,12 +661,24 @@
* know if the Swap memory is shared or private, so we don't know
* what to blame on the application and what on the system.
* For now, just lump all the Swap in one place.
+ * For kernels reporting SwapPss {@link #getSummaryTotalSwapPss()}
+ * will report the application proportional Swap.
* @hide
*/
public int getSummaryTotalSwap() {
return getTotalSwappedOut();
}
+ /**
+ * Total proportional Swap in KB.
+ * Notes:
+ * * Always 0 if {@link #hasSwappedOutPss} is false.
+ * @hide
+ */
+ public int getSummaryTotalSwapPss() {
+ return getTotalSwappedOutPss();
+ }
+
public int describeContents() {
return 0;
}
@@ -664,6 +705,8 @@
dest.writeInt(otherPrivateClean);
dest.writeInt(otherSharedClean);
dest.writeInt(otherSwappedOut);
+ dest.writeInt(hasSwappedOutPss ? 1 : 0);
+ dest.writeInt(otherSwappedOutPss);
dest.writeIntArray(otherStats);
}
@@ -689,6 +732,8 @@
otherPrivateClean = source.readInt();
otherSharedClean = source.readInt();
otherSwappedOut = source.readInt();
+ hasSwappedOutPss = source.readInt() != 0;
+ otherSwappedOutPss = source.readInt();
otherStats = source.createIntArray();
}
@@ -1563,11 +1608,12 @@
/**
* Retrieves the PSS memory used by the process as given by the
- * smaps. Optionally supply a long array of 1 entry to also
- * receive the uss of the process, and another array to also
- * retrieve the separate memtrack size. @hide
+ * smaps. Optionally supply a long array of 2 entries to also
+ * receive the Uss and SwapPss of the process, and another array to also
+ * retrieve the separate memtrack size.
+ * @hide
*/
- public static native long getPss(int pid, long[] outUss, long[] outMemtrack);
+ public static native long getPss(int pid, long[] outUssSwapPss, long[] outMemtrack);
/** @hide */
public static final int MEMINFO_TOTAL = 0;
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index c42c791..2a52961 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -688,13 +688,14 @@
* @param bottom the bottom of the line
* @param fmi receives metrics information, can be null
* @param needWidth true if the width of the run is needed
+ * @param offset the offset for the purpose of measuring
* @return the signed width of the run based on the run direction; only
* valid if needWidth is true
*/
private float handleText(TextPaint wp, int start, int end,
int contextStart, int contextEnd, boolean runIsRtl,
Canvas c, float x, int top, int y, int bottom,
- FontMetricsInt fmi, boolean needWidth) {
+ FontMetricsInt fmi, boolean needWidth, int offset) {
// Get metrics first (even for empty strings or "0" width runs)
if (fmi != null) {
@@ -712,11 +713,11 @@
if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) {
if (mCharsValid) {
ret = wp.getRunAdvance(mChars, start, end, contextStart, contextEnd,
- runIsRtl, end);
+ runIsRtl, offset);
} else {
int delta = mStart;
ret = wp.getRunAdvance(mText, delta + start, delta + end,
- delta + contextStart, delta + contextEnd, runIsRtl, delta + end);
+ delta + contextStart, delta + contextEnd, runIsRtl, delta + offset);
}
}
@@ -865,8 +866,8 @@
TextPaint wp = mWorkPaint;
wp.set(mPaint);
final int mlimit = measureLimit;
- return handleText(wp, start, mlimit, start, limit, runIsRtl, c, x, top,
- y, bottom, fmi, needWidth || mlimit < measureLimit);
+ return handleText(wp, start, limit, start, limit, runIsRtl, c, x, top,
+ y, bottom, fmi, needWidth || mlimit < measureLimit, mlimit);
}
mMetricAffectingSpanSpanSet.init(mSpanned, mStart + start, mStart + limit);
@@ -910,13 +911,14 @@
}
for (int j = i, jnext; j < mlimit; j = jnext) {
- jnext = mCharacterStyleSpanSet.getNextTransition(mStart + j, mStart + mlimit) -
+ jnext = mCharacterStyleSpanSet.getNextTransition(mStart + j, mStart + inext) -
mStart;
+ int offset = Math.min(jnext, mlimit);
wp.set(mPaint);
for (int k = 0; k < mCharacterStyleSpanSet.numberOfSpans; k++) {
// Intentionally using >= and <= as explained above
- if ((mCharacterStyleSpanSet.spanStarts[k] >= mStart + jnext) ||
+ if ((mCharacterStyleSpanSet.spanStarts[k] >= mStart + offset) ||
(mCharacterStyleSpanSet.spanEnds[k] <= mStart + j)) continue;
CharacterStyle span = mCharacterStyleSpanSet.spans[k];
@@ -928,7 +930,7 @@
wp.setHyphenEdit(0);
}
x += handleText(wp, j, jnext, i, inext, runIsRtl, c, x,
- top, y, bottom, fmi, needWidth || jnext < measureLimit);
+ top, y, bottom, fmi, needWidth || jnext < measureLimit, offset);
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 0fb3951..3eb2e37 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1488,7 +1488,8 @@
if ((lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
|| lp.height == ViewGroup.LayoutParams.WRAP_CONTENT)
&& (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
- || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD)) {
+ || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD
+ || lp.type == WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY)) {
windowSizeMayChange = true;
// NOTE -- system code, won't try to do compat mode.
Point size = new Point();
diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java
index 830da79..b3222f0 100644
--- a/core/java/com/android/internal/os/InstallerConnection.java
+++ b/core/java/com/android/internal/os/InstallerConnection.java
@@ -19,6 +19,7 @@
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.SystemClock;
+import android.text.TextUtils;
import android.util.Slog;
import com.android.internal.util.Preconditions;
@@ -29,6 +30,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.Arrays;
/**
* Represents a connection to {@code installd}. Allows multiple connect and
@@ -61,6 +63,11 @@
}
public synchronized String transact(String cmd) {
+ if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
+ Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
+ + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
+ }
+
if (!connect()) {
Slog.e(TAG, "connection failed");
return "-1";
@@ -96,44 +103,50 @@
}
}
- public int execute(String cmd) {
- if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
- Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
- + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
- }
-
- String res = transact(cmd);
+ public void execute(String cmd, Object... args) throws InstallerException {
+ final String resRaw = executeForResult(cmd, args);
+ int res = -1;
try {
- return Integer.parseInt(res);
- } catch (NumberFormatException ex) {
- return -1;
+ res = Integer.parseInt(resRaw);
+ } catch (NumberFormatException ignored) {
+ }
+ if (res != 0) {
+ throw new InstallerException(
+ "Failed to execute " + cmd + " " + Arrays.toString(args) + ": " + res);
}
}
- public int dexopt(String apkPath, int uid, String instructionSet,
- int dexoptNeeded, int dexFlags) {
- return dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded,
- null /*outputPath*/, dexFlags);
+ public String executeForResult(String cmd, Object... args)
+ throws InstallerException {
+ final StringBuilder builder = new StringBuilder(cmd);
+ for (Object arg : args) {
+ String escaped;
+ if (arg == null) {
+ escaped = "";
+ } else {
+ escaped = String.valueOf(arg);
+ }
+ if (escaped.indexOf('\0') != -1 || escaped.indexOf(' ') != -1 || "!".equals(escaped)) {
+ throw new InstallerException(
+ "Invalid argument while executing " + cmd + " " + Arrays.toString(args));
+ }
+ if (TextUtils.isEmpty(escaped)) {
+ escaped = "!";
+ }
+ builder.append(' ').append(escaped);
+ }
+ return transact(builder.toString());
}
- public int dexopt(String apkPath, int uid, String pkgName, String instructionSet,
- int dexoptNeeded, String outputPath, int dexFlags) {
- StringBuilder builder = new StringBuilder("dexopt");
- builder.append(' ');
- builder.append(apkPath);
- builder.append(' ');
- builder.append(uid);
- builder.append(' ');
- builder.append(pkgName);
- builder.append(' ');
- builder.append(instructionSet);
- builder.append(' ');
- builder.append(dexoptNeeded);
- builder.append(' ');
- builder.append(outputPath != null ? outputPath : "!");
- builder.append(' ');
- builder.append(dexFlags);
- return execute(builder.toString());
+ public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded,
+ int dexFlags) throws InstallerException {
+ dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded, null /* outputPath */, dexFlags);
+ }
+
+ public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
+ int dexoptNeeded, String outputPath, int dexFlags) throws InstallerException {
+ execute("dexopt", apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
+ dexFlags);
}
private boolean connect() {
@@ -227,11 +240,19 @@
public void waitForConnection() {
for (;;) {
- if (execute("ping") >= 0) {
+ try {
+ execute("ping");
return;
+ } catch (InstallerException ignored) {
}
Slog.w(TAG, "installd not ready");
SystemClock.sleep(1000);
}
}
+
+ public static class InstallerException extends Exception {
+ public InstallerException(String detailMessage) {
+ super(detailMessage);
+ }
+ }
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 4a1f7f4..eecc0ee 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -37,6 +37,8 @@
import android.util.Log;
import android.webkit.WebViewFactory;
+import com.android.internal.os.InstallerConnection.InstallerException;
+
import dalvik.system.DexFile;
import dalvik.system.PathClassLoader;
import dalvik.system.VMRuntime;
@@ -502,8 +504,8 @@
dexoptNeeded, 0 /*dexFlags*/);
}
}
- } catch (IOException ioe) {
- throw new RuntimeException("Error starting system_server", ioe);
+ } catch (IOException | InstallerException e) {
+ throw new RuntimeException("Error starting system_server", e);
} finally {
installer.disconnect();
}
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index e162810..8e8f6c3 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -152,7 +152,8 @@
static struct {
jmethodID postDynPolicyEventFromNative;
-} gDynPolicyEventHandlerMethods;
+ jmethodID postRecordConfigEventFromNative;
+} gAudioPolicyEventHandlerMethods;
static Mutex gLock;
@@ -378,12 +379,26 @@
const char* zechars = regId.string();
jstring zestring = env->NewStringUTF(zechars);
- env->CallStaticVoidMethod(clazz, gDynPolicyEventHandlerMethods.postDynPolicyEventFromNative,
+ env->CallStaticVoidMethod(clazz, gAudioPolicyEventHandlerMethods.postDynPolicyEventFromNative,
event, zestring, val);
env->ReleaseStringUTFChars(zestring, zechars);
env->DeleteLocalRef(clazz);
+}
+static void
+android_media_AudioSystem_recording_callback(int event, int session, int source)
+{
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ if (env == NULL) {
+ return;
+ }
+
+ jclass clazz = env->FindClass(kClassPathName);
+ env->CallStaticVoidMethod(clazz,
+ gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative,
+ event, session, source);
+ env->DeleteLocalRef(clazz);
}
static jint
@@ -1503,6 +1518,12 @@
AudioSystem::setDynPolicyCallback(android_media_AudioSystem_dyn_policy_callback);
}
+static void
+android_media_AudioSystem_registerRecordingCallback(JNIEnv *env, jobject thiz)
+{
+ AudioSystem::setRecordConfigCallback(android_media_AudioSystem_recording_callback);
+}
+
static jint convertAudioMixToNative(JNIEnv *env,
AudioMix *nAudioMix,
@@ -1677,6 +1698,8 @@
(void *)android_media_AudioSystem_registerPolicyMixes},
{"native_register_dynamic_policy_callback", "()V",
(void *)android_media_AudioSystem_registerDynPolicyCallback},
+ {"native_register_recording_callback", "()V",
+ (void *)android_media_AudioSystem_registerRecordingCallback},
{"systemReady", "()I", (void *)android_media_AudioSystem_systemReady},
};
@@ -1780,9 +1803,12 @@
gEventHandlerFields.mJniCallback = GetFieldIDOrDie(env,
eventHandlerClass, "mJniCallback", "J");
- gDynPolicyEventHandlerMethods.postDynPolicyEventFromNative =
+ gAudioPolicyEventHandlerMethods.postDynPolicyEventFromNative =
GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName),
"dynamicPolicyCallbackFromNative", "(ILjava/lang/String;I)V");
+ gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative =
+ GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName),
+ "recordingCallbackFromNative", "(III)V");
jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 2488111..03a1e71 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -84,6 +84,7 @@
jfieldID privateClean_field;
jfieldID sharedClean_field;
jfieldID swappedOut_field;
+ jfieldID swappedOutPss_field;
};
struct stat_field_names {
@@ -94,20 +95,22 @@
const char* privateClean_name;
const char* sharedClean_name;
const char* swappedOut_name;
+ const char* swappedOutPss_name;
};
static stat_fields stat_fields[_NUM_CORE_HEAP];
static stat_field_names stat_field_names[_NUM_CORE_HEAP] = {
{ "otherPss", "otherSwappablePss", "otherPrivateDirty", "otherSharedDirty",
- "otherPrivateClean", "otherSharedClean", "otherSwappedOut" },
+ "otherPrivateClean", "otherSharedClean", "otherSwappedOut", "otherSwappedOutPss" },
{ "dalvikPss", "dalvikSwappablePss", "dalvikPrivateDirty", "dalvikSharedDirty",
- "dalvikPrivateClean", "dalvikSharedClean", "dalvikSwappedOut" },
+ "dalvikPrivateClean", "dalvikSharedClean", "dalvikSwappedOut", "dalvikSwappedOutPss" },
{ "nativePss", "nativeSwappablePss", "nativePrivateDirty", "nativeSharedDirty",
- "nativePrivateClean", "nativeSharedClean", "nativeSwappedOut" }
+ "nativePrivateClean", "nativeSharedClean", "nativeSwappedOut", "nativeSwappedOutPss" }
};
jfieldID otherStats_field;
+jfieldID hasSwappedOutPss_field;
static bool memtrackLoaded;
@@ -119,6 +122,7 @@
int privateClean;
int sharedClean;
int swappedOut;
+ int swappedOutPss;
};
#define BINDER_STATS "/proc/binder/stats"
@@ -206,7 +210,7 @@
return err;
}
-static void read_mapinfo(FILE *fp, stats_t* stats)
+static void read_mapinfo(FILE *fp, stats_t* stats, bool* foundSwapPss)
{
char line[1024];
int len, nameLen;
@@ -216,7 +220,7 @@
float sharing_proportion = 0.0;
unsigned shared_clean = 0, shared_dirty = 0;
unsigned private_clean = 0, private_dirty = 0;
- unsigned swapped_out = 0;
+ unsigned swapped_out = 0, swapped_out_pss = 0;
bool is_swappable = false;
unsigned temp;
@@ -230,6 +234,8 @@
int subHeap = HEAP_UNKNOWN;
int prevHeap = HEAP_UNKNOWN;
+ *foundSwapPss = false;
+
if(fgets(line, sizeof(line), fp) == 0) return;
while (!done) {
@@ -340,6 +346,7 @@
private_clean = 0;
private_dirty = 0;
swapped_out = 0;
+ swapped_out_pss = 0;
while (true) {
if (fgets(line, 1024, fp) == 0) {
@@ -365,6 +372,9 @@
/* referenced = temp; */
} else if (line[0] == 'S' && sscanf(line, "Swap: %d kB", &temp) == 1) {
swapped_out = temp;
+ } else if (line[0] == 'S' && sscanf(line, "SwapPss: %d kB", &temp) == 1) {
+ *foundSwapPss = true;
+ swapped_out_pss = temp;
} else if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %*s %*x %*x:%*x %*d", &start, &end) == 2) {
// looks like a new mapping
// example: "10000000-10001000 ---p 10000000 00:00 0"
@@ -390,6 +400,7 @@
stats[whichHeap].privateClean += private_clean;
stats[whichHeap].sharedClean += shared_clean;
stats[whichHeap].swappedOut += swapped_out;
+ stats[whichHeap].swappedOutPss += swapped_out_pss;
if (whichHeap == HEAP_DALVIK || whichHeap == HEAP_DALVIK_OTHER) {
stats[subHeap].pss += pss;
stats[subHeap].swappablePss += swappable_pss;
@@ -398,12 +409,13 @@
stats[subHeap].privateClean += private_clean;
stats[subHeap].sharedClean += shared_clean;
stats[subHeap].swappedOut += swapped_out;
+ stats[subHeap].swappedOutPss += swapped_out_pss;
}
}
}
}
-static void load_maps(int pid, stats_t* stats)
+static void load_maps(int pid, stats_t* stats, bool* foundSwapPss)
{
char tmp[128];
FILE *fp;
@@ -412,17 +424,18 @@
fp = fopen(tmp, "r");
if (fp == 0) return;
- read_mapinfo(fp, stats);
+ read_mapinfo(fp, stats, foundSwapPss);
fclose(fp);
}
static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
jint pid, jobject object)
{
+ bool foundSwapPss;
stats_t stats[_NUM_HEAP];
memset(&stats, 0, sizeof(stats));
- load_maps(pid, stats);
+ load_maps(pid, stats, &foundSwapPss);
struct graphics_memory_pss graphics_mem;
if (read_memtrack_memory(pid, &graphics_mem) == 0) {
@@ -442,6 +455,7 @@
stats[HEAP_UNKNOWN].privateClean += stats[i].privateClean;
stats[HEAP_UNKNOWN].sharedClean += stats[i].sharedClean;
stats[HEAP_UNKNOWN].swappedOut += stats[i].swappedOut;
+ stats[HEAP_UNKNOWN].swappedOutPss += stats[i].swappedOutPss;
}
for (int i=0; i<_NUM_CORE_HEAP; i++) {
@@ -452,9 +466,11 @@
env->SetIntField(object, stat_fields[i].privateClean_field, stats[i].privateClean);
env->SetIntField(object, stat_fields[i].sharedClean_field, stats[i].sharedClean);
env->SetIntField(object, stat_fields[i].swappedOut_field, stats[i].swappedOut);
+ env->SetIntField(object, stat_fields[i].swappedOutPss_field, stats[i].swappedOutPss);
}
+ env->SetBooleanField(object, hasSwappedOutPss_field, foundSwapPss);
jintArray otherIntArray = (jintArray)env->GetObjectField(object, otherStats_field);
jint* otherArray = (jint*)env->GetPrimitiveArrayCritical(otherIntArray, 0);
@@ -471,6 +487,7 @@
otherArray[j++] = stats[i].privateClean;
otherArray[j++] = stats[i].sharedClean;
otherArray[j++] = stats[i].swappedOut;
+ otherArray[j++] = stats[i].swappedOutPss;
}
env->ReleasePrimitiveArrayCritical(otherIntArray, otherArray, 0);
@@ -481,11 +498,12 @@
android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object);
}
-static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid, jlongArray outUss,
- jlongArray outMemtrack)
+static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid,
+ jlongArray outUssSwapPss, jlongArray outMemtrack)
{
char line[1024];
jlong pss = 0;
+ jlong swapPss = 0;
jlong uss = 0;
jlong memtrack = 0;
@@ -521,19 +539,31 @@
}
uss += atoi(c);
}
+ } else if (line[0] == 'S' && strncmp(line, "SwapPss:", 8) == 0) {
+ char* c = line + 8;
+ jlong lSwapPss;
+ while (*c != 0 && (*c < '0' || *c > '9')) {
+ c++;
+ }
+ lSwapPss = atoi(c);
+ swapPss += lSwapPss;
+ pss += lSwapPss; // Also in swap, those pages would be accounted as Pss without SWAP
}
}
fclose(fp);
}
- if (outUss != NULL) {
- if (env->GetArrayLength(outUss) >= 1) {
- jlong* outUssArray = env->GetLongArrayElements(outUss, 0);
- if (outUssArray != NULL) {
- outUssArray[0] = uss;
+ if (outUssSwapPss != NULL) {
+ if (env->GetArrayLength(outUssSwapPss) >= 1) {
+ jlong* outUssSwapPssArray = env->GetLongArrayElements(outUssSwapPss, 0);
+ if (outUssSwapPssArray != NULL) {
+ outUssSwapPssArray[0] = uss;
+ if (env->GetArrayLength(outUssSwapPss) >= 2) {
+ outUssSwapPssArray[1] = swapPss;
+ }
}
- env->ReleaseLongArrayElements(outUss, outUssArray, 0);
+ env->ReleaseLongArrayElements(outUssSwapPss, outUssSwapPssArray, 0);
}
}
@@ -1056,6 +1086,7 @@
}
otherStats_field = env->GetFieldID(clazz, "otherStats", "[I");
+ hasSwappedOutPss_field = env->GetFieldID(clazz, "hasSwappedOutPss", "Z");
for (int i=0; i<_NUM_CORE_HEAP; i++) {
stat_fields[i].pss_field =
@@ -1072,6 +1103,8 @@
env->GetFieldID(clazz, stat_field_names[i].sharedClean_name, "I");
stat_fields[i].swappedOut_field =
env->GetFieldID(clazz, stat_field_names[i].swappedOut_name, "I");
+ stat_fields[i].swappedOutPss_field =
+ env->GetFieldID(clazz, stat_field_names[i].swappedOutPss_name, "I");
}
return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods));
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 0932e89..44c5e2f 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -109,8 +109,8 @@
BakedOpDispatcher.cpp \
BakedOpRenderer.cpp \
BakedOpState.cpp \
- FrameReorderer.cpp \
- LayerReorderer.cpp \
+ FrameBuilder.cpp \
+ LayerBuilder.cpp \
RecordingCanvas.cpp
hwui_cflags += -DHWUI_NEW_OPS
@@ -237,7 +237,7 @@
ifeq (true, $(HWUI_NEW_OPS))
LOCAL_SRC_FILES += \
tests/unit/BakedOpStateTests.cpp \
- tests/unit/FrameReordererTests.cpp \
+ tests/unit/FrameBuilderTests.cpp \
tests/unit/RecordingCanvasTests.cpp
endif
@@ -299,7 +299,7 @@
ifeq (true, $(HWUI_NEW_OPS))
LOCAL_SRC_FILES += \
- tests/microbench/FrameReordererBench.cpp
+ tests/microbench/FrameBuilderBench.cpp
endif
include $(BUILD_EXECUTABLE)
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index 23aca89..5b34f6b 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -545,19 +545,19 @@
op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch);
Texture* texture = entry ? entry->texture : renderer.caches().textureCache.get(op.bitmap);
- if (!texture) return;
- const AutoTexture autoCleanup(texture);
- Glop glop;
- GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
- .setRoundRectClipState(state.roundRectClipState)
- .setMeshPatchQuads(*mesh)
- .setMeshTexturedUnitQuad(texture->uvMapper)
- .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
- .setTransform(state.computedState.transform, TransformFlags::None)
- .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top,
- Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight()))
- .build();
- renderer.renderGlop(state, glop);
+ if (CC_LIKELY(texture)) {
+ const AutoTexture autoCleanup(texture);
+ Glop glop;
+ GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+ .setRoundRectClipState(state.roundRectClipState)
+ .setMeshPatchQuads(*mesh)
+ .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
+ .setTransform(state.computedState.transform, TransformFlags::None)
+ .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top,
+ Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight()))
+ .build();
+ renderer.renderGlop(state, glop);
+ }
}
void BakedOpDispatcher::onPathOp(BakedOpRenderer& renderer, const PathOp& op, const BakedOpState& state) {
diff --git a/libs/hwui/BakedOpState.cpp b/libs/hwui/BakedOpState.cpp
index f0406fa..87844f9 100644
--- a/libs/hwui/BakedOpState.cpp
+++ b/libs/hwui/BakedOpState.cpp
@@ -71,7 +71,6 @@
clipState = snapshot.mutateClipArea().serializeClip(allocator);
LOG_ALWAYS_FATAL_IF(!clipState, "clipState required");
clippedBounds = clipState->rect;
- transform.mapRect(clippedBounds);
clipSideFlags = OpClipSideFlags::Full;
}
diff --git a/libs/hwui/FrameReorderer.cpp b/libs/hwui/FrameBuilder.cpp
similarity index 89%
rename from libs/hwui/FrameReorderer.cpp
rename to libs/hwui/FrameBuilder.cpp
index e95b267..166656c 100644
--- a/libs/hwui/FrameReorderer.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "FrameReorderer.h"
+#include "FrameBuilder.h"
#include "LayerUpdateQueue.h"
#include "RenderNode.h"
@@ -30,25 +30,25 @@
namespace android {
namespace uirenderer {
-FrameReorderer::FrameReorderer(const LayerUpdateQueue& layers, const SkRect& clip,
+FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
uint32_t viewportWidth, uint32_t viewportHeight,
const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter)
: mCanvasState(*this) {
ATRACE_NAME("prepare drawing commands");
- mLayerReorderers.reserve(layers.entries().size());
+ mLayerBuilders.reserve(layers.entries().size());
mLayerStack.reserve(layers.entries().size());
// Prepare to defer Fbo0
- auto fbo0 = mAllocator.create<LayerReorderer>(viewportWidth, viewportHeight, Rect(clip));
- mLayerReorderers.push_back(fbo0);
+ auto fbo0 = mAllocator.create<LayerBuilder>(viewportWidth, viewportHeight, Rect(clip));
+ mLayerBuilders.push_back(fbo0);
mLayerStack.push_back(0);
mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
clip.fLeft, clip.fTop, clip.fRight, clip.fBottom,
lightCenter);
// Render all layers to be updated, in order. Defer in reverse order, so that they'll be
- // updated in the order they're passed in (mLayerReorderers are issued to Renderer in reverse)
+ // updated in the order they're passed in (mLayerBuilders are issued to Renderer in reverse)
for (int i = layers.entries().size() - 1; i >= 0; i--) {
RenderNode* layerNode = layers.entries()[i].renderNode;
const Rect& layerDamage = layers.entries()[i].damage;
@@ -78,11 +78,11 @@
}
}
-void FrameReorderer::onViewportInitialized() {}
+void FrameBuilder::onViewportInitialized() {}
-void FrameReorderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
+void FrameBuilder::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
-void FrameReorderer::deferNodePropsAndOps(RenderNode& node) {
+void FrameBuilder::deferNodePropsAndOps(RenderNode& node) {
const RenderProperties& properties = node.properties();
const Outline& outline = properties.getOutline();
if (properties.getAlpha() <= 0
@@ -214,7 +214,7 @@
}
template <typename V>
-void FrameReorderer::defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes) {
+void FrameBuilder::defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes) {
const int size = zTranslatedNodes.size();
if (size == 0
|| (mode == ChildrenSelectMode::Negative&& zTranslatedNodes[0].key > 0.0f)
@@ -264,7 +264,7 @@
}
}
-void FrameReorderer::deferShadow(const RenderNodeOp& casterNodeOp) {
+void FrameBuilder::deferShadow(const RenderNodeOp& casterNodeOp) {
auto& node = *casterNodeOp.renderNode;
auto& properties = node.properties();
@@ -320,7 +320,7 @@
}
}
-void FrameReorderer::deferProjectedChildren(const RenderNode& renderNode) {
+void FrameBuilder::deferProjectedChildren(const RenderNode& renderNode) {
const SkPath* projectionReceiverOutline = renderNode.properties().getOutline().getPath();
int count = mCanvasState.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
@@ -353,15 +353,15 @@
}
/**
- * Used to define a list of lambdas referencing private FrameReorderer::onXX::defer() methods.
+ * Used to define a list of lambdas referencing private FrameBuilder::onXX::defer() methods.
*
* This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas.
- * E.g. a BitmapOp op then would be dispatched to FrameReorderer::onBitmapOp(const BitmapOp&)
+ * E.g. a BitmapOp op then would be dispatched to FrameBuilder::onBitmapOp(const BitmapOp&)
*/
#define OP_RECEIVER(Type) \
- [](FrameReorderer& reorderer, const RecordedOp& op) { reorderer.defer##Type(static_cast<const Type&>(op)); },
-void FrameReorderer::deferNodeOps(const RenderNode& renderNode) {
- typedef void (*OpDispatcher) (FrameReorderer& reorderer, const RecordedOp& op);
+ [](FrameBuilder& frameBuilder, const RecordedOp& op) { frameBuilder.defer##Type(static_cast<const Type&>(op)); },
+void FrameBuilder::deferNodeOps(const RenderNode& renderNode) {
+ typedef void (*OpDispatcher) (FrameBuilder& frameBuilder, const RecordedOp& op);
static OpDispatcher receivers[] = BUILD_DEFERRABLE_OP_LUT(OP_RECEIVER);
// can't be null, since DL=null node rejection happens before deferNodePropsAndOps
@@ -385,7 +385,7 @@
}
}
-void FrameReorderer::deferRenderNodeOpImpl(const RenderNodeOp& op) {
+void FrameBuilder::deferRenderNodeOpImpl(const RenderNodeOp& op) {
if (op.renderNode->nothingToDraw()) return;
int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
@@ -400,7 +400,7 @@
mCanvasState.restoreToCount(count);
}
-void FrameReorderer::deferRenderNodeOp(const RenderNodeOp& op) {
+void FrameBuilder::deferRenderNodeOp(const RenderNodeOp& op) {
if (!op.skipInOrderDraw) {
deferRenderNodeOpImpl(op);
}
@@ -410,7 +410,7 @@
* Defers an unmergeable, strokeable op, accounting correctly
* for paint's style on the bounds being computed.
*/
-void FrameReorderer::deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
+void FrameBuilder::deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
BakedOpState::StrokeBehavior strokeBehavior) {
// Note: here we account for stroke when baking the op
BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct(
@@ -432,7 +432,7 @@
: (paint.isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices);
}
-void FrameReorderer::deferArcOp(const ArcOp& op) {
+void FrameBuilder::deferArcOp(const ArcOp& op) {
deferStrokeableOp(op, tessBatchId(op));
}
@@ -441,7 +441,7 @@
|| state.computedState.clipState->mode == ClipMode::Rectangle;
}
-void FrameReorderer::deferBitmapOp(const BitmapOp& op) {
+void FrameBuilder::deferBitmapOp(const BitmapOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
if (!bakedState) return; // quick rejected
@@ -461,19 +461,19 @@
}
}
-void FrameReorderer::deferBitmapMeshOp(const BitmapMeshOp& op) {
+void FrameBuilder::deferBitmapMeshOp(const BitmapMeshOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
}
-void FrameReorderer::deferBitmapRectOp(const BitmapRectOp& op) {
+void FrameBuilder::deferBitmapRectOp(const BitmapRectOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
}
-void FrameReorderer::deferCirclePropsOp(const CirclePropsOp& op) {
+void FrameBuilder::deferCirclePropsOp(const CirclePropsOp& op) {
// allocate a temporary oval op (with mAllocator, so it persists until render), so the
// renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple.
float x = *(op.x);
@@ -488,22 +488,22 @@
deferOvalOp(*resolvedOp);
}
-void FrameReorderer::deferFunctorOp(const FunctorOp& op) {
+void FrameBuilder::deferFunctorOp(const FunctorOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Functor);
}
-void FrameReorderer::deferLinesOp(const LinesOp& op) {
+void FrameBuilder::deferLinesOp(const LinesOp& op) {
batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices;
deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced);
}
-void FrameReorderer::deferOvalOp(const OvalOp& op) {
+void FrameBuilder::deferOvalOp(const OvalOp& op) {
deferStrokeableOp(op, tessBatchId(op));
}
-void FrameReorderer::deferPatchOp(const PatchOp& op) {
+void FrameBuilder::deferPatchOp(const PatchOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
if (!bakedState) return; // quick rejected
@@ -521,24 +521,24 @@
}
}
-void FrameReorderer::deferPathOp(const PathOp& op) {
+void FrameBuilder::deferPathOp(const PathOp& op) {
deferStrokeableOp(op, OpBatchType::Bitmap);
}
-void FrameReorderer::deferPointsOp(const PointsOp& op) {
+void FrameBuilder::deferPointsOp(const PointsOp& op) {
batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices;
deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced);
}
-void FrameReorderer::deferRectOp(const RectOp& op) {
+void FrameBuilder::deferRectOp(const RectOp& op) {
deferStrokeableOp(op, tessBatchId(op));
}
-void FrameReorderer::deferRoundRectOp(const RoundRectOp& op) {
+void FrameBuilder::deferRoundRectOp(const RoundRectOp& op) {
deferStrokeableOp(op, tessBatchId(op));
}
-void FrameReorderer::deferRoundRectPropsOp(const RoundRectPropsOp& op) {
+void FrameBuilder::deferRoundRectPropsOp(const RoundRectPropsOp& op) {
// allocate a temporary round rect op (with mAllocator, so it persists until render), so the
// renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple.
const RoundRectOp* resolvedOp = new (mAllocator) RoundRectOp(
@@ -549,7 +549,7 @@
deferRoundRectOp(*resolvedOp);
}
-void FrameReorderer::deferSimpleRectsOp(const SimpleRectsOp& op) {
+void FrameBuilder::deferSimpleRectsOp(const SimpleRectsOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices);
@@ -560,7 +560,7 @@
return paint.getColor() == SK_ColorBLACK ? OpBatchType::Text : OpBatchType::ColorText;
}
-void FrameReorderer::deferTextOp(const TextOp& op) {
+void FrameBuilder::deferTextOp(const TextOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
if (!bakedState) return; // quick rejected
@@ -575,19 +575,19 @@
}
}
-void FrameReorderer::deferTextOnPathOp(const TextOnPathOp& op) {
+void FrameBuilder::deferTextOnPathOp(const TextOnPathOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, textBatchId(*(op.paint)));
}
-void FrameReorderer::deferTextureLayerOp(const TextureLayerOp& op) {
+void FrameBuilder::deferTextureLayerOp(const TextureLayerOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::TextureLayer);
}
-void FrameReorderer::saveForLayer(uint32_t layerWidth, uint32_t layerHeight,
+void FrameBuilder::saveForLayer(uint32_t layerWidth, uint32_t layerHeight,
float contentTranslateX, float contentTranslateY,
const Rect& repaintRect,
const Vector3& lightCenter,
@@ -602,13 +602,13 @@
repaintRect.left, repaintRect.top, repaintRect.right, repaintRect.bottom);
// create a new layer repaint, and push its index on the stack
- mLayerStack.push_back(mLayerReorderers.size());
- auto newFbo = mAllocator.create<LayerReorderer>(layerWidth, layerHeight,
+ mLayerStack.push_back(mLayerBuilders.size());
+ auto newFbo = mAllocator.create<LayerBuilder>(layerWidth, layerHeight,
repaintRect, beginLayerOp, renderNode);
- mLayerReorderers.push_back(newFbo);
+ mLayerBuilders.push_back(newFbo);
}
-void FrameReorderer::restoreForLayer() {
+void FrameBuilder::restoreForLayer() {
// restore canvas, and pop finished layer off of the stack
mCanvasState.restore();
mLayerStack.pop_back();
@@ -616,7 +616,7 @@
// TODO: defer time rejection (when bounds become empty) + tests
// Option - just skip layers with no bounds at playback + defer?
-void FrameReorderer::deferBeginLayerOp(const BeginLayerOp& op) {
+void FrameBuilder::deferBeginLayerOp(const BeginLayerOp& op) {
uint32_t layerWidth = (uint32_t) op.unmappedBounds.getWidth();
uint32_t layerHeight = (uint32_t) op.unmappedBounds.getHeight();
@@ -661,7 +661,7 @@
&op, nullptr);
}
-void FrameReorderer::deferEndLayerOp(const EndLayerOp& /* ignored */) {
+void FrameBuilder::deferEndLayerOp(const EndLayerOp& /* ignored */) {
const BeginLayerOp& beginLayerOp = *currentLayer().beginLayerOp;
int finishedLayerIndex = mLayerStack.back();
@@ -674,7 +674,7 @@
beginLayerOp.localMatrix,
beginLayerOp.localClip,
beginLayerOp.paint,
- &(mLayerReorderers[finishedLayerIndex]->offscreenBuffer));
+ &(mLayerBuilders[finishedLayerIndex]->offscreenBuffer));
BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
if (bakedOpState) {
@@ -684,12 +684,12 @@
// Layer won't be drawn - delete its drawing batches to prevent it from doing any work
// TODO: need to prevent any render work from being done
// - create layerop earlier for reject purposes?
- mLayerReorderers[finishedLayerIndex]->clear();
+ mLayerBuilders[finishedLayerIndex]->clear();
return;
}
}
-void FrameReorderer::deferBeginUnclippedLayerOp(const BeginUnclippedLayerOp& op) {
+void FrameBuilder::deferBeginUnclippedLayerOp(const BeginUnclippedLayerOp& op) {
Matrix4 boundsTransform(*(mCanvasState.currentSnapshot()->transform));
boundsTransform.multiply(op.localMatrix);
@@ -724,7 +724,7 @@
currentLayer().activeUnclippedSaveLayers.push_back(bakedState);
}
-void FrameReorderer::deferEndUnclippedLayerOp(const EndUnclippedLayerOp& /* ignored */) {
+void FrameBuilder::deferEndUnclippedLayerOp(const EndUnclippedLayerOp& /* ignored */) {
LOG_ALWAYS_FATAL_IF(currentLayer().activeUnclippedSaveLayers.empty(), "no layer to end!");
BakedOpState* copyFromLayerOp = currentLayer().activeUnclippedSaveLayers.back();
diff --git a/libs/hwui/FrameReorderer.h b/libs/hwui/FrameBuilder.h
similarity index 89%
rename from libs/hwui/FrameReorderer.h
rename to libs/hwui/FrameBuilder.h
index 3bb8626..3ba73f0 100644
--- a/libs/hwui/FrameReorderer.h
+++ b/libs/hwui/FrameBuilder.h
@@ -19,7 +19,7 @@
#include "BakedOpState.h"
#include "CanvasState.h"
#include "DisplayList.h"
-#include "LayerReorderer.h"
+#include "LayerBuilder.h"
#include "RecordedOp.h"
#include <vector>
@@ -42,7 +42,7 @@
* Resolves final drawing state for each operation (including clip, alpha and matrix), and then
* reorder and merge each op as it is resolved for drawing efficiency. Each layer of content (either
* from the LayerUpdateQueue, or temporary layers created by saveLayer operations in the
- * draw stream) will create different reorder contexts, each in its own LayerReorderer.
+ * draw stream) will create different reorder contexts, each in its own LayerBuilder.
*
* Then the prepared or 'baked' drawing commands can be issued by calling the templated
* replayBakedOps() function, which will dispatch them (including any created merged op collections)
@@ -52,13 +52,13 @@
* This class is also the authoritative source for traversing RenderNodes, both for standard op
* traversal within a DisplayList, and for out of order RenderNode traversal for Z and projection.
*/
-class FrameReorderer : public CanvasStateClient {
+class FrameBuilder : public CanvasStateClient {
public:
- FrameReorderer(const LayerUpdateQueue& layers, const SkRect& clip,
+ FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
uint32_t viewportWidth, uint32_t viewportHeight,
const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter);
- virtual ~FrameReorderer() {}
+ virtual ~FrameBuilder() {}
/**
* replayBakedOps() is templated based on what class will receive ops being replayed.
@@ -98,8 +98,8 @@
// Relay through layers in reverse order, since layers
// later in the list will be drawn by earlier ones
- for (int i = mLayerReorderers.size() - 1; i >= 1; i--) {
- LayerReorderer& layer = *(mLayerReorderers[i]);
+ for (int i = mLayerBuilders.size() - 1; i >= 1; i--) {
+ LayerBuilder& layer = *(mLayerBuilders[i]);
if (layer.renderNode) {
// cached HW layer - can't skip layer if empty
renderer.startRepaintLayer(layer.offscreenBuffer, layer.repaintRect);
@@ -112,14 +112,14 @@
}
}
- const LayerReorderer& fbo0 = *(mLayerReorderers[0]);
+ const LayerBuilder& fbo0 = *(mLayerBuilders[0]);
renderer.startFrame(fbo0.width, fbo0.height, fbo0.repaintRect);
fbo0.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers);
renderer.endFrame(fbo0.repaintRect);
}
void dump() const {
- for (auto&& layer : mLayerReorderers) {
+ for (auto&& layer : mLayerBuilders) {
layer->dump();
}
}
@@ -143,7 +143,7 @@
const BeginLayerOp* beginLayerOp, RenderNode* renderNode);
void restoreForLayer();
- LayerReorderer& currentLayer() { return *(mLayerReorderers[mLayerStack.back()]); }
+ LayerBuilder& currentLayer() { return *(mLayerBuilders[mLayerStack.back()]); }
BakedOpState* tryBakeOpState(const RecordedOp& recordedOp) {
return BakedOpState::tryConstruct(mAllocator, *mCanvasState.writableSnapshot(), recordedOp);
@@ -173,7 +173,7 @@
BakedOpState::StrokeBehavior strokeBehavior = BakedOpState::StrokeBehavior::StyleDefined);
/**
- * Declares all FrameReorderer::deferXXXXOp() methods for every RecordedOp type.
+ * Declares all FrameBuilder::deferXXXXOp() methods for every RecordedOp type.
*
* These private methods are called from within deferImpl to defer each individual op
* type differently.
@@ -183,17 +183,17 @@
#undef X
// List of every deferred layer's render state. Replayed in reverse order to render a frame.
- std::vector<LayerReorderer*> mLayerReorderers;
+ std::vector<LayerBuilder*> mLayerBuilders;
/*
- * Stack of indices within mLayerReorderers representing currently active layers. If drawing
+ * Stack of indices within mLayerBuilders representing currently active layers. If drawing
* layerA within a layerB, will contain, in order:
* - 0 (representing FBO 0, always present)
* - layerB's index
* - layerA's index
*
- * Note that this doesn't vector doesn't always map onto all values of mLayerReorderers. When a
- * layer is finished deferring, it will still be represented in mLayerReorderers, but it's index
+ * Note that this doesn't vector doesn't always map onto all values of mLayerBuilders. When a
+ * layer is finished deferring, it will still be represented in mLayerBuilders, but it's index
* won't be in mLayerStack. This is because it can be replayed, but can't have any more drawing
* ops added to it.
*/
diff --git a/libs/hwui/LayerReorderer.cpp b/libs/hwui/LayerBuilder.cpp
similarity index 95%
rename from libs/hwui/LayerReorderer.cpp
rename to libs/hwui/LayerBuilder.cpp
index 60f36be..7170d4f 100644
--- a/libs/hwui/LayerReorderer.cpp
+++ b/libs/hwui/LayerBuilder.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "LayerReorderer.h"
+#include "LayerBuilder.h"
#include "BakedOpState.h"
#include "RenderNode.h"
@@ -202,7 +202,7 @@
int mClipSideFlags;
};
-LayerReorderer::LayerReorderer(uint32_t width, uint32_t height,
+LayerBuilder::LayerBuilder(uint32_t width, uint32_t height,
const Rect& repaintRect, const BeginLayerOp* beginLayerOp, RenderNode* renderNode)
: width(width)
, height(height)
@@ -214,7 +214,7 @@
// iterate back toward target to see if anything drawn since should overlap the new op
// if no target, merging ops still iterate to find similar batch to insert after
-void LayerReorderer::locateInsertIndex(int batchId, const Rect& clippedBounds,
+void LayerBuilder::locateInsertIndex(int batchId, const Rect& clippedBounds,
BatchBase** targetBatch, size_t* insertBatchIndex) const {
for (int i = mBatches.size() - 1; i >= 0; i--) {
BatchBase* overBatch = mBatches[i];
@@ -237,11 +237,11 @@
}
}
-void LayerReorderer::deferLayerClear(const Rect& rect) {
+void LayerBuilder::deferLayerClear(const Rect& rect) {
mClearRects.push_back(rect);
}
-void LayerReorderer::flushLayerClears(LinearAllocator& allocator) {
+void LayerBuilder::flushLayerClears(LinearAllocator& allocator) {
if (CC_UNLIKELY(!mClearRects.empty())) {
const int vertCount = mClearRects.size() * 4;
// put the verts in the frame allocator, since
@@ -273,7 +273,7 @@
}
}
-void LayerReorderer::deferUnmergeableOp(LinearAllocator& allocator,
+void LayerBuilder::deferUnmergeableOp(LinearAllocator& allocator,
BakedOpState* op, batchid_t batchId) {
if (batchId != OpBatchType::CopyToLayer) {
// if first op after one or more unclipped saveLayers, flush the layer clears
@@ -298,7 +298,7 @@
}
}
-void LayerReorderer::deferMergeableOp(LinearAllocator& allocator,
+void LayerBuilder::deferMergeableOp(LinearAllocator& allocator,
BakedOpState* op, batchid_t batchId, mergeid_t mergeId) {
if (batchId != OpBatchType::CopyToLayer) {
// if first op after one or more unclipped saveLayers, flush the layer clears
@@ -330,7 +330,7 @@
}
}
-void LayerReorderer::replayBakedOpsImpl(void* arg,
+void LayerBuilder::replayBakedOpsImpl(void* arg,
BakedOpReceiver* unmergedReceivers, MergedOpReceiver* mergedReceivers) const {
ATRACE_NAME("flush drawing commands");
for (const BatchBase* batch : mBatches) {
@@ -353,8 +353,8 @@
}
}
-void LayerReorderer::dump() const {
- ALOGD("LayerReorderer %p, %ux%u buffer %p, blo %p, rn %p",
+void LayerBuilder::dump() const {
+ ALOGD("LayerBuilder %p, %ux%u buffer %p, blo %p, rn %p",
this, width, height, offscreenBuffer, beginLayerOp, renderNode);
for (const BatchBase* batch : mBatches) {
batch->dump();
diff --git a/libs/hwui/LayerReorderer.h b/libs/hwui/LayerBuilder.h
similarity index 90%
rename from libs/hwui/LayerReorderer.h
rename to libs/hwui/LayerBuilder.h
index 59fd4f8..99968e1 100644
--- a/libs/hwui/LayerReorderer.h
+++ b/libs/hwui/LayerBuilder.h
@@ -67,17 +67,17 @@
* Stores the deferred render operations and state used to compute ordering
* for a single FBO/layer.
*/
-class LayerReorderer {
+class LayerBuilder {
// Prevent copy/assign because users may stash pointer to offscreenBuffer and viewportClip
-PREVENT_COPY_AND_ASSIGN(LayerReorderer);
+PREVENT_COPY_AND_ASSIGN(LayerBuilder);
public:
- // Create LayerReorderer for Fbo0
- LayerReorderer(uint32_t width, uint32_t height, const Rect& repaintRect)
- : LayerReorderer(width, height, repaintRect, nullptr, nullptr) {};
+ // Create LayerBuilder for Fbo0
+ LayerBuilder(uint32_t width, uint32_t height, const Rect& repaintRect)
+ : LayerBuilder(width, height, repaintRect, nullptr, nullptr) {};
- // Create LayerReorderer for an offscreen layer, where beginLayerOp is present for a
+ // Create LayerBuilder for an offscreen layer, where beginLayerOp is present for a
// saveLayer, renderNode is present for a HW layer.
- LayerReorderer(uint32_t width, uint32_t height,
+ LayerBuilder(uint32_t width, uint32_t height,
const Rect& repaintRect, const BeginLayerOp* beginLayerOp, RenderNode* renderNode);
// iterate back toward target to see if anything drawn since should overlap the new op
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 612cdfd..8e4a3df 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -47,11 +47,11 @@
class DisplayListCanvas;
class DisplayListOp;
class OpenGLRenderer;
-class OpReorderer;
class Rect;
class SkiaShader;
#if HWUI_NEW_OPS
+class FrameBuilder;
class OffscreenBuffer;
struct RenderNodeOp;
typedef OffscreenBuffer layer_t;
@@ -87,7 +87,7 @@
*/
class RenderNode : public VirtualLightRefBase {
friend class TestUtils; // allow TestUtils to access syncDisplayList / syncProperties
-friend class FrameReorderer;
+friend class FrameBuilder;
public:
enum DirtyPropertyMask {
GENERIC = 1 << 1,
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index fff8e09..644f356 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -31,7 +31,7 @@
#include "utils/TimeUtils.h"
#if HWUI_NEW_OPS
-#include "FrameReorderer.h"
+#include "FrameBuilder.h"
#endif
#include <cutils/properties.h>
@@ -338,14 +338,13 @@
mEglManager.damageFrame(frame, dirty);
#if HWUI_NEW_OPS
- FrameReorderer reorderer(mLayerUpdateQueue, dirty, frame.width(), frame.height(),
+ FrameBuilder frameBuilder(mLayerUpdateQueue, dirty, frame.width(), frame.height(),
mRenderNodes, mLightCenter);
mLayerUpdateQueue.clear();
BakedOpRenderer renderer(Caches::getInstance(), mRenderThread.renderState(),
mOpaque, mLightInfo);
// TODO: profiler().draw(mCanvas);
- reorderer.replayBakedOps<BakedOpDispatcher>(renderer);
-
+ frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
bool drew = renderer.didDraw();
#else
diff --git a/libs/hwui/tests/microbench/FrameReordererBench.cpp b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
similarity index 90%
rename from libs/hwui/tests/microbench/FrameReordererBench.cpp
rename to libs/hwui/tests/microbench/FrameBuilderBench.cpp
index b4c9a36..67c95e2 100644
--- a/libs/hwui/tests/microbench/FrameReordererBench.cpp
+++ b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
@@ -19,7 +19,7 @@
#include "BakedOpState.h"
#include "BakedOpDispatcher.h"
#include "BakedOpRenderer.h"
-#include "FrameReorderer.h"
+#include "FrameBuilder.h"
#include "LayerUpdateQueue.h"
#include "RecordedOp.h"
#include "RecordingCanvas.h"
@@ -66,9 +66,9 @@
auto nodes = createTestNodeList();
StartBenchmarkTiming();
for (int i = 0; i < iters; i++) {
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
nodes, sLightCenter);
- MicroBench::DoNotOptimize(&reorderer);
+ MicroBench::DoNotOptimize(&frameBuilder);
}
StopBenchmarkTiming();
}
@@ -84,11 +84,11 @@
StartBenchmarkTiming();
for (int i = 0; i < iters; i++) {
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
nodes, sLightCenter);
BakedOpRenderer renderer(caches, renderState, true, lightInfo);
- reorderer.replayBakedOps<BakedOpDispatcher>(renderer);
+ frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
MicroBench::DoNotOptimize(&renderer);
}
StopBenchmarkTiming();
@@ -117,10 +117,10 @@
auto nodes = getSyncedSceneNodes(sceneName);
benchmark.StartBenchmarkTiming();
for (int i = 0; i < iters; i++) {
- FrameReorderer reorderer(sEmptyLayerUpdateQueue,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h,
nodes, sLightCenter);
- MicroBench::DoNotOptimize(&reorderer);
+ MicroBench::DoNotOptimize(&frameBuilder);
}
benchmark.StopBenchmarkTiming();
}
@@ -136,12 +136,12 @@
benchmark.StartBenchmarkTiming();
for (int i = 0; i < iters; i++) {
- FrameReorderer reorderer(sEmptyLayerUpdateQueue,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h,
nodes, sLightCenter);
BakedOpRenderer renderer(caches, renderState, true, lightInfo);
- reorderer.replayBakedOps<BakedOpDispatcher>(renderer);
+ frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
MicroBench::DoNotOptimize(&renderer);
}
benchmark.StopBenchmarkTiming();
diff --git a/libs/hwui/tests/unit/BakedOpStateTests.cpp b/libs/hwui/tests/unit/BakedOpStateTests.cpp
index b350686..0f8e047 100644
--- a/libs/hwui/tests/unit/BakedOpStateTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpStateTests.cpp
@@ -199,9 +199,12 @@
}
TEST(BakedOpState, tryShadowOpConstruct) {
+ Matrix4 translate10x20;
+ translate10x20.loadTranslate(10, 20, 0);
+
LinearAllocator allocator;
{
- auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip
+ auto snapshot = TestUtils::makeSnapshot(translate10x20, Rect()); // Note: empty clip
BakedOpState* bakedState = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
EXPECT_EQ(nullptr, bakedState) << "op should be rejected by clip, so not constructed";
@@ -209,11 +212,14 @@
"since op is quick rejected based on snapshot clip";
}
{
- auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
+ auto snapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
BakedOpState* bakedState = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
ASSERT_NE(nullptr, bakedState) << "NOT rejected by clip, so op should be constructed";
EXPECT_LE(64u, allocator.usedSize()) << "relatively large alloc for non-rejected op";
+
+ EXPECT_MATRIX_APPROX_EQ(translate10x20, bakedState->computedState.transform);
+ EXPECT_EQ(Rect(100, 200), bakedState->computedState.clippedBounds);
}
}
diff --git a/libs/hwui/tests/unit/FrameReordererTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
similarity index 90%
rename from libs/hwui/tests/unit/FrameReordererTests.cpp
rename to libs/hwui/tests/unit/FrameBuilderTests.cpp
index 9d2eb98..bded50a 100644
--- a/libs/hwui/tests/unit/FrameReordererTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -18,7 +18,7 @@
#include <BakedOpState.h>
#include <DeferredLayerUpdater.h>
-#include <FrameReorderer.h>
+#include <FrameBuilder.h>
#include <LayerUpdateQueue.h>
#include <RecordedOp.h>
#include <RecordingCanvas.h>
@@ -113,7 +113,7 @@
class FailRenderer : public TestRendererBase {};
-TEST(FrameReorderer, simple) {
+TEST(FrameBuilder, simple) {
class SimpleTestRenderer : public TestRendererBase {
public:
void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
@@ -138,14 +138,14 @@
canvas.drawRect(0, 0, 100, 200, SkPaint());
canvas.drawBitmap(bitmap, 10, 10, nullptr);
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
createSyncedNodeList(node), sLightCenter);
SimpleTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
}
-TEST(FrameReorderer, simpleStroke) {
+TEST(FrameBuilder, simpleStroke) {
class SimpleStrokeTestRenderer : public TestRendererBase {
public:
void onPointsOp(const PointsOp& op, const BakedOpState& state) override {
@@ -164,14 +164,14 @@
strokedPaint.setStrokeWidth(10);
canvas.drawPoint(50, 50, strokedPaint);
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
createSyncedNodeList(node), sLightCenter);
SimpleStrokeTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(1, renderer.getIndex());
}
-TEST(FrameReorderer, simpleRejection) {
+TEST(FrameBuilder, simpleRejection) {
auto node = TestUtils::createNode(0, 0, 200, 200,
[](RenderProperties& props, RecordingCanvas& canvas) {
canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
@@ -179,14 +179,14 @@
canvas.drawRect(0, 0, 400, 400, SkPaint());
canvas.restore();
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
createSyncedNodeList(node), sLightCenter);
FailRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
}
-TEST(FrameReorderer, simpleBatching) {
+TEST(FrameBuilder, simpleBatching) {
const int LOOPS = 5;
class SimpleBatchingTestRenderer : public TestRendererBase {
public:
@@ -214,15 +214,15 @@
canvas.restore();
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
createSyncedNodeList(node), sLightCenter);
SimpleBatchingTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(2 * LOOPS, renderer.getIndex())
<< "Expect number of ops = 2 * loop count";
}
-TEST(FrameReorderer, clippedMerging) {
+TEST(FrameBuilder, clippedMerging) {
class ClippedMergingTestRenderer : public TestRendererBase {
public:
void onMergedBitmapOps(const MergedBakedOpList& opList) override {
@@ -255,14 +255,14 @@
canvas.drawBitmap(bitmap, 40, 70, nullptr);
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
createSyncedNodeList(node), sLightCenter);
ClippedMergingTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(4, renderer.getIndex());
}
-TEST(FrameReorderer, textMerging) {
+TEST(FrameBuilder, textMerging) {
class TextMergingTestRenderer : public TestRendererBase {
public:
void onMergedTextOps(const MergedBakedOpList& opList) override {
@@ -283,14 +283,14 @@
TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
createSyncedNodeList(node), sLightCenter);
TextMergingTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
}
-TEST(FrameReorderer, textStrikethrough) {
+TEST(FrameBuilder, textStrikethrough) {
const int LOOPS = 5;
class TextStrikethroughTestRenderer : public TestRendererBase {
public:
@@ -314,15 +314,15 @@
TestUtils::drawTextToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
}
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 2000), 200, 2000,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 2000), 200, 2000,
createSyncedNodeList(node), sLightCenter);
TextStrikethroughTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(2 * LOOPS, renderer.getIndex())
<< "Expect number of ops = 2 * loop count";
}
-RENDERTHREAD_TEST(FrameReorderer, textureLayer) {
+RENDERTHREAD_TEST(FrameBuilder, textureLayer) {
class TextureLayerTestRenderer : public TestRendererBase {
public:
void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
@@ -348,14 +348,14 @@
canvas.drawLayer(layerUpdater.get());
canvas.restore();
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
createSyncedNodeList(node), sLightCenter);
TextureLayerTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(1, renderer.getIndex());
}
-TEST(FrameReorderer, renderNode) {
+TEST(FrameBuilder, renderNode) {
class RenderNodeTestRenderer : public TestRendererBase {
public:
void onRectOp(const RectOp& op, const BakedOpState& state) override {
@@ -393,13 +393,13 @@
canvas.restore();
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
createSyncedNodeList(parent), sLightCenter);
RenderNodeTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
}
-TEST(FrameReorderer, clipped) {
+TEST(FrameBuilder, clipped) {
class ClippedTestRenderer : public TestRendererBase {
public:
void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
@@ -416,14 +416,14 @@
canvas.drawBitmap(bitmap, 0, 0, nullptr);
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
200, 200, createSyncedNodeList(node), sLightCenter);
ClippedTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
}
-TEST(FrameReorderer, saveLayer_simple) {
+TEST(FrameBuilder, saveLayer_simple) {
class SaveLayerSimpleTestRenderer : public TestRendererBase {
public:
OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
@@ -459,14 +459,14 @@
canvas.drawRect(10, 10, 190, 190, SkPaint());
canvas.restore();
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
createSyncedNodeList(node), sLightCenter);
SaveLayerSimpleTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(4, renderer.getIndex());
}
-TEST(FrameReorderer, saveLayer_nested) {
+TEST(FrameBuilder, saveLayer_nested) {
/* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as:
* - startTemporaryLayer2, rect2 endLayer2
* - startTemporaryLayer1, rect1, drawLayer2, endLayer1
@@ -531,14 +531,14 @@
canvas.restore();
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(800, 800), 800, 800,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(800, 800), 800, 800,
createSyncedNodeList(node), sLightCenter);
SaveLayerNestedTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(10, renderer.getIndex());
}
-TEST(FrameReorderer, saveLayer_contentRejection) {
+TEST(FrameBuilder, saveLayer_contentRejection) {
auto node = TestUtils::createNode(0, 0, 200, 200,
[](RenderProperties& props, RecordingCanvas& canvas) {
canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
@@ -551,15 +551,15 @@
canvas.restore();
canvas.restore();
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
createSyncedNodeList(node), sLightCenter);
FailRenderer renderer;
// should see no ops, even within the layer, since the layer should be rejected
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
}
-TEST(FrameReorderer, saveLayerUnclipped_simple) {
+TEST(FrameBuilder, saveLayerUnclipped_simple) {
class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase {
public:
void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
@@ -594,14 +594,14 @@
canvas.drawRect(0, 0, 200, 200, SkPaint());
canvas.restore();
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
createSyncedNodeList(node), sLightCenter);
SaveLayerUnclippedSimpleTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(4, renderer.getIndex());
}
-TEST(FrameReorderer, saveLayerUnclipped_mergedClears) {
+TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase {
public:
void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
@@ -648,10 +648,10 @@
canvas.drawRect(0, 0, 100, 100, SkPaint());
canvas.restoreToCount(restoreTo);
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
createSyncedNodeList(node), sLightCenter);
SaveLayerUnclippedMergedClearsTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(10, renderer.getIndex())
<< "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect.";
}
@@ -660,7 +660,7 @@
* - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer
* - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe
*/
-TEST(FrameReorderer, saveLayerUnclipped_complex) {
+TEST(FrameBuilder, saveLayerUnclipped_complex) {
class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase {
public:
OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
@@ -710,14 +710,14 @@
canvas.restore();
canvas.restore();
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(600, 600), 600, 600,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(600, 600), 600, 600,
createSyncedNodeList(node), sLightCenter);
SaveLayerUnclippedComplexTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(12, renderer.getIndex());
}
-RENDERTHREAD_TEST(FrameReorderer, hwLayer_simple) {
+RENDERTHREAD_TEST(FrameBuilder, hwLayer_simple) {
class HwLayerSimpleTestRenderer : public TestRendererBase {
public:
void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
@@ -768,17 +768,17 @@
LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
- FrameReorderer reorderer(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
syncedNodeList, sLightCenter);
HwLayerSimpleTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(6, renderer.getIndex());
// clean up layer pointer, so we can safely destruct RenderNode
*layerHandle = nullptr;
}
-RENDERTHREAD_TEST(FrameReorderer, hwLayer_complex) {
+RENDERTHREAD_TEST(FrameBuilder, hwLayer_complex) {
/* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as:
* - startRepaintLayer(child), rect(grey), endLayer
* - startTemporaryLayer, drawLayer(child), endLayer
@@ -869,10 +869,10 @@
layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100));
layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
- FrameReorderer reorderer(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
syncedList, sLightCenter);
HwLayerComplexTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(13, renderer.getIndex());
// clean up layer pointers, so we can safely destruct RenderNodes
@@ -894,7 +894,7 @@
node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z);
canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
}
-TEST(FrameReorderer, zReorder) {
+TEST(FrameBuilder, zReorder) {
class ZReorderTestRenderer : public TestRendererBase {
public:
void onRectOp(const RectOp& op, const BakedOpState& state) override {
@@ -918,14 +918,14 @@
drawOrderedRect(&canvas, 8);
drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
createSyncedNodeList(parent), sLightCenter);
ZReorderTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(10, renderer.getIndex());
};
-TEST(FrameReorderer, projectionReorder) {
+TEST(FrameBuilder, projectionReorder) {
static const int scrollX = 5;
static const int scrollY = 10;
class ProjectionReorderTestRenderer : public TestRendererBase {
@@ -1001,10 +1001,10 @@
canvas.restore();
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
createSyncedNodeList(parent), sLightCenter);
ProjectionReorderTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(3, renderer.getIndex());
}
@@ -1020,7 +1020,7 @@
});
}
-TEST(FrameReorderer, shadow) {
+TEST(FrameBuilder, shadow) {
class ShadowTestRenderer : public TestRendererBase {
public:
void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
@@ -1044,14 +1044,14 @@
canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
createSyncedNodeList(parent), sLightCenter);
ShadowTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(2, renderer.getIndex());
}
-TEST(FrameReorderer, shadowSaveLayer) {
+TEST(FrameBuilder, shadowSaveLayer) {
class ShadowSaveLayerTestRenderer : public TestRendererBase {
public:
OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
@@ -1085,14 +1085,14 @@
canvas.restoreToCount(count);
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
createSyncedNodeList(parent), (Vector3) { 100, 100, 100 });
ShadowSaveLayerTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(5, renderer.getIndex());
}
-RENDERTHREAD_TEST(FrameReorderer, shadowHwLayer) {
+RENDERTHREAD_TEST(FrameBuilder, shadowHwLayer) {
class ShadowHwLayerTestRenderer : public TestRendererBase {
public:
void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
@@ -1135,17 +1135,17 @@
auto syncedList = createSyncedNodeList(parent);
LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
- FrameReorderer reorderer(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
syncedList, (Vector3) { 100, 100, 100 });
ShadowHwLayerTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(5, renderer.getIndex());
// clean up layer pointer, so we can safely destruct RenderNode
*layerHandle = nullptr;
}
-TEST(FrameReorderer, shadowLayering) {
+TEST(FrameBuilder, shadowLayering) {
class ShadowLayeringTestRenderer : public TestRendererBase {
public:
void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
@@ -1164,10 +1164,10 @@
canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
createSyncedNodeList(parent), sLightCenter);
ShadowLayeringTestRenderer renderer;
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(4, renderer.getIndex());
}
@@ -1192,14 +1192,14 @@
canvas.drawRect(0, 0, 100, 100, paint);
});
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
createSyncedNodeList(node), sLightCenter);
PropertyTestRenderer renderer(opValidateCallback);
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
}
-TEST(FrameReorderer, renderPropOverlappingRenderingAlpha) {
+TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
testProperty([](RenderProperties& properties) {
properties.setAlpha(0.5f);
properties.setHasOverlappingRendering(false);
@@ -1208,7 +1208,7 @@
});
}
-TEST(FrameReorderer, renderPropClipping) {
+TEST(FrameBuilder, renderPropClipping) {
testProperty([](RenderProperties& properties) {
properties.setClipToBounds(true);
properties.setClipBounds(Rect(10, 20, 300, 400));
@@ -1218,7 +1218,7 @@
});
}
-TEST(FrameReorderer, renderPropRevealClip) {
+TEST(FrameBuilder, renderPropRevealClip) {
testProperty([](RenderProperties& properties) {
properties.mutableRevealClip().set(true, 50, 50, 25);
}, [](const RectOp& op, const BakedOpState& state) {
@@ -1229,7 +1229,7 @@
});
}
-TEST(FrameReorderer, renderPropOutlineClip) {
+TEST(FrameBuilder, renderPropOutlineClip) {
testProperty([](RenderProperties& properties) {
properties.mutableOutline().setShouldClip(true);
properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
@@ -1241,7 +1241,7 @@
});
}
-TEST(FrameReorderer, renderPropTransform) {
+TEST(FrameBuilder, renderPropTransform) {
testProperty([](RenderProperties& properties) {
properties.setLeftTopRightBottom(10, 10, 110, 110);
@@ -1334,15 +1334,15 @@
});
auto nodes = createSyncedNodeList(node); // sync before querying height
- FrameReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, nodes, sLightCenter);
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, nodes, sLightCenter);
SaveLayerAlphaClipTestRenderer renderer(outObservedData);
- reorderer.replayBakedOps<TestDispatcher>(renderer);
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
// assert, since output won't be valid if we haven't seen a save layer triggered
ASSERT_EQ(4, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
}
-TEST(FrameReorderer, renderPropSaveLayerAlphaClipBig) {
+TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
SaveLayerAlphaData observedData;
testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
properties.setTranslationX(10); // offset rendering content
@@ -1358,7 +1358,7 @@
<< "expect content to be translated as part of being clipped";
}
-TEST(FrameReorderer, renderPropSaveLayerAlphaRotate) {
+TEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
SaveLayerAlphaData observedData;
testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
// Translate and rotate the view so that the only visible part is the top left corner of
@@ -1377,7 +1377,7 @@
EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
}
-TEST(FrameReorderer, renderPropSaveLayerAlphaScale) {
+TEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
SaveLayerAlphaData observedData;
testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
properties.setPivotX(0);
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index a092408..ea1690f 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -51,6 +51,7 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
/**
* AudioManager provides access to volume and ringer mode control.
@@ -2158,36 +2159,73 @@
}
/**
- * Handler for audio focus events coming from the audio service.
+ * Handler for events (audio focus change, recording config change) coming from the
+ * audio service.
*/
- private final FocusEventHandlerDelegate mAudioFocusEventHandlerDelegate =
- new FocusEventHandlerDelegate();
+ private final ServiceEventHandlerDelegate mServiceEventHandlerDelegate =
+ new ServiceEventHandlerDelegate();
/**
- * Helper class to handle the forwarding of audio focus events to the appropriate listener
+ * Event types
*/
- private class FocusEventHandlerDelegate {
+ private final static int MSSG_FOCUS_CHANGE = 0;
+ private final static int MSSG_RECORDING_CONFIG_CHANGE = 1;
+
+ /**
+ * Helper class to handle the forwarding of audio service events to the appropriate listener
+ */
+ private class ServiceEventHandlerDelegate {
private final Handler mHandler;
- FocusEventHandlerDelegate() {
+ ServiceEventHandlerDelegate() {
Looper looper;
if ((looper = Looper.myLooper()) == null) {
looper = Looper.getMainLooper();
}
if (looper != null) {
- // implement the event handler delegate to receive audio focus events
+ // implement the event handler delegate to receive events from audio service
mHandler = new Handler(looper) {
@Override
public void handleMessage(Message msg) {
- OnAudioFocusChangeListener listener = null;
- synchronized(mFocusListenerLock) {
- listener = findFocusListener((String)msg.obj);
- }
- if (listener != null) {
- Log.d(TAG, "AudioManager dispatching onAudioFocusChange("
- + msg.what + ") for " + msg.obj);
- listener.onAudioFocusChange(msg.what);
+ switch (msg.what) {
+ case MSSG_FOCUS_CHANGE:
+ OnAudioFocusChangeListener listener = null;
+ synchronized(mFocusListenerLock) {
+ listener = findFocusListener((String)msg.obj);
+ }
+ if (listener != null) {
+ Log.d(TAG, "AudioManager dispatching onAudioFocusChange("
+ + msg.what + ") for " + msg.obj);
+ listener.onAudioFocusChange(msg.arg1);
+ }
+ break;
+ case MSSG_RECORDING_CONFIG_CHANGE:
+ // optimizing for the case of a single callback
+ AudioRecordingCallback singleCallback = null;
+ ArrayList<AudioRecordingCallback> multipleCallbacks = null;
+ synchronized(mRecordCallbackLock) {
+ if ((mRecordCallbackList != null)
+ && (mRecordCallbackList.size() != 0)) {
+ if (mRecordCallbackList.size() == 1) {
+ singleCallback = mRecordCallbackList.get(0);
+ } else {
+ multipleCallbacks =
+ new ArrayList<AudioRecordingCallback>(
+ mRecordCallbackList);
+ }
+ }
+ }
+ if (singleCallback != null) {
+ singleCallback.onRecordConfigChanged();
+ } else if (multipleCallbacks != null) {
+ for (int i=0 ; i < multipleCallbacks.size() ; i++) {
+ multipleCallbacks.get(i).onRecordConfigChanged();
+ }
+ }
+ break;
+ default:
+ Log.e(TAG, "Unknown event " + msg.what);
}
}
};
@@ -2204,8 +2242,9 @@
private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
public void dispatchAudioFocusChange(int focusChange, String id) {
- Message m = mAudioFocusEventHandlerDelegate.getHandler().obtainMessage(focusChange, id);
- mAudioFocusEventHandlerDelegate.getHandler().sendMessage(m);
+ final Message m = mServiceEventHandlerDelegate.getHandler().obtainMessage(
+ MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/, id/*obj*/);
+ mServiceEventHandlerDelegate.getHandler().sendMessage(m);
}
};
@@ -2702,6 +2741,8 @@
}
+ //====================================================================
+ // Audio policy
/**
* @hide
* Register the given {@link AudioPolicy}.
@@ -2754,6 +2795,131 @@
}
+ //====================================================================
+ // Recording configuration
+ /**
+ * @hide
+ * candidate for public API
+ */
+ public static abstract class AudioRecordingCallback {
+ /**
+ * @hide
+ * candidate for public API
+ */
+ public void onRecordConfigChanged() {}
+ }
+
+ /**
+ * @hide
+ * candidate for public API
+ * @param non-null callback
+ */
+ public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb) {
+ if (cb == null) {
+ throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
+ }
+ synchronized(mRecordCallbackLock) {
+ // lazy initialization of the list of recording callbacks
+ if (mRecordCallbackList == null) {
+ mRecordCallbackList = new ArrayList<AudioRecordingCallback>();
+ }
+ final int oldCbCount = mRecordCallbackList.size();
+ if (!mRecordCallbackList.contains(cb)) {
+ mRecordCallbackList.add(cb);
+ final int newCbCount = mRecordCallbackList.size();
+ if ((oldCbCount == 0) && (newCbCount > 0)) {
+ // register binder for callbacks
+ final IAudioService service = getService();
+ try {
+ service.registerRecordingCallback(mRecCb);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in registerRecordingCallback", e);
+ }
+ }
+ } else {
+ Log.w(TAG, "attempt to call registerAudioRecordingCallback() on a previously"
+ + "registered callback");
+ }
+ }
+ }
+
+ /**
+ * @hide
+ * candidate for public API
+ * @param non-null callback
+ */
+ public void unregisterAudioRecordingCallback(@NonNull AudioRecordingCallback cb) {
+ if (cb == null) {
+ throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
+ }
+ synchronized(mRecordCallbackLock) {
+ if (mRecordCallbackList == null) {
+ return;
+ }
+ final int oldCbCount = mRecordCallbackList.size();
+ if (mRecordCallbackList.remove(cb)) {
+ final int newCbCount = mRecordCallbackList.size();
+ if ((oldCbCount > 0) && (newCbCount == 0)) {
+ // unregister binder for callbacks
+ final IAudioService service = getService();
+ try {
+ service.unregisterRecordingCallback(mRecCb);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in unregisterRecordingCallback", e);
+ }
+ }
+ } else {
+ Log.w(TAG, "attempt to call unregisterAudioRecordingCallback() on a callback"
+ + " already unregistered or never registered");
+ }
+ }
+ }
+
+ /**
+ * @hide
+ * candidate for public API
+ * @return a non-null array of recording configurations. An array of length 0 indicates there is
+ * no recording active when queried.
+ */
+ public @NonNull AudioRecordConfiguration[] getActiveRecordConfigurations() {
+ final IAudioService service = getService();
+ try {
+ return service.getActiveRecordConfigurations();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to retrieve active record configurations", e);
+ return null;
+ }
+ }
+
+ /**
+ * constants for the recording events, to keep in sync
+ * with frameworks/av/include/media/AudioPolicy.h
+ */
+ /** @hide */
+ public final static int RECORD_CONFIG_EVENT_START = 1;
+ /** @hide */
+ public final static int RECORD_CONFIG_EVENT_STOP = 0;
+
+ /**
+ * All operations on this list are sync'd on mRecordCallbackLock.
+ * List is lazy-initialized in {@link #registerAudioRecordingCallback(AudioRecordingCallback)}.
+ * List can be null.
+ */
+ private List<AudioRecordingCallback> mRecordCallbackList;
+ private final Object mRecordCallbackLock = new Object();
+
+ private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() {
+
+ public void dispatchRecordingConfigChange() {
+ final Message m = mServiceEventHandlerDelegate.getHandler().obtainMessage(
+ MSSG_RECORDING_CONFIG_CHANGE/*what*/);
+ mServiceEventHandlerDelegate.getHandler().sendMessage(m);
+ }
+
+ };
+
+ //=====================================================================
+
/**
* @hide
* Reload audio settings. This method is called by Settings backup
diff --git a/media/java/android/media/AudioRecordConfiguration.aidl b/media/java/android/media/AudioRecordConfiguration.aidl
new file mode 100644
index 0000000..afe912b
--- /dev/null
+++ b/media/java/android/media/AudioRecordConfiguration.aidl
@@ -0,0 +1,18 @@
+/* Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.media;
+
+parcelable AudioRecordConfiguration;
diff --git a/media/java/android/media/AudioRecordConfiguration.java b/media/java/android/media/AudioRecordConfiguration.java
new file mode 100644
index 0000000..aefe692
--- /dev/null
+++ b/media/java/android/media/AudioRecordConfiguration.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * @hide
+ * Candidate for public API, see AudioManager.getActiveRecordConfiguration()
+ *
+ */
+public class AudioRecordConfiguration implements Parcelable {
+
+ private final int mSessionId;
+
+ private final int mClientSource;
+
+ /**
+ * @hide
+ */
+ public AudioRecordConfiguration(int session, int source) {
+ mSessionId = session;
+ mClientSource = source;
+ }
+
+ /**
+ * @return one of AudioSource.MIC, AudioSource.VOICE_UPLINK,
+ * AudioSource.VOICE_DOWNLINK, AudioSource.VOICE_CALL,
+ * AudioSource.CAMCORDER, AudioSource.VOICE_RECOGNITION,
+ * AudioSource.VOICE_COMMUNICATION.
+ */
+ public int getClientAudioSource() { return mClientSource; }
+
+ /**
+ * @return the session number of the recorder.
+ */
+ public int getAudioSessionId() { return mSessionId; }
+
+
+ public static final Parcelable.Creator<AudioRecordConfiguration> CREATOR
+ = new Parcelable.Creator<AudioRecordConfiguration>() {
+ /**
+ * Rebuilds an AudioRecordConfiguration previously stored with writeToParcel().
+ * @param p Parcel object to read the AudioRecordConfiguration from
+ * @return a new AudioRecordConfiguration created from the data in the parcel
+ */
+ public AudioRecordConfiguration createFromParcel(Parcel p) {
+ return new AudioRecordConfiguration(p);
+ }
+ public AudioRecordConfiguration[] newArray(int size) {
+ return new AudioRecordConfiguration[size];
+ }
+ };
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mSessionId, mClientSource);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mSessionId);
+ dest.writeInt(mClientSource);
+ }
+
+ private AudioRecordConfiguration(Parcel in) {
+ mSessionId = in.readInt();
+ mClientSource = in.readInt();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || !(o instanceof AudioRecordConfiguration)) return false;
+
+ final AudioRecordConfiguration that = (AudioRecordConfiguration) o;
+ return ((mSessionId == that.mSessionId)
+ && (mClientSource == that.mClientSource));
+ }
+}
\ No newline at end of file
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 7bfd7ca..aa0d78d 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -227,7 +227,7 @@
}
/**
- * Handles events for the audio policy manager about dynamic audio policies
+ * Handles events from the audio policy manager about dynamic audio policies
* @see android.media.audiopolicy.AudioPolicy
*/
public interface DynamicPolicyCallback
@@ -267,6 +267,33 @@
}
}
+ /**
+ * Handles events from the audio policy manager about recording events
+ * @see android.media.AudioManager.AudioRecordingCallback
+ */
+ public interface AudioRecordingCallback
+ {
+ void onRecordingConfigurationChanged(int event, int session, int source);
+ }
+
+ private static AudioRecordingCallback sRecordingCallback;
+
+ public static void setRecordingCallback(AudioRecordingCallback cb) {
+ synchronized (AudioSystem.class) {
+ sRecordingCallback = cb;
+ native_register_recording_callback();
+ }
+ }
+
+ private static void recordingCallbackFromNative(int event, int session, int source) {
+ AudioRecordingCallback cb = null;
+ synchronized (AudioSystem.class) {
+ cb = sRecordingCallback;
+ }
+ if (cb != null) {
+ cb.onRecordingConfigurationChanged(event, session, source);
+ }
+ }
/*
* Error codes used by public APIs (AudioTrack, AudioRecord, AudioManager ...)
@@ -646,6 +673,8 @@
// declare this instance as having a dynamic policy callback handler
private static native final void native_register_dynamic_policy_callback();
+ // declare this instance as having a recording configuration update callback handler
+ private static native final void native_register_recording_callback();
// must be kept in sync with value in include/system/audio.h
public static final int AUDIO_HW_SYNC_INVALID = 0;
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index dbb7661..abe92c7 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -20,9 +20,11 @@
import android.bluetooth.BluetoothDevice;
import android.content.ComponentName;
import android.media.AudioAttributes;
+import android.media.AudioRecordConfiguration;
import android.media.AudioRoutesInfo;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioRoutesObserver;
+import android.media.IRecordingConfigDispatcher;
import android.media.IRingtonePlayer;
import android.media.IVolumeController;
import android.media.Rating;
@@ -161,4 +163,10 @@
int setFocusPropertiesForPolicy(int duckingBehavior, in IAudioPolicyCallback pcb);
void setVolumePolicy(in VolumePolicy policy);
+
+ void registerRecordingCallback(in IRecordingConfigDispatcher rcdb);
+
+ oneway void unregisterRecordingCallback(in IRecordingConfigDispatcher rcdb);
+
+ AudioRecordConfiguration[] getActiveRecordConfigurations();
}
diff --git a/media/java/android/media/IRecordingConfigDispatcher.aidl b/media/java/android/media/IRecordingConfigDispatcher.aidl
new file mode 100644
index 0000000..a5eb8b9f
--- /dev/null
+++ b/media/java/android/media/IRecordingConfigDispatcher.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * AIDL for the RecordingActivity monitor in AudioService to signal audio recording updates.
+ *
+ * {@hide}
+ */
+oneway interface IRecordingConfigDispatcher {
+
+ void dispatchRecordingConfigChange();
+
+}
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 9bcb5e3..0fba992 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -1735,8 +1735,7 @@
CodecProfileLevel[] profileLevels = mParent.profileLevels;
String mime = mParent.getMimeType();
- if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC) ||
- mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_DOLBY_AVC)) {
+ if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_AVC)) {
maxBlocks = 99;
maxBlocksPerSecond = 1485;
maxBps = 64000;
@@ -2090,8 +2089,7 @@
applyMacroBlockLimits(Short.MAX_VALUE, Short.MAX_VALUE,
maxBlocks, maxBlocksPerSecond, blockSize, blockSize,
1 /* widthAlignment */, 1 /* heightAlignment */);
- } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC) ||
- mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_DOLBY_HEVC)) {
+ } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
maxBlocks = 36864;
maxBlocksPerSecond = maxBlocks * 15;
maxBps = 128000;
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index a102e51..b2fa0ac 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -92,8 +92,6 @@
public static final String MIMETYPE_VIDEO_H263 = "video/3gpp";
public static final String MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
public static final String MIMETYPE_VIDEO_RAW = "video/raw";
- public static final String MIMETYPE_VIDEO_DOLBY_AVC = "video/dolby-avc";
- public static final String MIMETYPE_VIDEO_DOLBY_HEVC = "video/dolby-hevc";
public static final String MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
public static final String MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml
index 8e3447d..1b5911d 100644
--- a/packages/DocumentsUI/res/layout/fragment_directory.xml
+++ b/packages/DocumentsUI/res/layout/fragment_directory.xml
@@ -23,7 +23,7 @@
<ProgressBar
android:id="@+id/progressbar"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/progress_bar_height"
android:indeterminate="true"
style="@style/TrimmedHorizontalProgressBar"
android:visibility="gone"/>
diff --git a/packages/DocumentsUI/res/values/dimens.xml b/packages/DocumentsUI/res/values/dimens.xml
index 898112a..5adb165 100644
--- a/packages/DocumentsUI/res/values/dimens.xml
+++ b/packages/DocumentsUI/res/values/dimens.xml
@@ -26,6 +26,8 @@
<dimen name="list_item_thumbnail_size">40dp</dimen>
<dimen name="grid_item_icon_size">30dp</dimen>
+ <dimen name="progress_bar_height">4dp</dimen>
+
<dimen name="grid_width">152dp</dimen>
<dimen name="grid_height">176dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 443778e..7556c6b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -474,10 +474,12 @@
ViewMediatorCallback mViewMediatorCallback = new ViewMediatorCallback() {
+ @Override
public void userActivity() {
KeyguardViewMediator.this.userActivity();
}
+ @Override
public void keyguardDone(boolean strongAuth) {
if (!mKeyguardDonePending) {
KeyguardViewMediator.this.keyguardDone(true /* authenticated */);
@@ -487,6 +489,7 @@
}
}
+ @Override
public void keyguardDoneDrawing() {
mHandler.sendEmptyMessage(KEYGUARD_DONE_DRAWING);
}
@@ -1248,7 +1251,9 @@
if (DEBUG) Log.d(TAG, "received DELAYED_KEYGUARD_ACTION with seq = "
+ sequence + ", mDelayedShowingSequence = " + mDelayedShowingSequence);
synchronized (KeyguardViewMediator.this) {
- doKeyguardLocked(null);
+ if (mDelayedShowingSequence == sequence) {
+ doKeyguardLocked(null);
+ }
}
} else if (DELAYED_LOCK_PROFILE_ACTION.equals(intent.getAction())) {
int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, 0);
@@ -1698,6 +1703,7 @@
mHandler.removeMessages(KEYGUARD_DONE_PENDING_TIMEOUT);
}
+ @Override
public void onBootCompleted() {
mUpdateMonitor.dispatchBootCompleted();
synchronized (this) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 3c63aae..0901015 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -27,6 +27,7 @@
import android.app.Dialog;
import android.app.KeyguardManager;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
@@ -559,7 +560,13 @@
: R.drawable.ic_volume_expand_animation;
if (res == mExpandButtonRes) return;
mExpandButtonRes = res;
- mExpandButton.setImageResource(res);
+ if (hasTouchFeature()) {
+ mExpandButton.setImageResource(res);
+ } else {
+ // if there is no touch feature, show the volume ringer instead
+ mExpandButton.setImageResource(R.drawable.ic_volume_ringer);
+ mExpandButton.setBackgroundResource(0); // remove gray background emphasis
+ }
mExpandButton.setContentDescription(mContext.getString(mExpanded ?
R.string.accessibility_volume_collapse : R.string.accessibility_volume_expand));
}
@@ -837,6 +844,11 @@
rescheduleTimeoutH();
}
+ private boolean hasTouchFeature() {
+ final PackageManager pm = mContext.getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
+ }
+
private final VolumeDialogController.Callbacks mControllerCallbackH
= new VolumeDialogController.Callbacks() {
@Override
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b27b92d..093a33d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -35,6 +35,7 @@
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.TransferPipe;
import com.android.internal.os.Zygote;
+import com.android.internal.os.InstallerConnection.InstallerException;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
@@ -1308,7 +1309,7 @@
int mMemWatchDumpUid;
String mTrackAllocationApp = null;
- final long[] mTmpLong = new long[1];
+ final long[] mTmpLong = new long[2];
static final class ProcessChangeItem {
static final int CHANGE_ACTIVITIES = 1<<0;
@@ -2241,7 +2242,7 @@
}
int num = 0;
- long[] tmp = new long[1];
+ long[] tmp = new long[2];
do {
ProcessRecord proc;
int procState;
@@ -2273,7 +2274,7 @@
if (pss != 0 && proc.thread != null && proc.setProcState == procState
&& proc.pid == pid && proc.lastPssTime == lastPssTime) {
num++;
- recordPssSampleLocked(proc, procState, pss, tmp[0],
+ recordPssSampleLocked(proc, procState, pss, tmp[0], tmp[1],
SystemClock.uptimeMillis());
}
}
@@ -6590,8 +6591,10 @@
Process.establishZygoteConnectionForAbi(abi);
final String instructionSet = VMRuntime.getInstructionSet(abi);
if (!completedIsas.contains(instructionSet)) {
- if (mInstaller.markBootComplete(VMRuntime.getInstructionSet(abi)) != 0) {
- Slog.e(TAG, "Unable to mark boot complete for abi: " + abi);
+ try {
+ mInstaller.markBootComplete(VMRuntime.getInstructionSet(abi));
+ } catch (InstallerException e) {
+ Slog.e(TAG, "Unable to mark boot complete for abi: " + abi, e);
}
completedIsas.add(instructionSet);
}
@@ -10832,6 +10835,14 @@
* belonging to any running apps.
*/
private void installEncryptionUnawareProviders(int userId) {
+ if (!StorageManager.isFileBasedEncryptionEnabled()) {
+ // TODO: eventually pivot this back to look at current user state,
+ // similar to the comment in UserManager.isUserUnlocked(), but for
+ // now, if we started apps when "unlocked" then unaware providers
+ // have already been spun up.
+ return;
+ }
+
synchronized (this) {
final int NP = mProcessNames.getMap().size();
for (int ip = 0; ip < NP; ip++) {
@@ -12259,6 +12270,8 @@
sb.append(proc.processName);
sb.append(" in idle maint: pss=");
sb.append(proc.lastPss);
+ sb.append(", swapPss=");
+ sb.append(proc.lastSwapPss);
sb.append(", initialPss=");
sb.append(proc.initialIdlePss);
sb.append(", period=");
@@ -15166,6 +15179,7 @@
pw.print("state: cur="); pw.print(ProcessList.makeProcStateString(r.curProcState));
pw.print(" set="); pw.print(ProcessList.makeProcStateString(r.setProcState));
pw.print(" lastPss="); DebugUtils.printSizeValue(pw, r.lastPss*1024);
+ pw.print(" lastSwapPss="); DebugUtils.printSizeValue(pw, r.lastSwapPss*1024);
pw.print(" lastCachedPss="); DebugUtils.printSizeValue(pw, r.lastCachedPss*1024);
pw.println();
pw.print(prefix);
@@ -15319,32 +15333,35 @@
final String label;
final String shortLabel;
final long pss;
+ final long swapPss;
final int id;
final boolean hasActivities;
ArrayList<MemItem> subitems;
- public MemItem(String _label, String _shortLabel, long _pss, int _id,
+ public MemItem(String _label, String _shortLabel, long _pss, long _swapPss, int _id,
boolean _hasActivities) {
isProc = true;
label = _label;
shortLabel = _shortLabel;
pss = _pss;
+ swapPss = _swapPss;
id = _id;
hasActivities = _hasActivities;
}
- public MemItem(String _label, String _shortLabel, long _pss, int _id) {
+ public MemItem(String _label, String _shortLabel, long _pss, long _swapPss, int _id) {
isProc = false;
label = _label;
shortLabel = _shortLabel;
pss = _pss;
+ swapPss = _swapPss;
id = _id;
hasActivities = false;
}
}
static final void dumpMemItems(PrintWriter pw, String prefix, String tag,
- ArrayList<MemItem> items, boolean sort, boolean isCompact) {
+ ArrayList<MemItem> items, boolean sort, boolean isCompact, boolean dumpSwapPss) {
if (sort && !isCompact) {
Collections.sort(items, new Comparator<MemItem>() {
@Override
@@ -15362,18 +15379,24 @@
for (int i=0; i<items.size(); i++) {
MemItem mi = items.get(i);
if (!isCompact) {
- pw.printf("%s%s: %s\n", prefix, stringifyKBSize(mi.pss), mi.label);
+ if (dumpSwapPss) {
+ pw.printf("%s%s: %-60s (%s in swap)\n", prefix, stringifyKBSize(mi.pss),
+ mi.label, stringifyKBSize(mi.swapPss));
+ } else {
+ pw.printf("%s%s: %s\n", prefix, stringifyKBSize(mi.pss), mi.label);
+ }
} else if (mi.isProc) {
pw.print("proc,"); pw.print(tag); pw.print(","); pw.print(mi.shortLabel);
- pw.print(","); pw.print(mi.id); pw.print(","); pw.print(mi.pss);
+ pw.print(","); pw.print(mi.id); pw.print(","); pw.print(mi.pss); pw.print(",");
+ pw.print(dumpSwapPss ? mi.swapPss : "N/A");
pw.println(mi.hasActivities ? ",a" : ",e");
} else {
pw.print(tag); pw.print(","); pw.print(mi.shortLabel); pw.print(",");
- pw.println(mi.pss);
+ pw.println(mi.pss); pw.print(dumpSwapPss ? mi.swapPss : "N/A");
}
if (mi.subitems != null) {
- dumpMemItems(pw, prefix + " ", mi.shortLabel, mi.subitems,
- true, isCompact);
+ dumpMemItems(pw, prefix + " ", mi.shortLabel, mi.subitems,
+ true, isCompact, dumpSwapPss);
}
}
}
@@ -15502,6 +15525,8 @@
boolean isCompact = false;
boolean localOnly = false;
boolean packages = false;
+ boolean isCheckinRequest = false;
+ boolean dumpSwapPss = false;
int opti = 0;
while (opti < args.length) {
@@ -15514,6 +15539,7 @@
dumpDetails = true;
dumpFullDetails = true;
dumpDalvik = true;
+ dumpSwapPss = true;
} else if ("-d".equals(opt)) {
dumpDalvik = true;
} else if ("-c".equals(opt)) {
@@ -15521,22 +15547,29 @@
} else if ("-s".equals(opt)) {
dumpDetails = true;
dumpSummaryOnly = true;
+ } else if ("-S".equals(opt)) {
+ dumpSwapPss = true;
} else if ("--oom".equals(opt)) {
oomOnly = true;
} else if ("--local".equals(opt)) {
localOnly = true;
} else if ("--package".equals(opt)) {
packages = true;
+ } else if ("--checkin".equals(opt)) {
+ isCheckinRequest = true;
+
} else if ("-h".equals(opt)) {
pw.println("meminfo dump options: [-a] [-d] [-c] [-s] [--oom] [process]");
pw.println(" -a: include all available information for each process.");
pw.println(" -d: include dalvik details.");
pw.println(" -c: dump in a compact machine-parseable representation.");
pw.println(" -s: dump only summary of application memory usage.");
+ pw.println(" -S: dump also SwapPss.");
pw.println(" --oom: only show processes organized by oom adj.");
pw.println(" --local: only collect details locally, don't call process.");
pw.println(" --package: interpret process arg as package, dumping all");
pw.println(" processes that have loaded that package.");
+ pw.println(" --checkin: dump data for a checkin");
pw.println("If [process] is specified it can be the name or ");
pw.println("pid of a specific process to dump.");
return;
@@ -15545,7 +15578,6 @@
}
}
- final boolean isCheckinRequest = scanArgs(args, "--checkin");
long uptime = SystemClock.uptimeMillis();
long realtime = SystemClock.elapsedRealtime();
final long[] tmpLong = new long[1];
@@ -15617,18 +15649,28 @@
ArrayList<MemItem> procMems = new ArrayList<MemItem>();
final SparseArray<MemItem> procMemsMap = new SparseArray<MemItem>();
long nativePss = 0;
+ long nativeSwapPss = 0;
long dalvikPss = 0;
+ long dalvikSwapPss = 0;
long[] dalvikSubitemPss = dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] :
EmptyArray.LONG;
+ long[] dalvikSubitemSwapPss = dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] :
+ EmptyArray.LONG;
long otherPss = 0;
+ long otherSwapPss = 0;
long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
+ long[] miscSwapPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
long oomPss[] = new long[DUMP_MEM_OOM_LABEL.length];
+ long oomSwapPss[] = new long[DUMP_MEM_OOM_LABEL.length];
ArrayList<MemItem>[] oomProcs = (ArrayList<MemItem>[])
new ArrayList[DUMP_MEM_OOM_LABEL.length];
long totalPss = 0;
+ long totalSwapPss = 0;
long cachedPss = 0;
+ long cachedSwapPss = 0;
+ boolean hasSwapPss = false;
Debug.MemoryInfo mi = null;
for (int i = procs.size() - 1 ; i >= 0 ; i--) {
@@ -15652,6 +15694,7 @@
}
if (dumpDetails || (!brief && !oomOnly)) {
Debug.getMemoryInfo(pid, mi);
+ hasSwapPss = mi.hasSwappedOutPss;
} else {
mi.dalvikPss = (int)Debug.getPss(pid, tmpLong, null);
mi.dalvikPrivateDirty = (int)tmpLong[0];
@@ -15679,6 +15722,7 @@
final long myTotalPss = mi.getTotalPss();
final long myTotalUss = mi.getTotalUss();
+ final long myTotalSwapPss = mi.getTotalSwappedOutPss();
synchronized (this) {
if (r.thread != null && oomAdj == r.getSetAdjWithServices()) {
@@ -15689,32 +15733,43 @@
if (!isCheckinRequest && mi != null) {
totalPss += myTotalPss;
+ totalSwapPss += myTotalSwapPss;
MemItem pssItem = new MemItem(r.processName + " (pid " + pid +
- (hasActivities ? " / activities)" : ")"),
- r.processName, myTotalPss, pid, hasActivities);
+ (hasActivities ? " / activities)" : ")"), r.processName, myTotalPss,
+ myTotalSwapPss, pid, hasActivities);
procMems.add(pssItem);
procMemsMap.put(pid, pssItem);
nativePss += mi.nativePss;
+ nativeSwapPss += mi.nativeSwappedOutPss;
dalvikPss += mi.dalvikPss;
+ dalvikSwapPss += mi.dalvikSwappedOutPss;
for (int j=0; j<dalvikSubitemPss.length; j++) {
dalvikSubitemPss[j] += mi.getOtherPss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
+ dalvikSubitemSwapPss[j] +=
+ mi.getOtherSwappedOutPss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
}
otherPss += mi.otherPss;
+ otherSwapPss += mi.otherSwappedOutPss;
for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
long mem = mi.getOtherPss(j);
miscPss[j] += mem;
otherPss -= mem;
+ mem = mi.getOtherSwappedOutPss(j);
+ miscSwapPss[j] += mem;
+ otherSwapPss -= mem;
}
if (oomAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
cachedPss += myTotalPss;
+ cachedSwapPss += myTotalSwapPss;
}
for (int oomIndex=0; oomIndex<oomPss.length; oomIndex++) {
if (oomAdj <= DUMP_MEM_OOM_ADJ[oomIndex]
|| oomIndex == (oomPss.length-1)) {
oomPss[oomIndex] += myTotalPss;
+ oomSwapPss[oomIndex] += myTotalSwapPss;
if (oomProcs[oomIndex] == null) {
oomProcs[oomIndex] = new ArrayList<MemItem>();
}
@@ -15749,26 +15804,35 @@
}
final long myTotalPss = mi.getTotalPss();
+ final long myTotalSwapPss = mi.getTotalSwappedOutPss();
totalPss += myTotalPss;
nativeProcTotalPss += myTotalPss;
MemItem pssItem = new MemItem(st.name + " (pid " + st.pid + ")",
- st.name, myTotalPss, st.pid, false);
+ st.name, myTotalPss, mi.getSummaryTotalSwapPss(), st.pid, false);
procMems.add(pssItem);
nativePss += mi.nativePss;
+ nativeSwapPss += mi.nativeSwappedOutPss;
dalvikPss += mi.dalvikPss;
+ dalvikSwapPss += mi.dalvikSwappedOutPss;
for (int j=0; j<dalvikSubitemPss.length; j++) {
- dalvikSubitemPss[j] += mi.getOtherPss(
- Debug.MemoryInfo.NUM_OTHER_STATS + j);
+ dalvikSubitemPss[j] += mi.getOtherPss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
+ dalvikSubitemSwapPss[j] +=
+ mi.getOtherSwappedOutPss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
}
otherPss += mi.otherPss;
+ otherSwapPss += mi.otherSwappedOutPss;
for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
long mem = mi.getOtherPss(j);
miscPss[j] += mem;
otherPss -= mem;
+ mem = mi.getOtherSwappedOutPss(j);
+ miscSwapPss[j] += mem;
+ otherSwapPss -= mem;
}
oomPss[0] += myTotalPss;
+ oomSwapPss[0] += myTotalSwapPss;
if (oomProcs[0] == null) {
oomProcs[0] = new ArrayList<MemItem>();
}
@@ -15779,21 +15843,23 @@
ArrayList<MemItem> catMems = new ArrayList<MemItem>();
- catMems.add(new MemItem("Native", "Native", nativePss, -1));
- final MemItem dalvikItem = new MemItem("Dalvik", "Dalvik", dalvikPss, -2);
+ catMems.add(new MemItem("Native", "Native", nativePss, nativeSwapPss, -1));
+ final MemItem dalvikItem =
+ new MemItem("Dalvik", "Dalvik", dalvikPss, dalvikSwapPss, -2);
if (dalvikSubitemPss.length > 0) {
dalvikItem.subitems = new ArrayList<MemItem>();
for (int j=0; j<dalvikSubitemPss.length; j++) {
final String name = Debug.MemoryInfo.getOtherLabel(
Debug.MemoryInfo.NUM_OTHER_STATS + j);
- dalvikItem.subitems.add(new MemItem(name, name, dalvikSubitemPss[j], j));
+ dalvikItem.subitems.add(new MemItem(name, name, dalvikSubitemPss[j],
+ dalvikSubitemSwapPss[j], j));
}
}
catMems.add(dalvikItem);
- catMems.add(new MemItem("Unknown", "Unknown", otherPss, -3));
+ catMems.add(new MemItem("Unknown", "Unknown", otherPss, otherSwapPss, -3));
for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
String label = Debug.MemoryInfo.getOtherLabel(j);
- catMems.add(new MemItem(label, label, miscPss[j], j));
+ catMems.add(new MemItem(label, label, miscPss[j], miscSwapPss[j], j));
}
ArrayList<MemItem> oomMems = new ArrayList<MemItem>();
@@ -15801,30 +15867,31 @@
if (oomPss[j] != 0) {
String label = isCompact ? DUMP_MEM_OOM_COMPACT_LABEL[j]
: DUMP_MEM_OOM_LABEL[j];
- MemItem item = new MemItem(label, label, oomPss[j],
+ MemItem item = new MemItem(label, label, oomPss[j], oomSwapPss[j],
DUMP_MEM_OOM_ADJ[j]);
item.subitems = oomProcs[j];
oomMems.add(item);
}
}
+ dumpSwapPss = dumpSwapPss && hasSwapPss && totalSwapPss != 0;
if (!brief && !oomOnly && !isCompact) {
pw.println();
pw.println("Total PSS by process:");
- dumpMemItems(pw, " ", "proc", procMems, true, isCompact);
+ dumpMemItems(pw, " ", "proc", procMems, true, isCompact, dumpSwapPss);
pw.println();
}
if (!isCompact) {
pw.println("Total PSS by OOM adjustment:");
}
- dumpMemItems(pw, " ", "oom", oomMems, false, isCompact);
+ dumpMemItems(pw, " ", "oom", oomMems, false, isCompact, dumpSwapPss);
if (!brief && !oomOnly) {
PrintWriter out = categoryPw != null ? categoryPw : pw;
if (!isCompact) {
out.println();
out.println("Total PSS by category:");
}
- dumpMemItems(out, " ", "cat", catMems, true, isCompact);
+ dumpMemItems(out, " ", "cat", catMems, true, isCompact, dumpSwapPss);
}
if (!isCompact) {
pw.println();
@@ -19147,8 +19214,10 @@
/**
* Record new PSS sample for a process.
*/
- void recordPssSampleLocked(ProcessRecord proc, int procState, long pss, long uss, long now) {
- EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss * 1024, uss * 1024);
+ void recordPssSampleLocked(ProcessRecord proc, int procState, long pss, long uss, long swapPss,
+ long now) {
+ EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss * 1024, uss * 1024,
+ swapPss * 1024);
proc.lastPssTime = now;
proc.baseProcessTracker.addPss(pss, uss, true, proc.pkgList);
if (DEBUG_PSS) Slog.d(TAG_PSS,
@@ -19158,8 +19227,10 @@
proc.initialIdlePss = pss;
}
proc.lastPss = pss;
+ proc.lastSwapPss = swapPss;
if (procState >= ActivityManager.PROCESS_STATE_HOME) {
proc.lastCachedPss = pss;
+ proc.lastCachedSwapPss = swapPss;
}
final SparseArray<Pair<Long, String>> watchUids
@@ -19595,7 +19666,7 @@
// states, which well tend to give noisy data.
long start = SystemClock.uptimeMillis();
long pss = Debug.getPss(app.pid, mTmpLong, null);
- recordPssSampleLocked(app, app.curProcState, pss, mTmpLong[0], now);
+ recordPssSampleLocked(app, app.curProcState, pss, mTmpLong[0], mTmpLong[1], now);
mPendingPssProcesses.remove(app);
Slog.i(TAG, "Recorded pss for " + app + " state " + app.setProcState
+ " to " + app.curProcState + ": "
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index 0397553..f2e8d09 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -100,6 +100,6 @@
30045 am_pre_boot (User|1|5),(Package|3)
# Report collection of global memory state
-30046 am_meminfo (CachedKb|2|2),(FreeKb|2|2),(ZramKb|2|2),(KernelKb|2|2),(NativeKb|2|2)
+30046 am_meminfo (Cached|2|2),(Free|2|2),(Zram|2|2),(Kernel|2|2),(Native|2|2)
# Report collection of memory used by a process
-30047 am_pss (Pid|1|5),(UID|1|5),(Process Name|3),(PssKb|2|2),(UssKb|2|2)
+30047 am_pss (Pid|1|5),(UID|1|5),(Process Name|3),(Pss|2|2),(Uss|2|2),(SwapPss|2|2)
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 4bfe300..b4aa4cf 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -82,7 +82,9 @@
long lastStateTime; // Last time setProcState changed
long initialIdlePss; // Initial memory pss of process for idle maintenance.
long lastPss; // Last computed memory pss.
+ long lastSwapPss; // Last computed SwapPss.
long lastCachedPss; // Last computed pss when in cached state.
+ long lastCachedSwapPss; // Last computed SwapPss when in cached state.
int maxAdj; // Maximum OOM adjustment for this process
int curRawAdj; // Current OOM unlimited adjustment for this process
int setRawAdj; // Last set OOM unlimited adjustment for this process
@@ -257,7 +259,9 @@
pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
pw.print(" lruSeq="); pw.print(lruSeq);
pw.print(" lastPss="); DebugUtils.printSizeValue(pw, lastPss*1024);
+ pw.print(" lastSwapPss="); DebugUtils.printSizeValue(pw, lastSwapPss*1024);
pw.print(" lastCachedPss="); DebugUtils.printSizeValue(pw, lastCachedPss*1024);
+ pw.print(" lastCachedSwapPss="); DebugUtils.printSizeValue(pw, lastCachedSwapPss*1024);
pw.println();
pw.print(prefix); pw.print("cached="); pw.print(cached);
pw.print(" empty="); pw.println(empty);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index b8cbecb..9331dd8 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -58,10 +58,12 @@
import android.media.AudioManager;
import android.media.AudioManagerInternal;
import android.media.AudioPort;
+import android.media.AudioRecordConfiguration;
import android.media.AudioRoutesInfo;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioRoutesObserver;
import android.media.IAudioService;
+import android.media.IRecordingConfigDispatcher;
import android.media.IRingtonePlayer;
import android.media.IVolumeController;
import android.media.MediaPlayer;
@@ -706,6 +708,8 @@
LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
mUserManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
+
+ mRecordMonitor.initMonitor();
}
public void systemReady() {
@@ -6165,7 +6169,7 @@
}
//======================
- // Audio policy callback from AudioSystem
+ // Audio policy callbacks from AudioSystem for dynamic policies
//======================
private final AudioSystem.DynamicPolicyCallback mDynPolicyCallback =
new AudioSystem.DynamicPolicyCallback() {
@@ -6194,7 +6198,23 @@
}
}
}
+ }
+ //======================
+ // Audio policy callbacks from AudioSystem for recording configuration updates
+ //======================
+ private final RecordingActivityMonitor mRecordMonitor = new RecordingActivityMonitor();
+
+ public void registerRecordingCallback(IRecordingConfigDispatcher rcdb) {
+ mRecordMonitor.registerRecordingCallback(rcdb);
+ }
+
+ public void unregisterRecordingCallback(IRecordingConfigDispatcher rcdb) {
+ mRecordMonitor.unregisterRecordingCallback(rcdb);
+ }
+
+ public AudioRecordConfiguration[] getActiveRecordConfigurations() {
+ return mRecordMonitor.getActiveRecordConfigurations();
}
//======================
diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
new file mode 100644
index 0000000..5806f3f
--- /dev/null
+++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.audio;
+
+import android.media.AudioManager;
+import android.media.AudioRecordConfiguration;
+import android.media.AudioSystem;
+import android.media.IRecordingConfigDispatcher;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * Class to receive and dispatch updates from AudioSystem about recording configurations.
+ */
+public final class RecordingActivityMonitor implements AudioSystem.AudioRecordingCallback {
+
+ public final static String TAG = "AudioService.RecordingActivityMonitor";
+
+ private ArrayList<RecMonitorClient> mClients = new ArrayList<RecMonitorClient>();
+
+ private HashMap<Integer, AudioRecordConfiguration> mRecordConfigs =
+ new HashMap<Integer, AudioRecordConfiguration>();
+
+ RecordingActivityMonitor() {
+ RecMonitorClient.sMonitor = this;
+ }
+
+ /**
+ * Implementation of android.media.AudioSystem.AudioRecordingCallback
+ */
+ public void onRecordingConfigurationChanged(int event, int session, int source) {
+ if (updateSnapshot(event, session, source)) {
+ final Iterator<RecMonitorClient> clientIterator = mClients.iterator();
+ synchronized(mClients) {
+ while (clientIterator.hasNext()) {
+ try {
+ clientIterator.next().mDispatcherCb.dispatchRecordingConfigChange();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not call dispatchRecordingConfigChange() on client", e);
+ }
+ }
+ }
+ }
+ }
+
+ void initMonitor() {
+ AudioSystem.setRecordingCallback(this);
+ }
+
+ void registerRecordingCallback(IRecordingConfigDispatcher rcdb) {
+ if (rcdb == null) {
+ return;
+ }
+ synchronized(mClients) {
+ final RecMonitorClient rmc = new RecMonitorClient(rcdb);
+ if (rmc.init()) {
+ mClients.add(rmc);
+ }
+ }
+ }
+
+ void unregisterRecordingCallback(IRecordingConfigDispatcher rcdb) {
+ if (rcdb == null) {
+ return;
+ }
+ synchronized(mClients) {
+ final Iterator<RecMonitorClient> clientIterator = mClients.iterator();
+ while (clientIterator.hasNext()) {
+ RecMonitorClient rmc = clientIterator.next();
+ if (rcdb.equals(rmc.mDispatcherCb)) {
+ rmc.release();
+ clientIterator.remove();
+ break;
+ }
+ }
+ }
+ }
+
+ AudioRecordConfiguration[] getActiveRecordConfigurations() {
+ synchronized(mRecordConfigs) {
+ return mRecordConfigs.values().toArray(new AudioRecordConfiguration[0]);
+ }
+ }
+
+ /**
+ * Update the internal "view" of the active recording sessions
+ * @param event
+ * @param session
+ * @param source
+ * @return true if the list of active recording sessions has been modified, false otherwise.
+ */
+ private boolean updateSnapshot(int event, int session, int source) {
+ synchronized(mRecordConfigs) {
+ switch (event) {
+ case AudioManager.RECORD_CONFIG_EVENT_STOP:
+ // return failure if an unknown recording session stopped
+ return (mRecordConfigs.remove(new Integer(session)) != null);
+ case AudioManager.RECORD_CONFIG_EVENT_START:
+ if (mRecordConfigs.containsKey(new Integer(session))) {
+ // start of session that's already tracked, not worth an update
+ // TO DO in the future when tracking record format: there might be a record
+ // format change during a recording that requires reporting
+ return false;
+ } else {
+ mRecordConfigs.put(new Integer(session),
+ new AudioRecordConfiguration(session, source));
+ return true;
+ }
+ default:
+ Log.e(TAG, String.format("Unknown event %d for session %d, source %d",
+ event, session, source));
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Inner class to track clients that want to be notified of recording updates
+ */
+ private final static class RecMonitorClient implements IBinder.DeathRecipient {
+
+ // can afford to be static because only one RecordingActivityMonitor ever instantiated
+ static RecordingActivityMonitor sMonitor;
+
+ final IRecordingConfigDispatcher mDispatcherCb;
+
+ RecMonitorClient(IRecordingConfigDispatcher rcdb) {
+ mDispatcherCb = rcdb;
+ }
+
+ public void binderDied() {
+ Log.w(TAG, "client died");
+ sMonitor.unregisterRecordingCallback(mDispatcherCb);
+ }
+
+ boolean init() {
+ try {
+ mDispatcherCb.asBinder().linkToDeath(this, 0);
+ return true;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not link to client death", e);
+ return false;
+ }
+ }
+
+ void release() {
+ mDispatcherCb.asBinder().unlinkToDeath(this, 0);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 99a051a..190eca6 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -20,14 +20,14 @@
import android.content.Context;
import android.content.pm.PackageStats;
import android.os.Build;
-import android.text.TextUtils;
import android.util.Slog;
-import dalvik.system.VMRuntime;
-
import com.android.internal.os.InstallerConnection;
+import com.android.internal.os.InstallerConnection.InstallerException;
import com.android.server.SystemService;
+import dalvik.system.VMRuntime;
+
public final class Installer extends SystemService {
private static final String TAG = "Installer";
@@ -46,6 +46,11 @@
/** Run the application with the JIT compiler */
public static final int DEXOPT_USEJIT = 1 << 5;
+ public static final int FLAG_DE_STORAGE = 1 << 0;
+ public static final int FLAG_CE_STORAGE = 1 << 1;
+ public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 2;
+ public static final int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 3;
+
private final InstallerConnection mInstaller;
public Installer(Context context) {
@@ -67,423 +72,137 @@
mInstaller.waitForConnection();
}
- private static String escapeNull(String arg) {
- if (TextUtils.isEmpty(arg)) {
- return "!";
- } else {
- if (arg.indexOf('\0') != -1 || arg.indexOf(' ') != -1) {
- throw new IllegalArgumentException(arg);
- }
- return arg;
- }
+ public void createAppData(String uuid, String pkgname, int userid, int flags, int appid,
+ String seinfo) throws InstallerException {
+ mInstaller.execute("create_app_data", uuid, pkgname, userid, flags, appid, seinfo);
}
- @Deprecated
- public int install(String name, int uid, int gid, String seinfo) {
- return install(null, name, uid, gid, seinfo);
+ public void restoreconAppData(String uuid, String pkgname, int userid, int flags, int appid,
+ String seinfo) throws InstallerException {
+ mInstaller.execute("restorecon_app_data", uuid, pkgname, userid, flags, appid,
+ seinfo);
}
- public int install(String uuid, String name, int uid, int gid, String seinfo) {
- StringBuilder builder = new StringBuilder("install");
- builder.append(' ');
- builder.append(escapeNull(uuid));
- builder.append(' ');
- builder.append(name);
- builder.append(' ');
- builder.append(uid);
- builder.append(' ');
- builder.append(gid);
- builder.append(' ');
- builder.append(seinfo != null ? seinfo : "!");
- return mInstaller.execute(builder.toString());
+ public void clearAppData(String uuid, String pkgname, int userid, int flags)
+ throws InstallerException {
+ mInstaller.execute("clear_app_data", uuid, pkgname, userid, flags);
}
- public int dexopt(String apkPath, int uid, String instructionSet,
- int dexoptNeeded, int dexFlags) {
- if (!isValidInstructionSet(instructionSet)) {
- Slog.e(TAG, "Invalid instruction set: " + instructionSet);
- return -1;
- }
-
- return mInstaller.dexopt(apkPath, uid, instructionSet, dexoptNeeded, dexFlags);
+ public void destroyAppData(String uuid, String pkgname, int userid, int flags)
+ throws InstallerException {
+ mInstaller.execute("destroy_app_data", uuid, pkgname, userid, flags);
}
- public int dexopt(String apkPath, int uid, String pkgName, String instructionSet,
- int dexoptNeeded, @Nullable String outputPath, int dexFlags) {
- if (!isValidInstructionSet(instructionSet)) {
- Slog.e(TAG, "Invalid instruction set: " + instructionSet);
- return -1;
- }
- return mInstaller.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded,
- outputPath, dexFlags);
+ public void moveCompleteApp(String from_uuid, String to_uuid, String package_name,
+ String data_app_name, int appid, String seinfo) throws InstallerException {
+ mInstaller.execute("move_complete_app", from_uuid, to_uuid, package_name,
+ data_app_name, appid, seinfo);
}
- public int idmap(String targetApkPath, String overlayApkPath, int uid) {
- StringBuilder builder = new StringBuilder("idmap");
- builder.append(' ');
- builder.append(targetApkPath);
- builder.append(' ');
- builder.append(overlayApkPath);
- builder.append(' ');
- builder.append(uid);
- return mInstaller.execute(builder.toString());
- }
-
- public int movedex(String srcPath, String dstPath, String instructionSet) {
- if (!isValidInstructionSet(instructionSet)) {
- Slog.e(TAG, "Invalid instruction set: " + instructionSet);
- return -1;
- }
-
- StringBuilder builder = new StringBuilder("movedex");
- builder.append(' ');
- builder.append(srcPath);
- builder.append(' ');
- builder.append(dstPath);
- builder.append(' ');
- builder.append(instructionSet);
- return mInstaller.execute(builder.toString());
- }
-
- public int rmdex(String codePath, String instructionSet) {
- if (!isValidInstructionSet(instructionSet)) {
- Slog.e(TAG, "Invalid instruction set: " + instructionSet);
- return -1;
- }
-
- StringBuilder builder = new StringBuilder("rmdex");
- builder.append(' ');
- builder.append(codePath);
- builder.append(' ');
- builder.append(instructionSet);
- return mInstaller.execute(builder.toString());
- }
-
- /**
- * Removes packageDir or its subdirectory
- */
- public int rmPackageDir(String packageDir) {
- StringBuilder builder = new StringBuilder("rmpackagedir");
- builder.append(' ');
- builder.append(packageDir);
- return mInstaller.execute(builder.toString());
- }
-
- @Deprecated
- public int remove(String name, int userId) {
- return remove(null, name, userId);
- }
-
- public int remove(String uuid, String name, int userId) {
- StringBuilder builder = new StringBuilder("remove");
- builder.append(' ');
- builder.append(escapeNull(uuid));
- builder.append(' ');
- builder.append(name);
- builder.append(' ');
- builder.append(userId);
- return mInstaller.execute(builder.toString());
- }
-
- @Deprecated
- public int fixUid(String name, int uid, int gid) {
- return fixUid(null, name, uid, gid);
- }
-
- public int fixUid(String uuid, String name, int uid, int gid) {
- StringBuilder builder = new StringBuilder("fixuid");
- builder.append(' ');
- builder.append(escapeNull(uuid));
- builder.append(' ');
- builder.append(name);
- builder.append(' ');
- builder.append(uid);
- builder.append(' ');
- builder.append(gid);
- return mInstaller.execute(builder.toString());
- }
-
- @Deprecated
- public int deleteCacheFiles(String name, int userId) {
- return deleteCacheFiles(null, name, userId);
- }
-
- public int deleteCacheFiles(String uuid, String name, int userId) {
- StringBuilder builder = new StringBuilder("rmcache");
- builder.append(' ');
- builder.append(escapeNull(uuid));
- builder.append(' ');
- builder.append(name);
- builder.append(' ');
- builder.append(userId);
- return mInstaller.execute(builder.toString());
- }
-
- @Deprecated
- public int deleteCodeCacheFiles(String name, int userId) {
- return deleteCodeCacheFiles(null, name, userId);
- }
-
- public int deleteCodeCacheFiles(String uuid, String name, int userId) {
- StringBuilder builder = new StringBuilder("rmcodecache");
- builder.append(' ');
- builder.append(escapeNull(uuid));
- builder.append(' ');
- builder.append(name);
- builder.append(' ');
- builder.append(userId);
- return mInstaller.execute(builder.toString());
- }
-
- @Deprecated
- public int createUserData(String name, int uid, int userId, String seinfo) {
- return createUserData(null, name, uid, userId, seinfo);
- }
-
- public int createUserData(String uuid, String name, int uid, int userId, String seinfo) {
- StringBuilder builder = new StringBuilder("mkuserdata");
- builder.append(' ');
- builder.append(escapeNull(uuid));
- builder.append(' ');
- builder.append(name);
- builder.append(' ');
- builder.append(uid);
- builder.append(' ');
- builder.append(userId);
- builder.append(' ');
- builder.append(seinfo != null ? seinfo : "!");
- return mInstaller.execute(builder.toString());
- }
-
- public int createUserConfig(int userId) {
- StringBuilder builder = new StringBuilder("mkuserconfig");
- builder.append(' ');
- builder.append(userId);
- return mInstaller.execute(builder.toString());
- }
-
- @Deprecated
- public int removeUserDataDirs(int userId) {
- return removeUserDataDirs(null, userId);
- }
-
- public int removeUserDataDirs(String uuid, int userId) {
- StringBuilder builder = new StringBuilder("rmuser");
- builder.append(' ');
- builder.append(escapeNull(uuid));
- builder.append(' ');
- builder.append(userId);
- return mInstaller.execute(builder.toString());
- }
-
- public int copyCompleteApp(String fromUuid, String toUuid, String packageName,
- String dataAppName, int appId, String seinfo) {
- StringBuilder builder = new StringBuilder("cpcompleteapp");
- builder.append(' ');
- builder.append(escapeNull(fromUuid));
- builder.append(' ');
- builder.append(escapeNull(toUuid));
- builder.append(' ');
- builder.append(packageName);
- builder.append(' ');
- builder.append(dataAppName);
- builder.append(' ');
- builder.append(appId);
- builder.append(' ');
- builder.append(seinfo);
- return mInstaller.execute(builder.toString());
- }
-
- @Deprecated
- public int clearUserData(String name, int userId) {
- return clearUserData(null, name, userId);
- }
-
- public int clearUserData(String uuid, String name, int userId) {
- StringBuilder builder = new StringBuilder("rmuserdata");
- builder.append(' ');
- builder.append(escapeNull(uuid));
- builder.append(' ');
- builder.append(name);
- builder.append(' ');
- builder.append(userId);
- return mInstaller.execute(builder.toString());
- }
-
- public int markBootComplete(String instructionSet) {
- if (!isValidInstructionSet(instructionSet)) {
- Slog.e(TAG, "Invalid instruction set: " + instructionSet);
- return -1;
- }
-
- StringBuilder builder = new StringBuilder("markbootcomplete");
- builder.append(' ');
- builder.append(instructionSet);
- return mInstaller.execute(builder.toString());
- }
-
- @Deprecated
- public int freeCache(long freeStorageSize) {
- return freeCache(null, freeStorageSize);
- }
-
- public int freeCache(String uuid, long freeStorageSize) {
- StringBuilder builder = new StringBuilder("freecache");
- builder.append(' ');
- builder.append(escapeNull(uuid));
- builder.append(' ');
- builder.append(String.valueOf(freeStorageSize));
- return mInstaller.execute(builder.toString());
- }
-
- @Deprecated
- public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath,
- String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats) {
- return getSizeInfo(null, pkgName, persona, apkPath, libDirPath, fwdLockApkPath, asecPath,
- instructionSets, pStats);
- }
-
- public int getSizeInfo(String uuid, String pkgName, int persona, String apkPath,
+ public void getAppSize(String uuid, String pkgname, int userid, int flags, String apkPath,
String libDirPath, String fwdLockApkPath, String asecPath, String[] instructionSets,
- PackageStats pStats) {
+ PackageStats pStats) throws InstallerException {
for (String instructionSet : instructionSets) {
- if (!isValidInstructionSet(instructionSet)) {
- Slog.e(TAG, "Invalid instruction set: " + instructionSet);
- return -1;
- }
+ assertValidInstructionSet(instructionSet);
}
- StringBuilder builder = new StringBuilder("getsize");
- builder.append(' ');
- builder.append(escapeNull(uuid));
- builder.append(' ');
- builder.append(pkgName);
- builder.append(' ');
- builder.append(persona);
- builder.append(' ');
- builder.append(apkPath);
- builder.append(' ');
// TODO: Extend getSizeInfo to look at the full subdirectory tree,
// not just the first level.
- builder.append(libDirPath != null ? libDirPath : "!");
- builder.append(' ');
- builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!");
- builder.append(' ');
- builder.append(asecPath != null ? asecPath : "!");
- builder.append(' ');
// TODO: Extend getSizeInfo to look at *all* instrution sets, not
// just the primary.
- builder.append(instructionSets[0]);
-
- String s = mInstaller.transact(builder.toString());
- String res[] = s.split(" ");
+ final String rawRes = mInstaller.executeForResult("get_app_size", uuid, pkgname, userid,
+ flags, apkPath, libDirPath, fwdLockApkPath, asecPath, instructionSets[0]);
+ final String res[] = rawRes.split(" ");
if ((res == null) || (res.length != 5)) {
- return -1;
+ throw new InstallerException("Invalid size result: " + rawRes);
}
try {
pStats.codeSize = Long.parseLong(res[1]);
pStats.dataSize = Long.parseLong(res[2]);
pStats.cacheSize = Long.parseLong(res[3]);
pStats.externalCodeSize = Long.parseLong(res[4]);
- return Integer.parseInt(res[0]);
} catch (NumberFormatException e) {
- return -1;
+ throw new InstallerException("Invalid size result: " + rawRes);
}
}
- public int moveFiles() {
- return mInstaller.execute("movefiles");
+ public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded,
+ int dexFlags) throws InstallerException {
+ assertValidInstructionSet(instructionSet);
+ mInstaller.dexopt(apkPath, uid, instructionSet, dexoptNeeded, dexFlags);
}
- @Deprecated
- public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath32, int userId) {
- return linkNativeLibraryDirectory(null, dataPath, nativeLibPath32, userId);
+ public void dexopt(String apkPath, int uid, String pkgName, String instructionSet,
+ int dexoptNeeded, @Nullable String outputPath, int dexFlags)
+ throws InstallerException {
+ assertValidInstructionSet(instructionSet);
+ mInstaller.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded,
+ outputPath, dexFlags);
+ }
+
+ public void idmap(String targetApkPath, String overlayApkPath, int uid)
+ throws InstallerException {
+ mInstaller.execute("idmap", targetApkPath, overlayApkPath, uid);
+ }
+
+ public void rmdex(String codePath, String instructionSet) throws InstallerException {
+ assertValidInstructionSet(instructionSet);
+ mInstaller.execute("rmdex", codePath, instructionSet);
+ }
+
+ public void rmPackageDir(String packageDir) throws InstallerException {
+ mInstaller.execute("rmpackagedir", packageDir);
+ }
+
+ public void createUserConfig(int userid) throws InstallerException {
+ mInstaller.execute("mkuserconfig", userid);
+ }
+
+ public void removeUserDataDirs(String uuid, int userid) throws InstallerException {
+ mInstaller.execute("rmuser", uuid, userid);
+ }
+
+ public void markBootComplete(String instructionSet) throws InstallerException {
+ assertValidInstructionSet(instructionSet);
+ mInstaller.execute("markbootcomplete", instructionSet);
+ }
+
+ public void freeCache(String uuid, long freeStorageSize) throws InstallerException {
+ mInstaller.execute("freecache", uuid, freeStorageSize);
+ }
+
+ public void moveFiles() throws InstallerException {
+ mInstaller.execute("movefiles");
}
/**
- * Links the 32 bit native library directory in an application's data directory to the
- * real location for backward compatibility. Note that no such symlink is created for
- * 64 bit shared libraries.
- *
- * @return -1 on error
+ * Links the 32 bit native library directory in an application's data
+ * directory to the real location for backward compatibility. Note that no
+ * such symlink is created for 64 bit shared libraries.
*/
- public int linkNativeLibraryDirectory(String uuid, String dataPath, String nativeLibPath32,
- int userId) {
- if (dataPath == null) {
- Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null");
- return -1;
- } else if (nativeLibPath32 == null) {
- Slog.e(TAG, "linkNativeLibraryDirectory nativeLibPath is null");
- return -1;
- }
-
- StringBuilder builder = new StringBuilder("linklib");
- builder.append(' ');
- builder.append(escapeNull(uuid));
- builder.append(' ');
- builder.append(dataPath);
- builder.append(' ');
- builder.append(nativeLibPath32);
- builder.append(' ');
- builder.append(userId);
-
- return mInstaller.execute(builder.toString());
+ public void linkNativeLibraryDirectory(String uuid, String dataPath, String nativeLibPath32,
+ int userId) throws InstallerException {
+ mInstaller.execute("linklib", uuid, dataPath, nativeLibPath32, userId);
}
- @Deprecated
- public boolean restoreconData(String pkgName, String seinfo, int uid) {
- return restoreconData(null, pkgName, seinfo, uid);
+ public void createOatDir(String oatDir, String dexInstructionSet)
+ throws InstallerException {
+ mInstaller.execute("createoatdir", oatDir, dexInstructionSet);
}
- public boolean restoreconData(String uuid, String pkgName, String seinfo, int uid) {
- StringBuilder builder = new StringBuilder("restorecondata");
- builder.append(' ');
- builder.append(escapeNull(uuid));
- builder.append(' ');
- builder.append(pkgName);
- builder.append(' ');
- builder.append(seinfo != null ? seinfo : "!");
- builder.append(' ');
- builder.append(uid);
- return (mInstaller.execute(builder.toString()) == 0);
+ public void linkFile(String relativePath, String fromBase, String toBase)
+ throws InstallerException {
+ mInstaller.execute("linkfile", relativePath, fromBase, toBase);
}
- public int createOatDir(String oatDir, String dexInstructionSet) {
- StringBuilder builder = new StringBuilder("createoatdir");
- builder.append(' ');
- builder.append(oatDir);
- builder.append(' ');
- builder.append(dexInstructionSet);
- return mInstaller.execute(builder.toString());
- }
-
-
- public int linkFile(String relativePath, String fromBase, String toBase) {
- StringBuilder builder = new StringBuilder("linkfile");
- builder.append(' ');
- builder.append(relativePath);
- builder.append(' ');
- builder.append(fromBase);
- builder.append(' ');
- builder.append(toBase);
- return mInstaller.execute(builder.toString());
- }
-
- /**
- * Returns true iff. {@code instructionSet} is a valid instruction set.
- */
- private static boolean isValidInstructionSet(String instructionSet) {
- if (instructionSet == null) {
- return false;
- }
-
+ private static void assertValidInstructionSet(String instructionSet)
+ throws InstallerException {
for (String abi : Build.SUPPORTED_ABIS) {
- if (instructionSet.equals(VMRuntime.getInstructionSet(abi))) {
- return true;
+ if (VMRuntime.getInstructionSet(abi).equals(instructionSet)) {
+ return;
}
}
-
- return false;
+ throw new InstallerException("Invalid instruction set: " + instructionSet);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index d29a623..b45a922 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -27,6 +27,8 @@
import android.util.Log;
import android.util.Slog;
+import com.android.internal.os.InstallerConnection.InstallerException;
+
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@@ -166,12 +168,13 @@
| (vmSafeMode ? DEXOPT_SAFEMODE : 0)
| (debuggable ? DEXOPT_DEBUGGABLE : 0)
| DEXOPT_BOOTCOMPLETE;
- final int ret = mPackageManagerService.mInstaller.dexopt(path, sharedGid,
- pkg.packageName, dexCodeInstructionSet, dexoptNeeded, oatDir, dexFlags);
-
- // Dex2oat might fail due to compiler / verifier errors.
- if (ret == 0) {
+ try {
+ mPackageManagerService.mInstaller.dexopt(path, sharedGid,
+ pkg.packageName, dexCodeInstructionSet, dexoptNeeded, oatDir,
+ dexFlags);
performedDexOpt = true;
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to dexopt", e);
}
}
}
@@ -210,8 +213,13 @@
File codePath = new File(pkg.codePath);
if (codePath.isDirectory()) {
File oatDir = getOatDir(codePath);
- mPackageManagerService.mInstaller.createOatDir(oatDir.getAbsolutePath(),
- dexInstructionSet);
+ try {
+ mPackageManagerService.mInstaller.createOatDir(oatDir.getAbsolutePath(),
+ dexInstructionSet);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to create oat dir", e);
+ return null;
+ }
return oatDir.getAbsolutePath();
}
return null;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 55b8bf2..23a58d0 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -258,11 +258,7 @@
for (File stage : unclaimedStages) {
Slog.w(TAG, "Deleting orphan stage " + stage);
synchronized (mPm.mInstallLock) {
- if (stage.isDirectory()) {
- mPm.mInstaller.rmPackageDir(stage.getAbsolutePath());
- } else {
- stage.delete();
- }
+ mPm.removeCodePathLI(stage);
}
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 1655cb6..b84ffa3 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -69,6 +69,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.PackageHelper;
+import com.android.internal.os.InstallerConnection.InstallerException;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
@@ -832,9 +833,14 @@
throw new IOException("File: " + pathStr + " outside base: " + baseStr);
}
- private void createOatDirs(List<String> instructionSets, File fromDir) {
+ private void createOatDirs(List<String> instructionSets, File fromDir)
+ throws PackageManagerException {
for (String instructionSet : instructionSets) {
- mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
+ try {
+ mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
+ } catch (InstallerException e) {
+ throw PackageManagerException.from(e);
+ }
}
}
@@ -842,13 +848,12 @@
throws IOException {
for (File fromFile : fromFiles) {
final String relativePath = getRelativePath(fromFile, fromDir);
- final int ret = mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
- toDir.getAbsolutePath());
-
- if (ret < 0) {
- // installd will log failure details.
+ try {
+ mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
+ toDir.getAbsolutePath());
+ } catch (InstallerException e) {
throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
- + fromDir + ", " + toDir + ")");
+ + fromDir + ", " + toDir + ")", e);
}
}
@@ -1041,7 +1046,10 @@
}
}
if (stageDir != null) {
- mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
+ try {
+ mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
+ } catch (InstallerException ignored) {
+ }
}
if (stageCid != null) {
PackageHelper.destroySdDir(stageCid);
diff --git a/services/core/java/com/android/server/pm/PackageManagerException.java b/services/core/java/com/android/server/pm/PackageManagerException.java
index a41636e..d04eedc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerException.java
+++ b/services/core/java/com/android/server/pm/PackageManagerException.java
@@ -16,8 +16,11 @@
package com.android.server.pm;
+import android.content.pm.PackageManager;
import android.content.pm.PackageParser.PackageParserException;
+import com.android.internal.os.InstallerConnection.InstallerException;
+
/** {@hide} */
public class PackageManagerException extends Exception {
public final int error;
@@ -36,4 +39,10 @@
throws PackageManagerException {
throw new PackageManagerException(e.error, e.getMessage(), e.getCause());
}
+
+ public static PackageManagerException from(InstallerException e)
+ throws PackageManagerException {
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
+ e.getMessage(), e.getCause());
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e3ed0c1..f777faf 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -219,6 +219,7 @@
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.PackageHelper;
import com.android.internal.os.IParcelFileDescriptorFactory;
+import com.android.internal.os.InstallerConnection.InstallerException;
import com.android.internal.os.SomeArgs;
import com.android.internal.os.Zygote;
import com.android.internal.util.ArrayUtils;
@@ -2067,7 +2068,7 @@
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Library not found: " + lib);
- } catch (IOException e) {
+ } catch (IOException | InstallerException e) {
Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "
+ e.getMessage());
}
@@ -2136,7 +2137,11 @@
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
- mInstaller.moveFiles();
+ try {
+ mInstaller.moveFiles();
+ } catch (InstallerException e) {
+ logCriticalInfo(Log.WARN, "Update commands failed: " + e);
+ }
// Prune any system packages that no longer exist.
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
@@ -2710,11 +2715,7 @@
removeDataDirsLI(ps.volumeUuid, ps.name);
if (ps.codePath != null) {
- if (ps.codePath.isDirectory()) {
- mInstaller.rmPackageDir(ps.codePath.getAbsolutePath());
- } else {
- ps.codePath.delete();
- }
+ removeCodePathLI(ps.codePath);
}
if (ps.resourcePath != null && !ps.resourcePath.equals(ps.codePath)) {
if (ps.resourcePath.isDirectory()) {
@@ -3038,16 +3039,18 @@
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
- int retCode = -1;
+ boolean success = true;
synchronized (mInstallLock) {
- retCode = mInstaller.freeCache(volumeUuid, freeStorageSize);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't clear application caches");
+ try {
+ mInstaller.freeCache(volumeUuid, freeStorageSize);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Couldn't clear application caches: " + e);
+ success = false;
}
}
if (observer != null) {
try {
- observer.onRemoveCompleted(null, (retCode >= 0));
+ observer.onRemoveCompleted(null, success);
} catch (RemoteException e) {
Slog.w(TAG, "RemoveException when invoking call back");
}
@@ -3065,17 +3068,19 @@
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
- int retCode = -1;
+ boolean success = true;
synchronized (mInstallLock) {
- retCode = mInstaller.freeCache(volumeUuid, freeStorageSize);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't clear application caches");
+ try {
+ mInstaller.freeCache(volumeUuid, freeStorageSize);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Couldn't clear application caches: " + e);
+ success = false;
}
}
if(pi != null) {
try {
// Callback via pending intent
- int code = (retCode >= 0) ? 1 : 0;
+ int code = success ? 1 : 0;
pi.sendIntent(null, code, null,
null, null);
} catch (SendIntentException e1) {
@@ -3088,8 +3093,10 @@
void freeStorage(String volumeUuid, long freeStorageSize) throws IOException {
synchronized (mInstallLock) {
- if (mInstaller.freeCache(volumeUuid, freeStorageSize) < 0) {
- throw new IOException("Failed to free enough space");
+ try {
+ mInstaller.freeCache(volumeUuid, freeStorageSize);
+ } catch (InstallerException e) {
+ throw new IOException("Failed to free enough space", e);
}
}
}
@@ -6086,7 +6093,9 @@
}
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
// TODO: generate idmap for split APKs
- if (mInstaller.idmap(pkg.baseCodePath, opkg.baseCodePath, sharedGid) != 0) {
+ try {
+ mInstaller.idmap(pkg.baseCodePath, opkg.baseCodePath, sharedGid);
+ } catch (InstallerException e) {
Slog.e(TAG, "Failed to generate idmap for " + pkg.baseCodePath + " and "
+ opkg.baseCodePath);
return false;
@@ -6146,11 +6155,7 @@
if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
- if (file.isDirectory()) {
- mInstaller.rmPackageDir(file.getAbsolutePath());
- } else {
- file.delete();
- }
+ removeCodePathLI(file);
}
}
}
@@ -6716,50 +6721,65 @@
private void createDataDirsLI(String volumeUuid, String packageName, int uid, String seinfo)
throws PackageManagerException {
- int res = mInstaller.install(volumeUuid, packageName, uid, uid, seinfo);
- if (res != 0) {
+ // TODO: triage flags as part of 26466827
+ final int appId = UserHandle.getAppId(uid);
+ final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+
+ try {
+ final int[] users = sUserManager.getUserIds();
+ for (int user : users) {
+ mInstaller.createAppData(volumeUuid, packageName, user, flags, appId, seinfo);
+ }
+ } catch (InstallerException e) {
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
- "Failed to install " + packageName + ": " + res);
+ "Failed to prepare data directory", e);
}
+ }
+
+ private boolean removeDataDirsLI(String volumeUuid, String packageName) {
+ // TODO: triage flags as part of 26466827
+ final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+
+ boolean res = true;
+ final int[] users = sUserManager.getUserIds();
+ for (int user : users) {
+ try {
+ mInstaller.destroyAppData(volumeUuid, packageName, user, flags);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to delete data directory", e);
+ res = false;
+ }
+ }
+ return res;
+ }
+
+ void removeCodePathLI(File codePath) {
+ if (codePath.isDirectory()) {
+ try {
+ mInstaller.rmPackageDir(codePath.getAbsolutePath());
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to remove code path", e);
+ }
+ } else {
+ codePath.delete();
+ }
+ }
+
+ private void deleteCodeCacheDirsLI(String volumeUuid, String packageName) {
+ // TODO: triage flags as part of 26466827
+ final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
final int[] users = sUserManager.getUserIds();
for (int user : users) {
- if (user != 0) {
- res = mInstaller.createUserData(volumeUuid, packageName,
- UserHandle.getUid(user, uid), user, seinfo);
- if (res != 0) {
- throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
- "Failed to createUserData " + packageName + ": " + res);
- }
+ try {
+ mInstaller.clearAppData(volumeUuid, packageName, user,
+ flags | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to delete code cache directory", e);
}
}
}
- private int removeDataDirsLI(String volumeUuid, String packageName) {
- int[] users = sUserManager.getUserIds();
- int res = 0;
- for (int user : users) {
- int resInner = mInstaller.remove(volumeUuid, packageName, user);
- if (resInner < 0) {
- res = resInner;
- }
- }
-
- return res;
- }
-
- private int deleteCodeCacheDirsLI(String volumeUuid, String packageName) {
- int[] users = sUserManager.getUserIds();
- int res = 0;
- for (int user : users) {
- int resInner = mInstaller.deleteCodeCacheFiles(volumeUuid, packageName, user);
- if (resInner < 0) {
- res = resInner;
- }
- }
- return res;
- }
-
private void addSharedLibraryLPw(ArraySet<String> usesLibraryFiles, SharedLibraryEntry file,
PackageParser.Package changingLib) {
if (file.path != null) {
@@ -7258,6 +7278,8 @@
final File dataPath = Environment.getDataUserCredentialEncryptedPackageDirectory(
pkg.volumeUuid, UserHandle.USER_SYSTEM, pkg.packageName);
+ // TOOD: switch to ensure various directories
+
boolean uidError = false;
if (dataPath.exists()) {
int currentUid = 0;
@@ -7271,27 +7293,12 @@
// If we have mismatched owners for the data path, we have a problem.
if (currentUid != pkg.applicationInfo.uid) {
boolean recovered = false;
- if (currentUid == 0) {
- // The directory somehow became owned by root. Wow.
- // This is probably because the system was stopped while
- // installd was in the middle of messing with its libs
- // directory. Ask installd to fix that.
- int ret = mInstaller.fixUid(pkg.volumeUuid, pkgName,
- pkg.applicationInfo.uid, pkg.applicationInfo.uid);
- if (ret >= 0) {
- recovered = true;
- String msg = "Package " + pkg.packageName
- + " unexpectedly changed to uid 0; recovered to " +
- + pkg.applicationInfo.uid;
- reportSettingsProblem(Log.WARN, msg);
- }
- }
- if (!recovered && ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0
- || (scanFlags&SCAN_BOOTING) != 0)) {
+ if (((parseFlags & PackageParser.PARSE_IS_SYSTEM) != 0
+ || (scanFlags & SCAN_BOOTING) != 0)) {
// If this is a system app, we can at least delete its
// current data so the application will still work.
- int ret = removeDataDirsLI(pkg.volumeUuid, pkgName);
- if (ret >= 0) {
+ boolean res = removeDataDirsLI(pkg.volumeUuid, pkgName);
+ if (res) {
// TODO: Kill the processes first
// Old data gone!
String prefix = (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0
@@ -7306,11 +7313,12 @@
if (!recovered) {
mHasSystemUidErrors = true;
}
- } else if (!recovered) {
+ } else {
// If we allow this install to proceed, we will be broken.
// Abort, abort!
throw new PackageManagerException(INSTALL_FAILED_UID_CHANGED,
- "scanPackageLI");
+ "Expected data to be owned by UID " + pkg.applicationInfo.uid
+ + " but found " + currentUid);
}
if (!recovered) {
pkg.applicationInfo.dataDir = "/mismatched_uid/settings_"
@@ -7340,8 +7348,16 @@
if (mShouldRestoreconData) {
Slog.i(TAG, "SELinux relabeling of " + pkg.packageName + " issued.");
- mInstaller.restoreconData(pkg.volumeUuid, pkg.packageName,
- pkg.applicationInfo.seinfo, pkg.applicationInfo.uid);
+ // TODO: extend this to restorecon over all users
+ final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
+ // TODO: triage flags as part of 26466827
+ final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+ try {
+ mInstaller.restoreconAppData(pkg.volumeUuid, pkg.packageName,
+ UserHandle.USER_SYSTEM, flags, appId, pkg.applicationInfo.seinfo);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to restorecon " + pkg.packageName, e);
+ }
}
} else {
if (DEBUG_PACKAGE_SCANNING) {
@@ -7397,9 +7413,15 @@
if (!TextUtils.isEmpty(pkg.volumeUuid)) {
for (int userId : userIds) {
if (userId != UserHandle.USER_SYSTEM) {
- mInstaller.createUserData(pkg.volumeUuid, pkg.packageName,
- UserHandle.getUid(userId, pkg.applicationInfo.uid), userId,
- pkg.applicationInfo.seinfo);
+ // TODO: triage flags as part of 26466827
+ final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+ final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
+ try {
+ mInstaller.createAppData(pkg.volumeUuid, pkg.packageName, userId,
+ flags, appId, pkg.applicationInfo.seinfo);
+ } catch (InstallerException e) {
+ throw PackageManagerException.from(e);
+ }
}
}
}
@@ -7413,10 +7435,11 @@
try {
final String nativeLibPath = pkg.applicationInfo.nativeLibraryDir;
for (int userId : userIds) {
- if (mInstaller.linkNativeLibraryDirectory(pkg.volumeUuid, pkg.packageName,
- nativeLibPath, userId) < 0) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Failed linking native library dir (user=" + userId + ")");
+ try {
+ mInstaller.linkNativeLibraryDirectory(pkg.volumeUuid, pkg.packageName,
+ nativeLibPath, userId);
+ } catch (InstallerException e) {
+ throw PackageManagerException.from(e);
}
}
} finally {
@@ -8149,8 +8172,11 @@
if (ps.pkg != null && ps.pkg.applicationInfo != null) {
ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
Slog.i(TAG, "Adjusting ABI for " + ps.name + " to " + adjustedAbi);
- mInstaller.rmdex(ps.codePathString,
- getDexCodeInstructionSet(getPreferredInstructionSet()));
+ try {
+ mInstaller.rmdex(ps.codePathString,
+ getDexCodeInstructionSet(getPreferredInstructionSet()));
+ } catch (InstallerException ignored) {
+ }
}
}
}
@@ -11133,9 +11159,12 @@
final long sizeBytes = mContainerService.calculateInstalledSize(
origin.resolvedPath, isForwardLocked(), packageAbiOverride);
- if (mInstaller.freeCache(null, sizeBytes + lowThreshold) >= 0) {
+ try {
+ mInstaller.freeCache(null, sizeBytes + lowThreshold);
pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
installFlags, packageAbiOverride);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to free cache", e);
}
/*
@@ -11533,11 +11562,9 @@
String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
for (String codePath : allCodePaths) {
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
- int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove dex file for package at location " + codePath
- + ", retcode=" + retCode);
- // we don't consider this to be a failure of the core package deletion
+ try {
+ mInstaller.rmdex(codePath, dexCodeInstructionSet);
+ } catch (InstallerException ignored) {
}
}
}
@@ -11723,11 +11750,7 @@
return false;
}
- if (codeFile.isDirectory()) {
- mInstaller.rmPackageDir(codeFile.getAbsolutePath());
- } else {
- codeFile.delete();
- }
+ removeCodePathLI(codeFile);
if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) {
resourceFile.delete();
@@ -12104,8 +12127,11 @@
if (DEBUG_INSTALL) Slog.d(TAG, "Moving " + move.packageName + " from "
+ move.fromUuid + " to " + move.toUuid);
synchronized (mInstaller) {
- if (mInstaller.copyCompleteApp(move.fromUuid, move.toUuid, move.packageName,
- move.dataAppName, move.appId, move.seinfo) != 0) {
+ try {
+ mInstaller.moveCompleteApp(move.fromUuid, move.toUuid, move.packageName,
+ move.dataAppName, move.appId, move.seinfo);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to move app", e);
return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
}
}
@@ -12168,11 +12194,7 @@
synchronized (mInstallLock) {
// Clean up both app data and code
removeDataDirsLI(volumeUuid, move.packageName);
- if (codeFile.isDirectory()) {
- mInstaller.rmPackageDir(codeFile.getAbsolutePath());
- } else {
- codeFile.delete();
- }
+ removeCodePathLI(codeFile);
}
return true;
}
@@ -13853,7 +13875,13 @@
outInfo.removedAppId = appId;
outInfo.removedUsers = new int[] {removeUser};
}
- mInstaller.clearUserData(ps.volumeUuid, packageName, removeUser);
+ // TODO: triage flags as part of 26466827
+ final int installerFlags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+ try {
+ mInstaller.destroyAppData(ps.volumeUuid, packageName, removeUser, installerFlags);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to delete app data", e);
+ }
removeKeystoreDataIfNeeded(removeUser, appId);
schedulePackageCleaning(packageName, removeUser, false);
synchronized (mPackages) {
@@ -14027,13 +14055,16 @@
// Always delete data directories for package, even if we found no other
// record of app. This helps users recover from UID mismatches without
// resorting to a full data wipe.
- int retCode = mInstaller.clearUserData(pkg.volumeUuid, packageName, userId);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove cache files for package " + packageName);
+ // TODO: triage flags as part of 26466827
+ final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+ try {
+ mInstaller.clearAppData(pkg.volumeUuid, packageName, userId, flags);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Couldn't remove cache files for package " + packageName, e);
return false;
}
- final int appId = pkg.applicationInfo.uid;
+ final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
removeKeystoreDataIfNeeded(userId, appId);
// Create a native library symlink only if we have native libraries
@@ -14042,9 +14073,11 @@
if (pkg.applicationInfo.primaryCpuAbi != null &&
!VMRuntime.is64BitAbi(pkg.applicationInfo.primaryCpuAbi)) {
final String nativeLibPath = pkg.applicationInfo.nativeLibraryDir;
- if (mInstaller.linkNativeLibraryDirectory(pkg.volumeUuid, pkg.packageName,
- nativeLibPath, userId) < 0) {
- Slog.w(TAG, "Failed linking native library dir");
+ try {
+ mInstaller.linkNativeLibraryDirectory(pkg.volumeUuid, pkg.packageName,
+ nativeLibPath, userId);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed linking native library dir", e);
return false;
}
}
@@ -14257,10 +14290,14 @@
Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
return false;
}
- int retCode = mInstaller.deleteCacheFiles(p.volumeUuid, packageName, userId);
- if (retCode < 0) {
+ // TODO: triage flags as part of 26466827
+ final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+ try {
+ mInstaller.clearAppData(p.volumeUuid, packageName, userId,
+ flags | Installer.FLAG_CLEAR_CACHE_ONLY);
+ } catch (InstallerException e) {
Slog.w(TAG, "Couldn't remove cache files for package "
- + packageName + " u" + userId);
+ + packageName + " u" + userId, e);
return false;
}
return true;
@@ -14354,9 +14391,12 @@
apkPath = p.baseCodePath;
}
- int res = mInstaller.getSizeInfo(p.volumeUuid, packageName, userHandle, apkPath,
- libDirRoot, publicSrcDir, asecPath, dexCodeInstructionSets, pStats);
- if (res < 0) {
+ // TODO: triage flags as part of 26466827
+ final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+ try {
+ mInstaller.getAppSize(p.volumeUuid, packageName, userHandle, flags, apkPath,
+ libDirRoot, publicSrcDir, asecPath, dexCodeInstructionSets, pStats);
+ } catch (InstallerException e) {
return false;
}
@@ -16571,7 +16611,11 @@
if (destroyUser) {
synchronized (mInstallLock) {
- mInstaller.removeUserDataDirs(volumeUuid, userId);
+ try {
+ mInstaller.removeUserDataDirs(volumeUuid, userId);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to clean up user dirs", e);
+ }
}
}
}
@@ -16637,11 +16681,7 @@
if (packageName != null) {
removeDataDirsLI(volumeUuid, packageName);
}
- if (file.isDirectory()) {
- mInstaller.rmPackageDir(file.getAbsolutePath());
- } else {
- file.delete();
- }
+ removeCodePathLI(file);
}
}
}
@@ -16977,7 +17017,11 @@
for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
final String volumeUuid = vol.getFsUuid();
if (DEBUG_INSTALL) Slog.d(TAG, "Removing user data on volume " + volumeUuid);
- mInstaller.removeUserDataDirs(volumeUuid, userHandle);
+ try {
+ mInstaller.removeUserDataDirs(volumeUuid, userHandle);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to remove user data", e);
+ }
}
synchronized (mPackages) {
removeUnusedPackagesLILPw(userManager, userHandle);
@@ -17040,7 +17084,11 @@
/** Called by UserManagerService */
void createNewUser(int userHandle) {
synchronized (mInstallLock) {
- mInstaller.createUserConfig(userHandle);
+ try {
+ mInstaller.createUserConfig(userHandle);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to create user config", e);
+ }
mSettings.createNewUserLI(this, mInstaller, userHandle);
}
synchronized (mPackages) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 1a79d3c3..9fef515 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -81,6 +81,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.os.InstallerConnection.InstallerException;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
@@ -3668,7 +3669,7 @@
int userHandle) {
String[] volumeUuids;
String[] names;
- int[] uids;
+ int[] appIds;
String[] seinfos;
int packagesCount;
synchronized (mPackages) {
@@ -3676,7 +3677,7 @@
packagesCount = packages.size();
volumeUuids = new String[packagesCount];
names = new String[packagesCount];
- uids = new int[packagesCount];
+ appIds = new int[packagesCount];
seinfos = new String[packagesCount];
Iterator<PackageSetting> packagesIterator = packages.iterator();
for (int i = 0; i < packagesCount; i++) {
@@ -3690,7 +3691,7 @@
// required args and call the installer after mPackages lock has been released
volumeUuids[i] = ps.volumeUuid;
names[i] = ps.name;
- uids[i] = UserHandle.getUid(userHandle, ps.appId);
+ appIds[i] = ps.appId;
seinfos[i] = ps.pkg.applicationInfo.seinfo;
}
}
@@ -3698,7 +3699,14 @@
if (names[i] == null) {
continue;
}
- installer.createUserData(volumeUuids[i], names[i], uids[i], userHandle, seinfos[i]);
+ // TODO: triage flags!
+ final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+ try {
+ installer.createAppData(volumeUuids[i], names[i], userHandle, flags, appIds[i],
+ seinfos[i]);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to prepare app data", e);
+ }
}
synchronized (mPackages) {
applyDefaultPreferredAppsLPw(service, userHandle);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index de1c1ea..75910a7 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -6402,6 +6402,7 @@
if (mLockScreenTimerActive != enable) {
if (enable) {
if (localLOGV) Log.v(TAG, "setting lockscreen timer");
+ mHandler.removeCallbacks(mScreenLockTimeout); // remove any pending requests
mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout);
} else {
if (localLOGV) Log.v(TAG, "clearing lockscreen timer");
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 72621a4..630367d 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -59,6 +59,7 @@
private final Context mContext;
private final UsageStatsDatabase mDatabase;
private final IntervalStats[] mCurrentStats;
+ private IntervalStats mAppIdleRollingWindow;
private boolean mStatsChanged = false;
private final UnixCalendar mDailyExpiryDate;
private final StatsUpdatedListener mListener;
@@ -137,6 +138,8 @@
initializeDefaultsForApps(currentTimeMillis, deviceUsageTime,
mDatabase.isFirstUpdate());
}
+
+ refreshAppIdleRollingWindow(currentTimeMillis);
}
/**
@@ -170,6 +173,7 @@
persistActiveStats();
mDatabase.onTimeChanged(newTime - oldTime);
loadActiveStats(newTime, resetBeginIdleTime);
+ refreshAppIdleRollingWindow(newTime);
}
void reportEvent(UsageEvents.Event event, long deviceUsageTime) {
@@ -211,6 +215,11 @@
}
}
+ if (event.mEventType != Event.CONFIGURATION_CHANGE) {
+ mAppIdleRollingWindow.update(event.mPackage, event.mTimeStamp, event.mEventType);
+ mAppIdleRollingWindow.updateBeginIdleTime(event.mPackage, deviceUsageTime);
+ }
+
notifyStatsChanged();
}
@@ -222,6 +231,7 @@
for (IntervalStats stats : mCurrentStats) {
stats.updateBeginIdleTime(packageName, beginIdleTime);
}
+ mAppIdleRollingWindow.updateBeginIdleTime(packageName, beginIdleTime);
notifyStatsChanged();
}
@@ -229,6 +239,7 @@
for (IntervalStats stats : mCurrentStats) {
stats.updateSystemLastUsedTime(packageName, lastUsedTime);
}
+ mAppIdleRollingWindow.updateSystemLastUsedTime(packageName, lastUsedTime);
notifyStatsChanged();
}
@@ -387,9 +398,8 @@
}
long getBeginIdleTime(String packageName) {
- final IntervalStats yearly = mCurrentStats[UsageStatsManager.INTERVAL_YEARLY];
UsageStats packageUsage;
- if ((packageUsage = yearly.packageStats.get(packageName)) == null) {
+ if ((packageUsage = mAppIdleRollingWindow.packageStats.get(packageName)) == null) {
return -1;
} else {
return packageUsage.getBeginIdleTime();
@@ -397,9 +407,8 @@
}
long getSystemLastUsedTime(String packageName) {
- final IntervalStats yearly = mCurrentStats[UsageStatsManager.INTERVAL_YEARLY];
UsageStats packageUsage;
- if ((packageUsage = yearly.packageStats.get(packageName)) == null) {
+ if ((packageUsage = mAppIdleRollingWindow.packageStats.get(packageName)) == null) {
return -1;
} else {
return packageUsage.getLastTimeSystemUsed();
@@ -461,6 +470,8 @@
}
persistActiveStats();
+ refreshAppIdleRollingWindow(currentTimeMillis);
+
final long totalTime = SystemClock.elapsedRealtime() - startTime;
Slog.i(TAG, mLogPrefix + "Rolling over usage stats complete. Took " + totalTime
+ " milliseconds");
@@ -503,6 +514,7 @@
}
}
}
+
mStatsChanged = false;
updateRolloverDeadline();
}
@@ -516,6 +528,68 @@
mDailyExpiryDate.getTimeInMillis() + ")");
}
+ private static void mergePackageStats(IntervalStats dst, IntervalStats src) {
+ dst.endTime = Math.max(dst.endTime, src.endTime);
+
+ final int srcPackageCount = src.packageStats.size();
+ for (int i = 0; i < srcPackageCount; i++) {
+ final String packageName = src.packageStats.keyAt(i);
+ final UsageStats srcStats = src.packageStats.valueAt(i);
+ final UsageStats dstStats = dst.packageStats.get(packageName);
+ if (dstStats == null) {
+ dst.packageStats.put(packageName, new UsageStats(srcStats));
+ } else {
+ dstStats.add(src.packageStats.valueAt(i));
+ }
+ }
+ }
+
+ /**
+ * Merges all the stats into the first element of the resulting list.
+ */
+ private static final StatCombiner<IntervalStats> sPackageStatsMerger =
+ new StatCombiner<IntervalStats>() {
+ @Override
+ public void combine(IntervalStats stats, boolean mutable,
+ List<IntervalStats> accumulatedResult) {
+ IntervalStats accum;
+ if (accumulatedResult.isEmpty()) {
+ accum = new IntervalStats();
+ accum.beginTime = stats.beginTime;
+ accumulatedResult.add(accum);
+ } else {
+ accum = accumulatedResult.get(0);
+ }
+
+ mergePackageStats(accum, stats);
+ }
+ };
+
+ /**
+ * App idle operates on a rolling window of time. When we roll over time, we end up with a
+ * period of time where in-memory stats are empty and we don't hit the disk for older stats
+ * for performance reasons. Suddenly all apps will become idle.
+ *
+ * Instead, at times we do a deep query to find all the apps that have run in the past few
+ * days and keep the cached data up to date.
+ *
+ * @param currentTimeMillis
+ */
+ void refreshAppIdleRollingWindow(long currentTimeMillis) {
+ // Start the rolling window for AppIdle requests.
+ List<IntervalStats> stats = mDatabase.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,
+ currentTimeMillis - (1000 * 60 * 60 * 24 * 2), currentTimeMillis,
+ sPackageStatsMerger);
+
+ if (stats == null || stats.isEmpty()) {
+ mAppIdleRollingWindow = new IntervalStats();
+ mergePackageStats(mAppIdleRollingWindow,
+ mCurrentStats[UsageStatsManager.INTERVAL_YEARLY]);
+ } else {
+ mAppIdleRollingWindow = stats.get(0);
+ }
+ }
+
//
// -- DUMP related methods --
//
@@ -538,6 +612,9 @@
pw.println(" stats");
printIntervalStats(pw, mCurrentStats[interval], screenOnTime, true);
}
+
+ pw.println("AppIdleRollingWindow cache");
+ printIntervalStats(pw, mAppIdleRollingWindow, screenOnTime, true);
}
private String formatDateTime(long dateTime, boolean pretty) {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 1a040bb..80c5b1e 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -473,6 +473,15 @@
public static final String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool";
/**
+ * Determine whether user can switch Wi-Fi preferred or Cellular preferred in calling preference.
+ * Some operators support Wi-Fi Calling only, not VoLTE.
+ * They don't need "Cellular preferred" option.
+ * In this case, set uneditalbe attribute for preferred preference.
+ * @hide
+ */
+ public static final String KEY_EDITABLE_WFC_MODE_BOOL = "editable_wfc_mode_bool";
+
+ /**
* If this is true, the SIM card (through Customer Service Profile EF file) will be able to
* prevent manual operator selection. If false, this SIM setting will be ignored and manual
* operator selection will always be available. See CPHS4_2.WW6, CPHS B.4.7.1 for more
@@ -645,6 +654,7 @@
sDefaults.putBoolean(KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL, false);
sDefaults.putBoolean(BOOL_ALLOW_EMERGENCY_VIDEO_CALLS, false);
sDefaults.putBoolean(BOOL_ALLOW_VIDEO_PAUSE, true);
+ sDefaults.putBoolean(KEY_EDITABLE_WFC_MODE_BOOL, true);
// MMS defaults
sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false);
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 9998937..39f3213 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -24,6 +24,7 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.net.Uri;
+import android.os.Looper;
import android.telephony.Rlog;
import android.os.Handler;
import android.os.Message;
@@ -347,7 +348,31 @@
* for #onSubscriptionsChanged to be invoked.
*/
public static class OnSubscriptionsChangedListener {
- private final Handler mHandler = new Handler() {
+ private final Handler mHandler;
+
+ public OnSubscriptionsChangedListener() {
+ mHandler = new OnSubscriptionsChangedListenerHandler();
+ }
+
+ /**
+ * Contructor that takes in looper as parameter in case a subclass/instantiation needs
+ * to use a specific looper (like in tests where mainLooper may need to be used).
+ * @param looper Looper to be used for mHandler
+ * @hide
+ */
+ protected OnSubscriptionsChangedListener(Looper looper) {
+ mHandler = new OnSubscriptionsChangedListenerHandler(looper);
+ }
+
+ private class OnSubscriptionsChangedListenerHandler extends Handler {
+ private OnSubscriptionsChangedListenerHandler() {
+ super();
+ }
+
+ private OnSubscriptionsChangedListenerHandler(Looper looper) {
+ super(looper);
+ }
+
@Override
public void handleMessage(Message msg) {
if (DBG) {
@@ -355,7 +380,7 @@
}
OnSubscriptionsChangedListener.this.onSubscriptionsChanged();
}
- };
+ }
/**
* Callback invoked when there is any change to any SubscriptionInfo. Typically