diff options
54 files changed, 1746 insertions, 884 deletions
diff --git a/Android.mk b/Android.mk index c1c74ea04e55..b95ab2e9d0dd 100644 --- a/Android.mk +++ b/Android.mk @@ -345,6 +345,7 @@ LOCAL_SRC_FILES += \ 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 47d32077861a..629d832c0c3c 100644 --- a/api/current.txt +++ b/api/current.txt @@ -20371,8 +20371,6 @@ package android.media { 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 @@ package java.lang { 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 @@ package java.lang { 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 @@ package java.security.cert { 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 @@ package java.security.cert { 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 @@ package java.security.cert { 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 @@ package java.security.cert { 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 @@ package java.security.cert { 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 @@ package java.security.cert { 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 @@ package java.security.cert { 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 bf8e0e7eb7ad..6a36ce05acca 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -21670,8 +21670,6 @@ package android.media { 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 @@ package java.lang { 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 @@ package java.lang { 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 @@ package java.security.cert { 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 @@ package java.security.cert { 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 @@ package java.security.cert { 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 @@ package java.security.cert { 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 @@ package java.security.cert { 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 @@ package java.security.cert { 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 @@ package java.security.cert { 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 6eba6bd7a2df..21b101fef449 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -20379,8 +20379,6 @@ package android.media { 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 @@ package java.lang { 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 @@ package java.lang { 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 @@ package java.security.cert { 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 @@ package java.security.cert { 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 @@ package java.security.cert { 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 @@ package java.security.cert { 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 @@ package java.security.cert { 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 @@ package java.security.cert { 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 @@ package java.security.cert { 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 81e00ff80e11..4e55c89fa739 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -2015,7 +2015,7 @@ public final class ActivityThread { 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 @@ public final class ActivityThread { 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 @@ public final class ActivityThread { 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 @@ public final class ActivityThread { 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 @@ public final class ActivityThread { 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 @@ public final class ActivityThread { 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 @@ public final class ActivityThread { 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 @@ public final class ActivityThread { 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 @@ public final class ActivityThread { 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 38abac7e741b..5113e1979812 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -4413,6 +4413,15 @@ public abstract class PackageManager { 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 f642f08df76e..282688295fee 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -1258,6 +1258,10 @@ public class InputMethodService extends AbstractInputMethodService { */ @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 fdd34f586e8c..e58744bfd905 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -130,6 +130,9 @@ public final class Debug /** 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 @@ public final class Debug /** 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 @@ public final class Debug /** 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 final class Debug 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 final class Debug 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 @@ public final class Debug * Return total PSS memory usage in kB. */ public int getTotalPss() { - return dalvikPss + nativePss + otherPss; + return dalvikPss + nativePss + otherPss + getTotalSwappedOutPss(); } /** @@ -274,7 +289,8 @@ public final class Debug } /** - * 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 @@ public final class Debug 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 @@ public final class Debug } /** @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 @@ public final class Debug * 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 @@ public final class Debug dest.writeInt(otherPrivateClean); dest.writeInt(otherSharedClean); dest.writeInt(otherSwappedOut); + dest.writeInt(hasSwappedOutPss ? 1 : 0); + dest.writeInt(otherSwappedOutPss); dest.writeIntArray(otherStats); } @@ -689,6 +732,8 @@ public final class Debug otherPrivateClean = source.readInt(); otherSharedClean = source.readInt(); otherSwappedOut = source.readInt(); + hasSwappedOutPss = source.readInt() != 0; + otherSwappedOutPss = source.readInt(); otherStats = source.createIntArray(); } @@ -1563,11 +1608,12 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * 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 c42c791769e6..2a52961984f7 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -688,13 +688,14 @@ class TextLine { * @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 @@ class TextLine { 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 @@ class TextLine { 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 @@ class TextLine { } 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 @@ class TextLine { 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 0fb39516d4d2..3eb2e37be781 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1488,7 +1488,8 @@ public final class ViewRootImpl implements ViewParent, 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 830da79c2a0b..b3222f013b3e 100644 --- a/core/java/com/android/internal/os/InstallerConnection.java +++ b/core/java/com/android/internal/os/InstallerConnection.java @@ -19,6 +19,7 @@ package com.android.internal.os; 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 libcore.io.Streams; 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 class InstallerConnection { } 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 class InstallerConnection { } } - 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()); + public void execute(String cmd, Object... args) throws InstallerException { + final String resRaw = executeForResult(cmd, args); + int res = -1; + try { + res = Integer.parseInt(resRaw); + } catch (NumberFormatException ignored) { + } + if (res != 0) { + throw new InstallerException( + "Failed to execute " + cmd + " " + Arrays.toString(args) + ": " + res); } + } - String res = transact(cmd); - try { - return Integer.parseInt(res); - } catch (NumberFormatException ex) { - return -1; + 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 instructionSet, - int dexoptNeeded, int dexFlags) { - return dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded, - null /*outputPath*/, dexFlags); + public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded, + int dexFlags) throws InstallerException { + dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded, null /* outputPath */, dexFlags); } - 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 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 class InstallerConnection { 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 4a1f7f490a6d..eecc0eeab062 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.EventLog; 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 @@ public class ZygoteInit { 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 e162810fd802..8e8f6c371204 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -152,7 +152,8 @@ static struct { static struct { jmethodID postDynPolicyEventFromNative; -} gDynPolicyEventHandlerMethods; + jmethodID postRecordConfigEventFromNative; +} gAudioPolicyEventHandlerMethods; static Mutex gLock; @@ -378,12 +379,26 @@ android_media_AudioSystem_dyn_policy_callback(int event, String8 regId, int val) 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 @@ android_media_AudioSystem_registerDynPolicyCallback(JNIEnv *env, jobject thiz) 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 @@ static const JNINativeMethod gMethods[] = { (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 @@ int register_android_media_AudioSystem(JNIEnv *env) 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 2488111247a2..03a1e718d2ea 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -84,6 +84,7 @@ struct stat_fields { jfieldID privateClean_field; jfieldID sharedClean_field; jfieldID swappedOut_field; + jfieldID swappedOutPss_field; }; struct stat_field_names { @@ -94,20 +95,22 @@ struct stat_field_names { 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 @@ struct stats_t { int privateClean; int sharedClean; int swappedOut; + int swappedOutPss; }; #define BINDER_STATS "/proc/binder/stats" @@ -206,7 +210,7 @@ static int read_memtrack_memory(int pid, struct graphics_memory_pss* graphics_me 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 @@ static void read_mapinfo(FILE *fp, stats_t* stats) 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 @@ static void read_mapinfo(FILE *fp, stats_t* stats) int subHeap = HEAP_UNKNOWN; int prevHeap = HEAP_UNKNOWN; + *foundSwapPss = false; + if(fgets(line, sizeof(line), fp) == 0) return; while (!done) { @@ -340,6 +346,7 @@ static void read_mapinfo(FILE *fp, stats_t* stats) 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 @@ static void read_mapinfo(FILE *fp, stats_t* stats) /* 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 @@ static void read_mapinfo(FILE *fp, stats_t* stats) 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 @@ static void read_mapinfo(FILE *fp, stats_t* stats) 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 @@ static void load_maps(int pid, stats_t* stats) 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 @@ static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz, 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 @@ static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz, 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 @@ static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz, 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 @@ static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject o 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 @@ static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid, jl } 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 @@ int register_android_os_Debug(JNIEnv *env) } 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 @@ int register_android_os_Debug(JNIEnv *env) 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 0932e8998ce2..44c5e2f35f6e 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -109,8 +109,8 @@ ifeq (true, $(HWUI_NEW_OPS)) 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 @@ LOCAL_SRC_FILES += \ 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 @@ LOCAL_SRC_FILES += \ 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 23aca899a485..5b34f6b79199 100644 --- a/libs/hwui/BakedOpDispatcher.cpp +++ b/libs/hwui/BakedOpDispatcher.cpp @@ -545,19 +545,19 @@ void BakedOpDispatcher::onPatchOp(BakedOpRenderer& renderer, const PatchOp& op, 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 f0406fa13a3d..87844f9840d7 100644 --- a/libs/hwui/BakedOpState.cpp +++ b/libs/hwui/BakedOpState.cpp @@ -71,7 +71,6 @@ ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& s 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 index e95b26787273..166656cbd72b 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 @@ FrameReorderer::FrameReorderer(const LayerUpdateQueue& layers, const SkRect& cli } } -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 @@ static size_t findNonNegativeIndex(const V& zTranslatedNodes) { } 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::defer3dChildren(ChildrenSelectMode mode, const V& zTranslat } } -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::deferShadow(const RenderNodeOp& casterNodeOp) { } } -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 @@ void FrameReorderer::deferProjectedChildren(const RenderNode& renderNode) { } /** - * 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::deferNodeOps(const RenderNode& renderNode) { } } -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 @@ void FrameReorderer::deferRenderNodeOpImpl(const RenderNodeOp& op) { mCanvasState.restoreToCount(count); } -void FrameReorderer::deferRenderNodeOp(const RenderNodeOp& op) { +void FrameBuilder::deferRenderNodeOp(const RenderNodeOp& op) { if (!op.skipInOrderDraw) { deferRenderNodeOpImpl(op); } @@ -410,7 +410,7 @@ void FrameReorderer::deferRenderNodeOp(const RenderNodeOp& op) { * 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 @@ static batchid_t tessBatchId(const RecordedOp& op) { : (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 @@ static bool hasMergeableClip(const BakedOpState& state) { || 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::deferBitmapOp(const BitmapOp& op) { } } -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 @@ void FrameReorderer::deferCirclePropsOp(const CirclePropsOp& op) { 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::deferPatchOp(const PatchOp& op) { } } -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 @@ void FrameReorderer::deferRoundRectPropsOp(const RoundRectPropsOp& op) { 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 @@ static batchid_t textBatchId(const SkPaint& paint) { 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::deferTextOp(const TextOp& op) { } } -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 @@ void FrameReorderer::saveForLayer(uint32_t layerWidth, uint32_t layerHeight, 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 @@ void FrameReorderer::restoreForLayer() { // 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 @@ void FrameReorderer::deferBeginLayerOp(const BeginLayerOp& op) { &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 @@ void FrameReorderer::deferEndLayerOp(const EndLayerOp& /* ignored */) { beginLayerOp.localMatrix, beginLayerOp.localClip, beginLayerOp.paint, - &(mLayerReorderers[finishedLayerIndex]->offscreenBuffer)); + &(mLayerBuilders[finishedLayerIndex]->offscreenBuffer)); BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp); if (bakedOpState) { @@ -684,12 +684,12 @@ void FrameReorderer::deferEndLayerOp(const EndLayerOp& /* ignored */) { // 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 @@ void FrameReorderer::deferBeginUnclippedLayerOp(const BeginUnclippedLayerOp& op) 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 index 3bb862620ba2..3ba73f00f61d 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 @@ class Rect; * 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 @@ class Rect; * 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 @@ public: // 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 @@ public: } } - 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 @@ private: 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 @@ private: 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 @@ private: #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 index 60f36bedd929..7170d4fbeea7 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 @@ private: 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 @@ LayerReorderer::LayerReorderer(uint32_t width, uint32_t height, // 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::locateInsertIndex(int batchId, const Rect& clippedBounds, } } -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::flushLayerClears(LinearAllocator& allocator) { } } -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::deferUnmergeableOp(LinearAllocator& allocator, } } -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::deferMergeableOp(LinearAllocator& allocator, } } -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::replayBakedOpsImpl(void* arg, } } -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 index 59fd4f8dff5d..99968e1750c8 100644 --- a/libs/hwui/LayerReorderer.h +++ b/libs/hwui/LayerBuilder.h @@ -67,17 +67,17 @@ typedef void (*MergedOpReceiver)(void*, const MergedBakedOpList& opList); * 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 612cdfdc7185..8e4a3df271f5 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -47,11 +47,11 @@ class CanvasState; 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; */ 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 fff8e0968ee6..644f3565216b 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 @@ void CanvasContext::draw() { 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 index b4c9a3626597..67c95e2e921f 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 @@ void BM_FrameBuilder_defer::Run(int iters) { 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 @@ void BM_FrameBuilder_deferAndRender::Run(int iters) { 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 @@ static void benchDeferScene(testing::Benchmark& benchmark, int iters, const char 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 @@ static void benchDeferAndRenderScene(testing::Benchmark& benchmark, 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 b3506869e0dc..0f8e0471556f 100644 --- a/libs/hwui/tests/unit/BakedOpStateTests.cpp +++ b/libs/hwui/tests/unit/BakedOpStateTests.cpp @@ -199,9 +199,12 @@ TEST(BakedOpState, tryConstruct) { } 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 @@ TEST(BakedOpState, tryShadowOpConstruct) { "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 index 9d2eb98a011d..bded50a2e0fd 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 @@ public: 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 @@ TEST(FrameReorderer, simple) { 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 @@ TEST(FrameReorderer, simpleStroke) { 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 @@ TEST(FrameReorderer, simpleRejection) { 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 @@ TEST(FrameReorderer, simpleBatching) { 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 @@ TEST(FrameReorderer, clippedMerging) { 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 @@ TEST(FrameReorderer, textMerging) { 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 @@ TEST(FrameReorderer, textStrikethrough) { 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 @@ RENDERTHREAD_TEST(FrameReorderer, textureLayer) { 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 @@ TEST(FrameReorderer, renderNode) { 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 @@ TEST(FrameReorderer, clipped) { 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 @@ TEST(FrameReorderer, saveLayer_simple) { 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 @@ TEST(FrameReorderer, saveLayer_nested) { 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 @@ TEST(FrameReorderer, saveLayer_contentRejection) { 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 @@ TEST(FrameReorderer, saveLayerUnclipped_simple) { 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 @@ TEST(FrameReorderer, saveLayerUnclipped_mergedClears) { 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 @@ TEST(FrameReorderer, saveLayerUnclipped_mergedClears) { * - 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 @@ TEST(FrameReorderer, saveLayerUnclipped_complex) { 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 @@ RENDERTHREAD_TEST(FrameReorderer, hwLayer_simple) { 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 @@ RENDERTHREAD_TEST(FrameReorderer, hwLayer_complex) { 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 @@ static void drawOrderedNode(RecordingCanvas* canvas, uint8_t expectedDrawOrder, 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 @@ TEST(FrameReorderer, zReorder) { 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 @@ TEST(FrameReorderer, projectionReorder) { 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 @@ static sp<RenderNode> createWhiteRectShadowCaster(float translationZ) { }); } -TEST(FrameReorderer, shadow) { +TEST(FrameBuilder, shadow) { class ShadowTestRenderer : public TestRendererBase { public: void onShadowOp(const ShadowOp& op, const BakedOpState& state) override { @@ -1044,14 +1044,14 @@ TEST(FrameReorderer, shadow) { 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 @@ TEST(FrameReorderer, shadowSaveLayer) { 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 @@ RENDERTHREAD_TEST(FrameReorderer, shadowHwLayer) { 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 @@ TEST(FrameReorderer, shadowLayering) { 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 @@ static void testProperty(std::function<void(RenderProperties&)> propSetupCallbac 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, renderPropOverlappingRenderingAlpha) { }); } -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, renderPropClipping) { }); } -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, renderPropRevealClip) { }); } -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, renderPropOutlineClip) { }); } -TEST(FrameReorderer, renderPropTransform) { +TEST(FrameBuilder, renderPropTransform) { testProperty([](RenderProperties& properties) { properties.setLeftTopRightBottom(10, 10, 110, 110); @@ -1334,15 +1334,15 @@ void testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData, }); 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 @@ TEST(FrameReorderer, renderPropSaveLayerAlphaClipBig) { << "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 @@ TEST(FrameReorderer, renderPropSaveLayerAlphaRotate) { 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 a09240852a38..ea1690fd2691 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -51,6 +51,7 @@ import java.util.ArrayList; 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 @@ public class AudioManager { } /** - * 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 @@ public class AudioManager { 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 @@ public class AudioManager { } + //==================================================================== + // Audio policy /** * @hide * Register the given {@link AudioPolicy}. @@ -2754,6 +2795,131 @@ public class AudioManager { } + //==================================================================== + // 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 000000000000..afe912b10b8f --- /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 000000000000..aefe692de651 --- /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 7bfd7ca4d56d..aa0d78dacd7e 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -227,7 +227,7 @@ public class AudioSystem } /** - * 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 @@ public class AudioSystem } } + /** + * 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 @@ public class AudioSystem // 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 dbb7661046c3..abe92c727cc5 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -20,9 +20,11 @@ import android.app.PendingIntent; 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 @@ interface IAudioService { 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 000000000000..a5eb8b9fa787 --- /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 9bcb5e35938b..0fba9925b6c1 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -1735,8 +1735,7 @@ public final class MediaCodecInfo { 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 @@ public final class MediaCodecInfo { 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 a102e51de3d0..b2fa0acf7f57 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -92,8 +92,6 @@ public final class MediaFormat { 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 8e3447d99da4..1b5911dba931 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 898112af4c48..5adb165667c4 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 443778e525d5..7556c6b33a83 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 @@ public class KeyguardViewMediator extends SystemUI { 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 @@ public class KeyguardViewMediator extends SystemUI { } } + @Override public void keyguardDoneDrawing() { mHandler.sendEmptyMessage(KEYGUARD_DONE_DRAWING); } @@ -1248,7 +1251,9 @@ public class KeyguardViewMediator extends SystemUI { 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 @@ public class KeyguardViewMediator extends SystemUI { 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 3c63aae9c416..0901015f12f2 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.annotation.SuppressLint; 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 @@ public class VolumeDialog { : 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 @@ public class VolumeDialog { 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 b27b92d50d0f..093a33dc6049 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.IResultReceiver; 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative } int num = 0; - long[] tmp = new long[1]; + long[] tmp = new long[2]; do { ProcessRecord proc; int procState; @@ -2273,7 +2274,7 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative * 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative dumpDetails = true; dumpFullDetails = true; dumpDalvik = true; + dumpSwapPss = true; } else if ("-d".equals(opt)) { dumpDalvik = true; } else if ("-c".equals(opt)) { @@ -15521,22 +15547,29 @@ public final class ActivityManagerService extends ActivityManagerNative } 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 @@ public final class ActivityManagerService extends ActivityManagerNative } } - final boolean isCheckinRequest = scanArgs(args, "--checkin"); long uptime = SystemClock.uptimeMillis(); long realtime = SystemClock.elapsedRealtime(); final long[] tmpLong = new long[1]; @@ -15617,18 +15649,28 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative } 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative } 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative /** * 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative // 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 03975536816d..f2e8d090d85d 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 @@ option java_package com.android.server.am 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 4bfe30075cff..b4aa4cfe84ec 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 @@ final class ProcessRecord { 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 @@ final class ProcessRecord { 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 b8cbecb48928..9331dd8cd92e 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.AudioFormat; 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 @@ public class AudioService extends IAudioService.Stub { LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal()); mUserManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener); + + mRecordMonitor.initMonitor(); } public void systemReady() { @@ -6165,7 +6169,7 @@ public class AudioService extends IAudioService.Stub { } //====================== - // 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 @@ public class AudioService extends IAudioService.Stub { } } } + } + + //====================== + // 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 000000000000..5806f3fb5b70 --- /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 99a051af1717..190eca63b183 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.annotation.Nullable; 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 @@ public final class Installer extends SystemService { /** 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 @@ public final class Installer extends SystemService { 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; - } - } - - @Deprecated - public int install(String name, int uid, int gid, String seinfo) { - return install(null, name, uid, gid, 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 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 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 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 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); } - 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 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 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 void clearAppData(String uuid, String pkgname, int userid, int flags) + throws InstallerException { + mInstaller.execute("clear_app_data", uuid, pkgname, userid, flags); } - 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()); + public void destroyAppData(String uuid, String pkgname, int userid, int flags) + throws InstallerException { + mInstaller.execute("destroy_app_data", uuid, pkgname, userid, flags); } - @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 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 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); } - /** - * 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 - */ - 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; - } + public void idmap(String targetApkPath, String overlayApkPath, int uid) + throws InstallerException { + mInstaller.execute("idmap", targetApkPath, overlayApkPath, uid); + } - 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 rmdex(String codePath, String instructionSet) throws InstallerException { + assertValidInstructionSet(instructionSet); + mInstaller.execute("rmdex", codePath, instructionSet); } - @Deprecated - public boolean restoreconData(String pkgName, String seinfo, int uid) { - return restoreconData(null, pkgName, seinfo, uid); + public void rmPackageDir(String packageDir) throws InstallerException { + mInstaller.execute("rmpackagedir", packageDir); } - 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 createUserConfig(int userid) throws InstallerException { + mInstaller.execute("mkuserconfig", userid); } - 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 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 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()); + public void moveFiles() throws InstallerException { + mInstaller.execute("movefiles"); } /** - * Returns true iff. {@code instructionSet} is a valid instruction set. + * 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. */ - private static boolean isValidInstructionSet(String instructionSet) { - if (instructionSet == null) { - return false; - } + public void linkNativeLibraryDirectory(String uuid, String dataPath, String nativeLibPath32, + int userId) throws InstallerException { + mInstaller.execute("linklib", uuid, dataPath, nativeLibPath32, userId); + } + public void createOatDir(String oatDir, String dexInstructionSet) + throws InstallerException { + mInstaller.execute("createoatdir", oatDir, dexInstructionSet); + } + + public void linkFile(String relativePath, String fromBase, String toBase) + throws InstallerException { + mInstaller.execute("linkfile", relativePath, fromBase, toBase); + } + + 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 d29a6231c2f5..b45a922460d3 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.ArraySet; 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 @@ final class PackageDexOptimizer { | (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 @@ final class PackageDexOptimizer { 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 55b8bf2f6206..23a58d06eed1 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 @@ public class PackageInstallerService extends IPackageInstaller.Stub { 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 1655cb67979d..b84ffa39a803 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 libcore.io.Libcore; 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 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { 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 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { 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 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } 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 a41636e5d1b5..d04eedc68126 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 @@ public class PackageManagerException extends Exception { 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 e3ed0c136d56..f777faf3c6c0 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.app.ResolverActivity; 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 @@ public class PackageManagerService extends IPackageManager.Stub { } } 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 @@ public class PackageManagerService extends IPackageManager.Stub { | 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { } 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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,48 +6721,63 @@ public class PackageManagerService extends IPackageManager.Stub { 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) { - 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.destroyAppData(volumeUuid, packageName, user, flags); + } catch (InstallerException e) { + Slog.w(TAG, "Failed to delete data directory", e); + res = false; } } + return res; } - 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; + 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(); } - - return res; } - private int deleteCodeCacheDirsLI(String volumeUuid, String packageName) { - int[] users = sUserManager.getUserIds(); - int res = 0; + 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) { - int resInner = mInstaller.deleteCodeCacheFiles(volumeUuid, packageName, user); - if (resInner < 0) { - res = resInner; + 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); } } - return res; } private void addSharedLibraryLPw(ArraySet<String> usesLibraryFiles, SharedLibraryEntry file, @@ -7258,6 +7278,8 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { // 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { // 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { if (packageName != null) { removeDataDirsLI(volumeUuid, packageName); } - if (file.isDirectory()) { - mInstaller.rmPackageDir(file.getAbsolutePath()); - } else { - file.delete(); - } + removeCodePathLI(file); } } } @@ -16977,7 +17017,11 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { /** 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 1a79d3c3e733..9fef51565c04 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 android.util.Xml; 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 @@ final class Settings { int userHandle) { String[] volumeUuids; String[] names; - int[] uids; + int[] appIds; String[] seinfos; int packagesCount; synchronized (mPackages) { @@ -3676,7 +3677,7 @@ final class Settings { 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 @@ final class Settings { // 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 @@ final class Settings { 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 de1c1ea091df..75910a76cffb 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 72621a422ce6..630367de40a9 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 @@ class UserUsageStatsService { 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 @@ class UserUsageStatsService { initializeDefaultsForApps(currentTimeMillis, deviceUsageTime, mDatabase.isFirstUpdate()); } + + refreshAppIdleRollingWindow(currentTimeMillis); } /** @@ -170,6 +173,7 @@ class UserUsageStatsService { persistActiveStats(); mDatabase.onTimeChanged(newTime - oldTime); loadActiveStats(newTime, resetBeginIdleTime); + refreshAppIdleRollingWindow(newTime); } void reportEvent(UsageEvents.Event event, long deviceUsageTime) { @@ -211,6 +215,11 @@ class UserUsageStatsService { } } + if (event.mEventType != Event.CONFIGURATION_CHANGE) { + mAppIdleRollingWindow.update(event.mPackage, event.mTimeStamp, event.mEventType); + mAppIdleRollingWindow.updateBeginIdleTime(event.mPackage, deviceUsageTime); + } + notifyStatsChanged(); } @@ -222,6 +231,7 @@ class UserUsageStatsService { for (IntervalStats stats : mCurrentStats) { stats.updateBeginIdleTime(packageName, beginIdleTime); } + mAppIdleRollingWindow.updateBeginIdleTime(packageName, beginIdleTime); notifyStatsChanged(); } @@ -229,6 +239,7 @@ class UserUsageStatsService { for (IntervalStats stats : mCurrentStats) { stats.updateSystemLastUsedTime(packageName, lastUsedTime); } + mAppIdleRollingWindow.updateSystemLastUsedTime(packageName, lastUsedTime); notifyStatsChanged(); } @@ -387,9 +398,8 @@ class UserUsageStatsService { } 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 @@ class UserUsageStatsService { } 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 @@ class UserUsageStatsService { } 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 @@ class UserUsageStatsService { } } } + mStatsChanged = false; updateRolloverDeadline(); } @@ -516,6 +528,68 @@ class UserUsageStatsService { 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 @@ class UserUsageStatsService { 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 1a040bb57fad..80c5b1e204f4 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -473,6 +473,15 @@ public class CarrierConfigManager { 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 @@ public class CarrierConfigManager { 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 99989377c374..39f321365c8d 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -24,6 +24,7 @@ import android.content.Intent; 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 @@ public class SubscriptionManager { * 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 @@ public class SubscriptionManager { } OnSubscriptionsChangedListener.this.onSubscriptionsChanged(); } - }; + } /** * Callback invoked when there is any change to any SubscriptionInfo. Typically |