summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp2
-rw-r--r--api/current.txt82
-rw-r--r--api/removed.txt15
-rw-r--r--cmds/statsd/src/atoms.proto37
-rw-r--r--cmds/statsd/src/external/SubsystemSleepStatePuller.cpp301
-rw-r--r--cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/Utils.java15
-rw-r--r--cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/localdrive/LocalDrive.java6
-rw-r--r--cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java2
-rw-r--r--config/hiddenapi-greylist.txt19
-rw-r--r--core/java/android/app/Activity.java2
-rw-r--r--core/java/android/app/ActivityManagerInternal.java4
-rw-r--r--core/java/android/app/ApplicationPackageManager.java11
-rw-r--r--core/java/android/app/RemoteInput.java2
-rw-r--r--core/java/android/app/SystemServiceRegistry.java2
-rw-r--r--core/java/android/app/slice/SliceProvider.java2
-rw-r--r--core/java/android/content/ContentProvider.java12
-rw-r--r--core/java/android/content/Context.java2
-rw-r--r--core/java/android/content/pm/ModuleInfo.java146
-rw-r--r--core/java/android/content/pm/PackageManager.java35
-rw-r--r--core/java/android/os/UserManager.java12
-rw-r--r--core/java/android/os/ZygoteProcess.java2
-rw-r--r--core/java/android/provider/DocumentsContract.java24
-rw-r--r--core/java/android/text/style/ImageSpan.java3
-rw-r--r--core/java/android/view/contentcapture/ContentCaptureManager.java63
-rw-r--r--core/java/com/android/internal/app/procstats/AssociationState.java15
-rw-r--r--core/java/com/android/internal/app/procstats/ProcessStats.java48
-rw-r--r--core/java/com/android/internal/os/Zygote.java5
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java4
-rw-r--r--core/java/com/android/internal/util/CollectionUtils.java4
-rw-r--r--core/java/com/android/server/SystemConfig.java736
-rw-r--r--core/jni/android/graphics/ColorFilter.cpp12
-rw-r--r--core/jni/android/graphics/Paint.cpp17
-rw-r--r--core/jni/com_android_internal_net_NetworkStatsFactory.cpp1
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp62
-rw-r--r--core/proto/android/app/settings_enums.proto4
-rw-r--r--core/res/AndroidManifest.xml8
-rw-r--r--core/tests/coretests/src/android/os/BinderWorkSourceTest.java2
-rw-r--r--docs/html/reference/images/graphics/blendmode_CLEAR.pngbin0 -> 363 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_COLOR.pngbin0 -> 3836 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_COLOR_BURN.pngbin0 -> 4092 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_COLOR_DODGE.pngbin0 -> 3980 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_DARKEN.pngbin0 -> 3894 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_DIFFERENCE.pngbin0 -> 4055 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_DST.pngbin0 -> 3656 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_DST_ATOP.pngbin0 -> 1717 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_DST_IN.pngbin0 -> 1423 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_DST_OUT.pngbin0 -> 2983 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_DST_OVER.pngbin0 -> 3982 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_EXCLUSION.pngbin0 -> 4002 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_HARD_LIGHT.pngbin0 -> 3857 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_HUE.pngbin0 -> 3926 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_LIGHTEN.pngbin0 -> 3749 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_LUMINOSITY.pngbin0 -> 4052 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_MODULATE.pngbin0 -> 1435 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_MULTIPLY.pngbin0 -> 3949 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_OVERLAY.pngbin0 -> 4011 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_PLUS.pngbin0 -> 3898 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_SATURATION.pngbin0 -> 4015 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_SCREEN.pngbin0 -> 3857 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_SOFT_LIGHT.pngbin0 -> 4031 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_SRC.pngbin0 -> 690 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_SRC_ATOP.pngbin0 -> 3762 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_SRC_IN.pngbin0 -> 1415 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_SRC_OUT.pngbin0 -> 1591 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_SRC_OVER.pngbin0 -> 3188 bytes
-rw-r--r--docs/html/reference/images/graphics/blendmode_XOR.pngbin0 -> 3971 bytes
-rw-r--r--graphics/java/android/graphics/BaseCanvas.java12
-rw-r--r--graphics/java/android/graphics/BaseRecordingCanvas.java9
-rw-r--r--graphics/java/android/graphics/BlendMode.java472
-rw-r--r--graphics/java/android/graphics/BlendModeColorFilter.java84
-rw-r--r--graphics/java/android/graphics/Canvas.java14
-rw-r--r--graphics/java/android/graphics/Paint.java43
-rw-r--r--graphics/java/android/graphics/PorterDuffColorFilter.java8
-rw-r--r--graphics/java/android/graphics/drawable/Drawable.java5
-rw-r--r--packages/CarSystemUI/Android.bp1
-rw-r--r--packages/CarSystemUI/res/values/config.xml27
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java161
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java5
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java6
-rw-r--r--packages/ExtServices/AndroidManifest.xml7
-rw-r--r--packages/ExtServices/src/android/ext/services/sms/FinancialSmsServiceImpl.java80
-rw-r--r--packages/ExtServices/tests/src/android/ext/services/sms/FinancialSmsServiceImplTest.java35
-rw-r--r--packages/SystemUI/res/layout/qs_detail.xml3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java28
-rw-r--r--proto/src/metrics_constants/metrics_constants.proto5
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java144
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java23
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java125
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java1
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java45
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerService.java10
-rw-r--r--services/core/java/com/android/server/job/controllers/ConnectivityController.java6
-rw-r--r--services/core/java/com/android/server/job/controllers/QuotaController.java54
-rw-r--r--services/core/java/com/android/server/job/controllers/StateController.java36
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java6
-rw-r--r--services/core/jni/com_android_server_net_NetworkStatsService.cpp1
-rw-r--r--services/net/java/android/net/apf/ApfFilter.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java54
-rw-r--r--services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java41
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java2
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java4
-rw-r--r--telephony/java/android/telephony/DataFailCause.java259
-rw-r--r--telephony/java/android/telephony/ims/RcsManager.java36
-rw-r--r--telephony/java/android/telephony/ims/RcsMessageStore.java (renamed from telephony/java/android/telephony/rcs/RcsManager.java)14
-rw-r--r--telephony/java/android/telephony/ims/RcsThread.aidl20
-rw-r--r--telephony/java/android/telephony/ims/RcsThread.java (renamed from telephony/java/android/telephony/rcs/RcsThread.java)5
-rw-r--r--telephony/java/android/telephony/ims/aidl/IRcs.aidl (renamed from telephony/java/com/android/internal/telephony/rcs/IRcs.aidl)8
-rw-r--r--telephony/java/android/telephony/rcs/RcsThread.aidl20
-rw-r--r--tests/RcsTests/src/com/android/tests/rcs/RcsMessageStoreTest.java (renamed from tests/RcsTests/src/com/android/tests/rcs/RcsManagerTest.java)8
-rw-r--r--tests/net/java/android/net/apf/ApfTest.java41
-rw-r--r--tests/net/jni/apf_jni.cpp101
-rw-r--r--tests/net/res/raw/apfPcap.pcapbin0 -> 101547 bytes
117 files changed, 3209 insertions, 627 deletions
diff --git a/Android.bp b/Android.bp
index 32bd40861839..e096c9df5662 100644
--- a/Android.bp
+++ b/Android.bp
@@ -535,6 +535,7 @@ java_defaults {
"telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl",
"telephony/java/android/telephony/ims/aidl/IImsServiceControllerListener.aidl",
"telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl",
+ "telephony/java/android/telephony/ims/aidl/IRcs.aidl",
"telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl",
"telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl",
"telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl",
@@ -611,7 +612,6 @@ java_defaults {
"telephony/java/com/android/internal/telephony/euicc/ISetDefaultSmdpAddressCallback.aidl",
"telephony/java/com/android/internal/telephony/euicc/ISetNicknameCallback.aidl",
"telephony/java/com/android/internal/telephony/euicc/ISwitchToProfileCallback.aidl",
- "telephony/java/com/android/internal/telephony/rcs/IRcs.aidl",
"wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl",
"wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl",
"wifi/java/android/net/wifi/ISoftApCallback.aidl",
diff --git a/api/current.txt b/api/current.txt
index f1f37896a3db..ae7ca9824373 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -57,6 +57,7 @@ package android {
field public static final java.lang.String BROADCAST_SMS = "android.permission.BROADCAST_SMS";
field public static final java.lang.String BROADCAST_STICKY = "android.permission.BROADCAST_STICKY";
field public static final java.lang.String BROADCAST_WAP_PUSH = "android.permission.BROADCAST_WAP_PUSH";
+ field public static final java.lang.String CALL_COMPANION_APP = "android.permission.CALL_COMPANION_APP";
field public static final java.lang.String CALL_PHONE = "android.permission.CALL_PHONE";
field public static final java.lang.String CALL_PRIVILEGED = "android.permission.CALL_PRIVILEGED";
field public static final java.lang.String CAMERA = "android.permission.CAMERA";
@@ -91,7 +92,6 @@ package android {
field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
field public static final java.lang.String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS";
- field public static final java.lang.String CALL_COMPANION_APP = "android.permission.CALL_COMPANION_APP";
field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
field public static final java.lang.String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL";
field public static final java.lang.String MODIFY_AUDIO_SETTINGS = "android.permission.MODIFY_AUDIO_SETTINGS";
@@ -11227,6 +11227,15 @@ package android.content.pm {
field public static final int FLAG_MATCH_PINNED_BY_ANY_LAUNCHER = 1024; // 0x400
}
+ public final class ModuleInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public java.lang.String getName();
+ method public java.lang.String getPackageName();
+ method public boolean isHidden();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.content.pm.ModuleInfo> CREATOR;
+ }
+
public class PackageInfo implements android.os.Parcelable {
ctor public PackageInfo();
method public int describeContents();
@@ -11443,6 +11452,7 @@ package android.content.pm {
method public abstract android.graphics.drawable.Drawable getDefaultActivityIcon();
method public abstract android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
+ method public java.util.List<android.content.pm.ModuleInfo> getInstalledModules(int);
method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
method public abstract java.lang.String getInstallerPackageName(java.lang.String);
method public abstract byte[] getInstantAppCookie();
@@ -11450,6 +11460,7 @@ package android.content.pm {
method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.Intent getLaunchIntentForPackage(java.lang.String);
method public abstract android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
+ method public android.content.pm.ModuleInfo getModuleInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract java.lang.String getNameForUid(int);
method public android.content.pm.PackageInfo getPackageArchiveInfo(java.lang.String, int);
method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -13561,6 +13572,46 @@ package android.graphics {
ctor public BitmapShader(android.graphics.Bitmap, android.graphics.Shader.TileMode, android.graphics.Shader.TileMode);
}
+ public final class BlendMode extends java.lang.Enum {
+ method public static android.graphics.BlendMode valueOf(java.lang.String);
+ method public static final android.graphics.BlendMode[] values();
+ enum_constant public static final android.graphics.BlendMode CLEAR;
+ enum_constant public static final android.graphics.BlendMode COLOR;
+ enum_constant public static final android.graphics.BlendMode COLOR_BURN;
+ enum_constant public static final android.graphics.BlendMode COLOR_DODGE;
+ enum_constant public static final android.graphics.BlendMode DARKEN;
+ enum_constant public static final android.graphics.BlendMode DIFFERENCE;
+ enum_constant public static final android.graphics.BlendMode DST;
+ enum_constant public static final android.graphics.BlendMode DST_ATOP;
+ enum_constant public static final android.graphics.BlendMode DST_IN;
+ enum_constant public static final android.graphics.BlendMode DST_OUT;
+ enum_constant public static final android.graphics.BlendMode DST_OVER;
+ enum_constant public static final android.graphics.BlendMode EXCLUSION;
+ enum_constant public static final android.graphics.BlendMode HARD_LIGHT;
+ enum_constant public static final android.graphics.BlendMode HUE;
+ enum_constant public static final android.graphics.BlendMode LIGHTEN;
+ enum_constant public static final android.graphics.BlendMode LUMINOSITY;
+ enum_constant public static final android.graphics.BlendMode MODULATE;
+ enum_constant public static final android.graphics.BlendMode MULTIPLY;
+ enum_constant public static final android.graphics.BlendMode OVERLAY;
+ enum_constant public static final android.graphics.BlendMode PLUS;
+ enum_constant public static final android.graphics.BlendMode SATURATION;
+ enum_constant public static final android.graphics.BlendMode SCREEN;
+ enum_constant public static final android.graphics.BlendMode SOFT_LIGHT;
+ enum_constant public static final android.graphics.BlendMode SRC;
+ enum_constant public static final android.graphics.BlendMode SRC_ATOP;
+ enum_constant public static final android.graphics.BlendMode SRC_IN;
+ enum_constant public static final android.graphics.BlendMode SRC_OUT;
+ enum_constant public static final android.graphics.BlendMode SRC_OVER;
+ enum_constant public static final android.graphics.BlendMode XOR;
+ }
+
+ public final class BlendModeColorFilter extends android.graphics.ColorFilter {
+ ctor public BlendModeColorFilter(int, android.graphics.BlendMode);
+ method public int getColor();
+ method public android.graphics.BlendMode getMode();
+ }
+
public class BlurMaskFilter extends android.graphics.MaskFilter {
ctor public BlurMaskFilter(float, android.graphics.BlurMaskFilter.Blur);
}
@@ -13623,7 +13674,8 @@ package android.graphics {
method public void drawBitmapMesh(android.graphics.Bitmap, int, int, float[], int, int[], int, android.graphics.Paint);
method public void drawCircle(float, float, float, android.graphics.Paint);
method public void drawColor(int);
- method public void drawColor(int, android.graphics.PorterDuff.Mode);
+ method public deprecated void drawColor(int, android.graphics.PorterDuff.Mode);
+ method public void drawColor(int, android.graphics.BlendMode);
method public void drawDoubleRoundRect(android.graphics.RectF, float, float, android.graphics.RectF, float, float, android.graphics.Paint);
method public void drawDoubleRoundRect(android.graphics.RectF, float[], android.graphics.RectF, float[], android.graphics.Paint);
method public void drawLine(float, float, float, float, android.graphics.Paint);
@@ -14245,6 +14297,7 @@ package android.graphics {
method public float descent();
method public boolean equalsForTextMeasurement(android.graphics.Paint);
method public int getAlpha();
+ method public android.graphics.BlendMode getBlendMode();
method public int getColor();
method public android.graphics.ColorFilter getColorFilter();
method public boolean getFillPath(android.graphics.Path, android.graphics.Path);
@@ -14299,7 +14352,7 @@ package android.graphics {
method public float getUnderlinePosition();
method public float getUnderlineThickness();
method public float getWordSpacing();
- method public android.graphics.Xfermode getXfermode();
+ method public deprecated android.graphics.Xfermode getXfermode();
method public boolean hasGlyph(java.lang.String);
method public final boolean isAntiAlias();
method public final boolean isDither();
@@ -14319,6 +14372,7 @@ package android.graphics {
method public void setARGB(int, int, int, int);
method public void setAlpha(int);
method public void setAntiAlias(boolean);
+ method public void setBlendMode(android.graphics.BlendMode);
method public void setColor(int);
method public android.graphics.ColorFilter setColorFilter(android.graphics.ColorFilter);
method public void setDither(boolean);
@@ -14352,7 +14406,7 @@ package android.graphics {
method public android.graphics.Typeface setTypeface(android.graphics.Typeface);
method public void setUnderlineText(boolean);
method public void setWordSpacing(float);
- method public android.graphics.Xfermode setXfermode(android.graphics.Xfermode);
+ method public deprecated android.graphics.Xfermode setXfermode(android.graphics.Xfermode);
field public static final int ANTI_ALIAS_FLAG = 1; // 0x1
field public static final int CURSOR_AFTER = 0; // 0x0
field public static final int CURSOR_AT = 4; // 0x4
@@ -14634,7 +14688,7 @@ package android.graphics {
enum_constant public static final android.graphics.PorterDuff.Mode XOR;
}
- public class PorterDuffColorFilter extends android.graphics.ColorFilter {
+ public deprecated class PorterDuffColorFilter extends android.graphics.ColorFilter {
ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode);
}
@@ -15190,7 +15244,7 @@ package android.graphics.drawable {
method public final void setCallback(android.graphics.drawable.Drawable.Callback);
method public void setChangingConfigurations(int);
method public abstract void setColorFilter(android.graphics.ColorFilter);
- method public void setColorFilter(int, android.graphics.PorterDuff.Mode);
+ method public deprecated void setColorFilter(int, android.graphics.PorterDuff.Mode);
method public deprecated void setDither(boolean);
method public void setFilterBitmap(boolean);
method public void setHotspot(float, float);
@@ -37479,25 +37533,37 @@ package android.provider {
method public static android.net.Uri buildSearchDocumentsUri(java.lang.String, java.lang.String, java.lang.String);
method public static android.net.Uri buildTreeDocumentUri(java.lang.String, java.lang.String);
method public static android.net.Uri copyDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static deprecated android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
method public static android.net.Uri createDocument(android.content.ContentInterface, android.net.Uri, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
+ method public static deprecated android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
method public static android.content.IntentSender createWebLinkIntent(android.content.ContentInterface, android.net.Uri, android.os.Bundle) throws java.io.FileNotFoundException;
+ method public static deprecated android.content.IntentSender createWebLinkIntent(android.content.ContentResolver, android.net.Uri, android.os.Bundle) throws java.io.FileNotFoundException;
method public static boolean deleteDocument(android.content.ContentInterface, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static deprecated boolean deleteDocument(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
method public static void ejectRoot(android.content.ContentInterface, android.net.Uri);
+ method public static deprecated void ejectRoot(android.content.ContentResolver, android.net.Uri);
method public static android.provider.DocumentsContract.Path findDocumentPath(android.content.ContentInterface, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static deprecated android.provider.DocumentsContract.Path findDocumentPath(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
method public static java.lang.String getDocumentId(android.net.Uri);
method public static android.os.Bundle getDocumentMetadata(android.content.ContentInterface, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static deprecated android.os.Bundle getDocumentMetadata(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentInterface, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
+ method public static deprecated android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public static java.lang.String getRootId(android.net.Uri);
method public static java.lang.String getSearchDocumentsQuery(android.net.Uri);
method public static java.lang.String getTreeDocumentId(android.net.Uri);
method public static boolean isChildDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static deprecated boolean isChildDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
method public static boolean isRootUri(android.content.Context, android.net.Uri);
method public static boolean isRootsUri(android.content.Context, android.net.Uri);
method public static boolean isTreeUri(android.net.Uri);
method public static android.net.Uri moveDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static deprecated android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
method public static boolean removeDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static deprecated boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
method public static android.net.Uri renameDocument(android.content.ContentInterface, android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
+ method public static deprecated android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
field public static final java.lang.String ACTION_DOCUMENT_SETTINGS = "android.provider.action.DOCUMENT_SETTINGS";
field public static final java.lang.String EXTRA_ERROR = "error";
field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
@@ -43168,6 +43234,7 @@ package android.telecom {
field public static final java.lang.String EXTRA_INCOMING_CALL_EXTRAS = "android.telecom.extra.INCOMING_CALL_EXTRAS";
field public static final java.lang.String EXTRA_INCOMING_VIDEO_STATE = "android.telecom.extra.INCOMING_VIDEO_STATE";
field public static final java.lang.String EXTRA_IS_DEFAULT_CALL_SCREENING_APP = "android.telecom.extra.IS_DEFAULT_CALL_SCREENING_APP";
+ field public static final java.lang.String EXTRA_IS_ENABLED = "android.telecom.extra.IS_ENABLED";
field public static final java.lang.String EXTRA_NOTIFICATION_COUNT = "android.telecom.extra.NOTIFICATION_COUNT";
field public static final java.lang.String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
@@ -43175,14 +43242,13 @@ package android.telecom {
field public static final java.lang.String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
- field public static final java.lang.String EXTRA_IS_ENABLED = "android.telecom.extra.IS_ENABLED";
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
field public static final java.lang.String METADATA_INCLUDE_EXTERNAL_CALLS = "android.telecom.INCLUDE_EXTERNAL_CALLS";
field public static final java.lang.String METADATA_INCLUDE_SELF_MANAGED_CALLS = "android.telecom.INCLUDE_SELF_MANAGED_CALLS";
+ field public static final java.lang.String METADATA_IN_CALL_SERVICE_CAR_MODE_UI = "android.telecom.IN_CALL_SERVICE_CAR_MODE_UI";
field public static final java.lang.String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING";
field public static final java.lang.String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI";
- field public static final java.lang.String METADATA_IN_CALL_SERVICE_CAR_MODE_UI = "android.telecom.IN_CALL_SERVICE_CAR_MODE_UI";
field public static final int PRESENTATION_ALLOWED = 1; // 0x1
field public static final int PRESENTATION_PAYPHONE = 4; // 0x4
field public static final int PRESENTATION_RESTRICTED = 2; // 0x2
diff --git a/api/removed.txt b/api/removed.txt
index e3e8b6397e6f..f7106d2207ec 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -508,21 +508,6 @@ package android.provider {
field public static final deprecated java.lang.String TIMESTAMP = "timestamp";
}
- public final class DocumentsContract {
- method public static android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
- method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
- method public static android.content.IntentSender createWebLinkIntent(android.content.ContentResolver, android.net.Uri, android.os.Bundle) throws java.io.FileNotFoundException;
- method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
- method public static void ejectRoot(android.content.ContentResolver, android.net.Uri);
- method public static android.provider.DocumentsContract.Path findDocumentPath(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
- method public static android.os.Bundle getDocumentMetadata(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
- method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
- method public static boolean isChildDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
- method public static android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
- method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
- method public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
- }
-
public static final class Settings.Global extends android.provider.Settings.NameValueTable {
field public static final deprecated java.lang.String CONTACT_METADATA_SYNC = "contact_metadata_sync";
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index f58caff76d27..410bd198a227 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -2394,16 +2394,23 @@ message KernelWakelock {
}
/**
- * Pulls low power state information. This includes platform and subsystem sleep state information,
- * PowerStatePlatformSleepState, PowerStateVoter or PowerStateSubsystemSleepState as defined in
+ * Pulls low power state information. If power.stats HAL is not available, this
+ * includes platform and subsystem sleep state information,
+ * PowerStatePlatformSleepState, PowerStateVoter or PowerStateSubsystemSleepState
+ * as defined in:
* hardware/interfaces/power/1.0/types.hal
* hardware/interfaces/power/1.1/types.hal
+ * If power.stats HAL is available, this includes PowerEntityStateResidencyResult
+ * as defined in:
+ * hardware/interfaces/power/stats/1.0/types.hal
*/
message SubsystemSleepState {
// Subsystem name
optional string subsystem_name = 1;
// For PlatformLowPowerStats (hal 1.0), this is the voter name, which could be empty.
// For SubsystemLowPowerStats (hal 1.1), this is the sleep state name.
+ // For PowerEntityStateResidencyResult (hal power/stats/1.0) this is the
+ // powerEntityStateName from the corresponding PowerEntityStateInfo.
optional string subname = 2;
// The number of times it entered, or voted for entering the sleep state
optional uint64 count = 3;
@@ -2540,15 +2547,19 @@ message BluetoothActivityInfo {
/*
* Logs the memory stats for a process.
+ *
+ * Pulled from StatsCompanionService for all managed processes (from ActivityManagerService).
*/
message ProcessMemoryState {
// The uid if available. -1 means not available.
optional int32 uid = 1 [(is_uid) = true];
// The process name.
+ // Usually package name, "system" for system server.
+ // Provided by ActivityManagerService.
optional string process_name = 2;
- // oom adj score.
+ // Current OOM score adjustment. Value read from ProcessRecord.
optional int32 oom_adj_score = 3;
// # of page-faults
@@ -2558,12 +2569,18 @@ message ProcessMemoryState {
optional int64 page_major_fault = 5;
// RSS
+ // Value is read from /proc/PID/stat, field 24. Or from memory.stat, field
+ // total_rss if per-app memory cgroups are enabled.
optional int64 rss_in_bytes = 6;
// CACHE
+ // Value is read from memory.stat, field total_cache if per-app memory
+ // cgroups are enabled. Otherwise, 0.
optional int64 cache_in_bytes = 7;
// SWAP
+ // Value is read from memory.stat, field total_swap if per-app memory
+ // cgroups are enabled. Otherwise, 0.
optional int64 swap_in_bytes = 8;
// Deprecated: use ProcessMemoryHighWaterMark atom instead. Always 0.
@@ -2576,12 +2593,15 @@ message ProcessMemoryState {
/*
* Logs the memory stats for a native process (from procfs).
+ *
+ * Pulled from StatsCompanionService for selected native processes.
*/
message NativeProcessMemoryState {
// The uid if available. -1 means not available.
optional int32 uid = 1 [(is_uid) = true];
// The process name.
+ // Value read from /proc/PID/cmdline.
optional string process_name = 2;
// # of page-faults
@@ -2591,6 +2611,7 @@ message NativeProcessMemoryState {
optional int64 page_major_fault = 4;
// RSS
+ // Value read from /proc/PID/stat, field 24.
optional int64 rss_in_bytes = 5;
// Deprecated: use ProcessMemoryHighWaterMark atom instead. Always 0.
@@ -2603,13 +2624,17 @@ message NativeProcessMemoryState {
/*
* Logs the memory high-water mark for a process.
- * Recorded in ActivityManagerService.
+ *
+ * Pulled from StatsCompanionService for all managed processes (from ActivityManagerServie)
+ * and for selected native processes.
*/
message ProcessMemoryHighWaterMark {
// The uid if available. -1 means not available.
optional int32 uid = 1 [(is_uid) = true];
- // The process name. Provided by ActivityManagerService or read from /proc/PID/cmdline.
+ // The process name.
+ // Usually package name or process cmdline.
+ // Provided by ActivityManagerService or read from /proc/PID/cmdline.
optional string process_name = 2;
// RSS high-water mark. Peak RSS usage of the process. Read from the VmHWM field in
@@ -3586,4 +3611,4 @@ message DocsUIUserActionReported {
*/
message DocsUIInvalidScopedAccessRequestReported {
optional android.stats.docsui.InvalidScopedAccess type = 1;
-} \ No newline at end of file
+}
diff --git a/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
index 4501b64ad47e..c8c392016e52 100644
--- a/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
+++ b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
@@ -19,6 +19,8 @@
#include <android/hardware/power/1.0/IPower.h>
#include <android/hardware/power/1.1/IPower.h>
+#include <android/hardware/power/stats/1.0/IPowerStats.h>
+
#include <fcntl.h>
#include <hardware/power.h>
#include <hardware_legacy/power.h>
@@ -42,9 +44,12 @@ using android::hardware::hidl_vec;
using android::hardware::power::V1_0::IPower;
using android::hardware::power::V1_0::PowerStatePlatformSleepState;
using android::hardware::power::V1_0::PowerStateVoter;
-using android::hardware::power::V1_0::Status;
using android::hardware::power::V1_1::PowerStateSubsystem;
using android::hardware::power::V1_1::PowerStateSubsystemSleepState;
+using android::hardware::power::stats::V1_0::PowerEntityInfo;
+using android::hardware::power::stats::V1_0::PowerEntityStateResidencyResult;
+using android::hardware::power::stats::V1_0::PowerEntityStateSpace;
+
using android::hardware::Return;
using android::hardware::Void;
@@ -55,44 +60,209 @@ namespace android {
namespace os {
namespace statsd {
+std::function<bool(vector<shared_ptr<LogEvent>>* data)> gPuller = {};
+
sp<android::hardware::power::V1_0::IPower> gPowerHalV1_0 = nullptr;
sp<android::hardware::power::V1_1::IPower> gPowerHalV1_1 = nullptr;
+sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHalV1_0 = nullptr;
+
+std::unordered_map<uint32_t, std::string> gEntityNames = {};
+std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>> gStateNames = {};
+
std::mutex gPowerHalMutex;
-bool gPowerHalExists = true;
-bool getPowerHal() {
- if (gPowerHalExists && gPowerHalV1_0 == nullptr) {
- gPowerHalV1_0 = android::hardware::power::V1_0::IPower::getService();
- if (gPowerHalV1_0 != nullptr) {
- gPowerHalV1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
- ALOGI("Loaded power HAL service");
- } else {
- ALOGW("Couldn't load power HAL service");
- gPowerHalExists = false;
+// The caller must be holding gPowerHalMutex.
+void deinitPowerStatsLocked() {
+ gPowerHalV1_0 = nullptr;
+ gPowerHalV1_1 = nullptr;
+ gPowerStatsHalV1_0 = nullptr;
+}
+
+struct PowerHalDeathRecipient : virtual public hardware::hidl_death_recipient {
+ virtual void serviceDied(uint64_t cookie,
+ const wp<android::hidl::base::V1_0::IBase>& who) override {
+ // The HAL just died. Reset all handles to HAL services.
+ std::lock_guard<std::mutex> lock(gPowerHalMutex);
+ deinitPowerStatsLocked();
+ }
+};
+
+sp<PowerHalDeathRecipient> gDeathRecipient = new PowerHalDeathRecipient();
+
+SubsystemSleepStatePuller::SubsystemSleepStatePuller() :
+ StatsPuller(android::util::SUBSYSTEM_SLEEP_STATE) {
+}
+
+// The caller must be holding gPowerHalMutex.
+bool checkResultLocked(const Return<void> &ret, const char* function) {
+ if (!ret.isOk()) {
+ ALOGE("%s failed: requested HAL service not available. Description: %s",
+ function, ret.description().c_str());
+ if (ret.isDeadObject()) {
+ deinitPowerStatsLocked();
+ }
+ return false;
+ }
+ return true;
+}
+
+// The caller must be holding gPowerHalMutex.
+// gPowerStatsHalV1_0 must not be null
+bool initializePowerStats() {
+ using android::hardware::power::stats::V1_0::Status;
+
+ // Clear out previous content if we are re-initializing
+ gEntityNames.clear();
+ gStateNames.clear();
+
+ Return<void> ret;
+ ret = gPowerStatsHalV1_0->getPowerEntityInfo([](auto infos, auto status) {
+ if (status != Status::SUCCESS) {
+ ALOGE("Error getting power entity info");
+ return;
+ }
+
+ // construct lookup table of powerEntityId to power entity name
+ for (auto info : infos) {
+ gEntityNames.emplace(info.powerEntityId, info.powerEntityName);
}
+ });
+ if (!checkResultLocked(ret, __func__)) {
+ return false;
}
- return gPowerHalV1_0 != nullptr;
+
+ ret = gPowerStatsHalV1_0->getPowerEntityStateInfo({}, [](auto stateSpaces, auto status) {
+ if (status != Status::SUCCESS) {
+ ALOGE("Error getting state info");
+ return;
+ }
+
+ // construct lookup table of powerEntityId, powerEntityStateId to power entity state name
+ for (auto stateSpace : stateSpaces) {
+ std::unordered_map<uint32_t, std::string> stateNames = {};
+ for (auto state : stateSpace.states) {
+ stateNames.emplace(state.powerEntityStateId,
+ state.powerEntityStateName);
+ }
+ gStateNames.emplace(stateSpace.powerEntityId, stateNames);
+ }
+ });
+ if (!checkResultLocked(ret, __func__)) {
+ return false;
+ }
+
+ return (!gEntityNames.empty()) && (!gStateNames.empty());
}
-SubsystemSleepStatePuller::SubsystemSleepStatePuller() : StatsPuller(android::util::SUBSYSTEM_SLEEP_STATE) {
+// The caller must be holding gPowerHalMutex.
+bool getPowerStatsHalLocked() {
+ if(gPowerStatsHalV1_0 == nullptr) {
+ gPowerStatsHalV1_0 = android::hardware::power::stats::V1_0::IPowerStats::getService();
+ if (gPowerStatsHalV1_0 == nullptr) {
+ ALOGE("Unable to get power.stats HAL service.");
+ return false;
+ }
+
+ // Link death recipient to power.stats service handle
+ hardware::Return<bool> linked = gPowerStatsHalV1_0->linkToDeath(gDeathRecipient, 0);
+ if (!linked.isOk()) {
+ ALOGE("Transaction error in linking to power.stats HAL death: %s",
+ linked.description().c_str());
+ deinitPowerStatsLocked();
+ return false;
+ } else if (!linked) {
+ ALOGW("Unable to link to power.stats HAL death notifications");
+ // We should still continue even though linking failed
+ }
+ return initializePowerStats();
+ }
+ return true;
}
-bool SubsystemSleepStatePuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
- std::lock_guard<std::mutex> lock(gPowerHalMutex);
+// The caller must be holding gPowerHalMutex.
+bool getIPowerStatsDataLocked(vector<shared_ptr<LogEvent>>* data) {
+ using android::hardware::power::stats::V1_0::Status;
- if (!getPowerHal()) {
- ALOGE("Power Hal not loaded");
+ if(!getPowerStatsHalLocked()) {
return false;
}
int64_t wallClockTimestampNs = getWallClockNs();
int64_t elapsedTimestampNs = getElapsedRealtimeNs();
- data->clear();
+ // Get power entity state residency data
+ bool success = false;
+ Return<void> ret = gPowerStatsHalV1_0->getPowerEntityStateResidencyData({},
+ [&data, &success, wallClockTimestampNs, elapsedTimestampNs]
+ (auto results, auto status) {
+ if (status == Status::NOT_SUPPORTED) {
+ ALOGW("getPowerEntityStateResidencyData is not supported");
+ success = false;
+ return;
+ }
+
+ for(auto result : results) {
+ for(auto stateResidency : result.stateResidencyData) {
+ auto statePtr = make_shared<LogEvent>(
+ android::util::SUBSYSTEM_SLEEP_STATE,
+ wallClockTimestampNs, elapsedTimestampNs);
+ statePtr->write(gEntityNames.at(result.powerEntityId));
+ statePtr->write(gStateNames.at(result.powerEntityId)
+ .at(stateResidency.powerEntityStateId));
+ statePtr->write(stateResidency.totalStateEntryCount);
+ statePtr->write(stateResidency.totalTimeInStateMs);
+ statePtr->init();
+ data->emplace_back(statePtr);
+ }
+ }
+ success = true;
+ });
+ // Intentionally not returning early here.
+ // bool success determines if this succeeded or not.
+ checkResultLocked(ret, __func__);
- Return<void> ret;
+ return success;
+}
+
+// The caller must be holding gPowerHalMutex.
+bool getPowerHalLocked() {
+ if(gPowerHalV1_0 == nullptr) {
+ gPowerHalV1_0 = android::hardware::power::V1_0::IPower::getService();
+ if(gPowerHalV1_0 == nullptr) {
+ ALOGE("Unable to get power HAL service.");
+ return false;
+ }
+ gPowerHalV1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
+
+ // Link death recipient to power service handle
+ hardware::Return<bool> linked = gPowerHalV1_0->linkToDeath(gDeathRecipient, 0);
+ if (!linked.isOk()) {
+ ALOGE("Transaction error in linking to power HAL death: %s",
+ linked.description().c_str());
+ gPowerHalV1_0 = nullptr;
+ return false;
+ } else if (!linked) {
+ ALOGW("Unable to link to power. death notifications");
+ // We should still continue even though linking failed
+ }
+ }
+ return true;
+}
+
+// The caller must be holding gPowerHalMutex.
+bool getIPowerDataLocked(vector<shared_ptr<LogEvent>>* data) {
+ using android::hardware::power::V1_0::Status;
+
+ if(!getPowerHalLocked()) {
+ return false;
+ }
+
+ int64_t wallClockTimestampNs = getWallClockNs();
+ int64_t elapsedTimestampNs = getElapsedRealtimeNs();
+ Return<void> ret;
ret = gPowerHalV1_0->getPlatformLowPowerStats(
- [&data, wallClockTimestampNs, elapsedTimestampNs](hidl_vec<PowerStatePlatformSleepState> states, Status status) {
+ [&data, wallClockTimestampNs, elapsedTimestampNs]
+ (hidl_vec<PowerStatePlatformSleepState> states, Status status) {
if (status != Status::SUCCESS) return;
for (size_t i = 0; i < states.size(); i++) {
@@ -128,9 +298,7 @@ bool SubsystemSleepStatePuller::PullInternal(vector<shared_ptr<LogEvent>>* data)
}
}
});
- if (!ret.isOk()) {
- ALOGE("getLowPowerStats() failed: power HAL service not available");
- gPowerHalV1_0 = nullptr;
+ if (!checkResultLocked(ret, __func__)) {
return false;
}
@@ -139,35 +307,68 @@ bool SubsystemSleepStatePuller::PullInternal(vector<shared_ptr<LogEvent>>* data)
android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
if (gPowerHal_1_1 != nullptr) {
ret = gPowerHal_1_1->getSubsystemLowPowerStats(
- [&data, wallClockTimestampNs, elapsedTimestampNs](hidl_vec<PowerStateSubsystem> subsystems, Status status) {
- if (status != Status::SUCCESS) return;
-
- if (subsystems.size() > 0) {
- for (size_t i = 0; i < subsystems.size(); i++) {
- const PowerStateSubsystem& subsystem = subsystems[i];
- for (size_t j = 0; j < subsystem.states.size(); j++) {
- const PowerStateSubsystemSleepState& state =
- subsystem.states[j];
- auto subsystemStatePtr = make_shared<LogEvent>(
- android::util::SUBSYSTEM_SLEEP_STATE,
- wallClockTimestampNs, elapsedTimestampNs);
- subsystemStatePtr->write(subsystem.name);
- subsystemStatePtr->write(state.name);
- subsystemStatePtr->write(state.totalTransitions);
- subsystemStatePtr->write(state.residencyInMsecSinceBoot);
- subsystemStatePtr->init();
- data->push_back(subsystemStatePtr);
- VLOG("subsystemstate: %s, %s, %lld, %lld, %lld",
- subsystem.name.c_str(), state.name.c_str(),
- (long long)state.residencyInMsecSinceBoot,
- (long long)state.totalTransitions,
- (long long)state.lastEntryTimestampMs);
- }
- }
+ [&data, wallClockTimestampNs, elapsedTimestampNs]
+ (hidl_vec<PowerStateSubsystem> subsystems, Status status) {
+ if (status != Status::SUCCESS) return;
+
+ if (subsystems.size() > 0) {
+ for (size_t i = 0; i < subsystems.size(); i++) {
+ const PowerStateSubsystem& subsystem = subsystems[i];
+ for (size_t j = 0; j < subsystem.states.size(); j++) {
+ const PowerStateSubsystemSleepState& state =
+ subsystem.states[j];
+ auto subsystemStatePtr = make_shared<LogEvent>(
+ android::util::SUBSYSTEM_SLEEP_STATE,
+ wallClockTimestampNs, elapsedTimestampNs);
+ subsystemStatePtr->write(subsystem.name);
+ subsystemStatePtr->write(state.name);
+ subsystemStatePtr->write(state.totalTransitions);
+ subsystemStatePtr->write(state.residencyInMsecSinceBoot);
+ subsystemStatePtr->init();
+ data->push_back(subsystemStatePtr);
+ VLOG("subsystemstate: %s, %s, %lld, %lld, %lld",
+ subsystem.name.c_str(), state.name.c_str(),
+ (long long)state.residencyInMsecSinceBoot,
+ (long long)state.totalTransitions,
+ (long long)state.lastEntryTimestampMs);
}
- });
+ }
+ }
+ });
}
- return true;
+ return true;
+}
+
+// The caller must be holding gPowerHalMutex.
+std::function<bool(vector<shared_ptr<LogEvent>>* data)> getPullerLocked() {
+ std::function<bool(vector<shared_ptr<LogEvent>>* data)> ret = {};
+
+ // First see if power.stats HAL is available. Fall back to power HAL if
+ // power.stats HAL is unavailable.
+ if(android::hardware::power::stats::V1_0::IPowerStats::getService() != nullptr) {
+ ALOGI("Using power.stats HAL");
+ ret = getIPowerStatsDataLocked;
+ } else if(android::hardware::power::V1_0::IPower::getService() != nullptr) {
+ ALOGI("Using power HAL");
+ ret = getIPowerDataLocked;
+ }
+
+ return ret;
+}
+
+bool SubsystemSleepStatePuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
+ std::lock_guard<std::mutex> lock(gPowerHalMutex);
+
+ if(!gPuller) {
+ gPuller = getPullerLocked();
+ }
+
+ if(gPuller) {
+ return gPuller(data);
+ }
+
+ ALOGE("Unable to load Power Hal or power.stats HAL");
+ return false;
}
} // namespace statsd
diff --git a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/Utils.java b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/Utils.java
index 597377e34ac3..8464b8df03d0 100644
--- a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/Utils.java
+++ b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/Utils.java
@@ -70,9 +70,16 @@ public class Utils {
/**
* Dumps the report from the device and converts it to a ConfigMetricsReportList.
* Erases the data if clearData is true.
+ * @param configId id of the config
+ * @param clearData whether to erase the report data from statsd after getting the report.
+ * @param useShellUid Pulls data for the {@link SHELL_UID} instead of the caller's uid.
+ * @param logger Logger to log error messages
+ * @return
+ * @throws IOException
+ * @throws InterruptedException
*/
public static ConfigMetricsReportList getReportList(long configId, boolean clearData,
- Logger logger) throws IOException, InterruptedException {
+ boolean useShellUid, Logger logger) throws IOException, InterruptedException {
try {
File outputFile = File.createTempFile("statsdret", ".bin");
outputFile.deleteOnExit();
@@ -82,7 +89,7 @@ public class Utils {
"adb",
"shell",
CMD_DUMP_REPORT,
- SHELL_UID,
+ useShellUid ? SHELL_UID : "",
String.valueOf(configId),
clearData ? "" : "--keep_data",
"--include_current_bucket",
@@ -93,8 +100,8 @@ public class Utils {
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
logger.severe("Failed to fetch and parse the statsd output report. "
+ "Perhaps there is not a valid statsd config for the requested "
- + "uid=" + SHELL_UID
- + ", configId=" + configId
+ + (useShellUid ? ("uid=" + SHELL_UID + ", ") : "")
+ + "configId=" + configId
+ ".");
throw (e);
}
diff --git a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/localdrive/LocalDrive.java b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/localdrive/LocalDrive.java
index 08074ede9d31..67fb906c2570 100644
--- a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/localdrive/LocalDrive.java
+++ b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/localdrive/LocalDrive.java
@@ -165,7 +165,7 @@ public class LocalDrive {
try {
Utils.runCommand(null, sLogger, "adb", "shell", Utils.CMD_REMOVE_CONFIG,
Utils.SHELL_UID, String.valueOf(configId));
- Utils.getReportList(configId, true /* clearData */, sLogger);
+ Utils.getReportList(configId, true /* clearData */, true /* SHELL_UID */, sLogger);
} catch (InterruptedException | IOException e) {
sLogger.severe("Failed to remove config: " + e.getMessage());
return false;
@@ -234,7 +234,7 @@ public class LocalDrive {
// Even if the args request no modifications, we still parse it to make sure it's valid.
ConfigMetricsReportList reportList;
try {
- reportList = Utils.getReportList(configId, clearData, sLogger);
+ reportList = Utils.getReportList(configId, clearData, true /* SHELL_UID */, sLogger);
} catch (IOException | InterruptedException e) {
sLogger.severe("Failed to get report list: " + e.getMessage());
return false;
@@ -278,7 +278,7 @@ public class LocalDrive {
sLogger.fine(String.format("cmdClear with %d", configId));
try {
- Utils.getReportList(configId, true /* clearData */, sLogger);
+ Utils.getReportList(configId, true /* clearData */, true /* SHELL_UID */, sLogger);
} catch (IOException | InterruptedException e) {
sLogger.severe("Failed to get report list: " + e.getMessage());
return false;
diff --git a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
index f7bd44aeab62..e3fe928a1309 100644
--- a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
+++ b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
@@ -165,7 +165,7 @@ public class TestDrive {
}
private void dumpMetrics() throws Exception {
- ConfigMetricsReportList reportList = Utils.getReportList(CONFIG_ID, true, logger);
+ ConfigMetricsReportList reportList = Utils.getReportList(CONFIG_ID, true, false, logger);
// We may get multiple reports. Take the last one.
ConfigMetricsReport report = reportList.getReports(reportList.getReportsCount() - 1);
// Really should be only one metric.
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index bacb991012fd..458c7decab5a 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -2861,7 +2861,6 @@ Lcom/android/internal/telephony/dataconnection/DataConnection;->mActivatingState
Lcom/android/internal/telephony/dataconnection/DataConnection;->mActiveState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcActiveState;
Lcom/android/internal/telephony/dataconnection/DataConnection;->mConnectionParams:Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;
Lcom/android/internal/telephony/dataconnection/DataConnection;->mDataRegState:I
-Lcom/android/internal/telephony/dataconnection/DataConnection;->mDcFailCause:Lcom/android/internal/telephony/dataconnection/DcFailCause;
Lcom/android/internal/telephony/dataconnection/DataConnection;->mDct:Lcom/android/internal/telephony/dataconnection/DcTracker;
Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectingErrorCreatingConnection:Lcom/android/internal/telephony/dataconnection/DataConnection$DcDisconnectionErrorCreatingConnection;
Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectingState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcDisconnectingState;
@@ -2872,10 +2871,8 @@ Lcom/android/internal/telephony/dataconnection/DataConnection;->mLinkProperties:
Lcom/android/internal/telephony/dataconnection/DataConnection;->mNetworkInfo:Landroid/net/NetworkInfo;
Lcom/android/internal/telephony/dataconnection/DataConnection;->mPhone:Lcom/android/internal/telephony/Phone;
Lcom/android/internal/telephony/dataconnection/DataConnection;->mRilRat:I
-Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllDisconnectCompleted(Lcom/android/internal/telephony/dataconnection/DcFailCause;)V
Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllOfConnected(Ljava/lang/String;)V
Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllOfDisconnectDcRetrying(Ljava/lang/String;)V
-Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyConnectCompleted(Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;Lcom/android/internal/telephony/dataconnection/DcFailCause;Z)V
Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyDisconnectCompleted(Lcom/android/internal/telephony/dataconnection/DataConnection$DisconnectParams;Z)V
Lcom/android/internal/telephony/dataconnection/DataConnection;->onConnect(Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;)V
Lcom/android/internal/telephony/dataconnection/DataConnection;->tearDownData(Ljava/lang/Object;)V
@@ -2884,22 +2881,6 @@ Lcom/android/internal/telephony/dataconnection/DcController;->lr(Ljava/lang/Stri
Lcom/android/internal/telephony/dataconnection/DcController;->mDcListActiveByCid:Ljava/util/HashMap;
Lcom/android/internal/telephony/dataconnection/DcController;->mDct:Lcom/android/internal/telephony/dataconnection/DcTracker;
Lcom/android/internal/telephony/dataconnection/DcController;->mDcTesterDeactivateAll:Lcom/android/internal/telephony/dataconnection/DcTesterDeactivateAll;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->ACTIVATION_REJECT_GGSN:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->ACTIVATION_REJECT_UNSPECIFIED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->APN_TYPE_CONFLICT:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->INSUFFICIENT_RESOURCES:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->MISSING_UNKNOWN_APN:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->NSAPI_IN_USE:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->ONLY_IPV4_ALLOWED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->ONLY_IPV6_ALLOWED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->ONLY_SINGLE_BEARER_ALLOWED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->OPERATOR_BARRED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->PROTOCOL_ERRORS:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->SERVICE_OPTION_NOT_SUBSCRIBED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->SERVICE_OPTION_NOT_SUPPORTED:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->SERVICE_OPTION_OUT_OF_ORDER:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->UNKNOWN_PDP_ADDRESS_TYPE:Lcom/android/internal/telephony/dataconnection/DcFailCause;
-Lcom/android/internal/telephony/dataconnection/DcFailCause;->USER_AUTHENTICATION:Lcom/android/internal/telephony/dataconnection/DcFailCause;
Lcom/android/internal/telephony/dataconnection/DcTracker$RecoveryAction;->isAggressiveRecovery(I)Z
Lcom/android/internal/telephony/dataconnection/DcTracker;->cancelReconnectAlarm(Lcom/android/internal/telephony/dataconnection/ApnContext;)V
Lcom/android/internal/telephony/dataconnection/DcTracker;->cleanUpAllConnections(Ljava/lang/String;)V
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 5e445d14a08b..b584d5d4c3b4 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2545,7 +2545,7 @@ public class Activity extends ContextThemeWrapper
* picture-in-picture.
*
* @return true if the system successfully put this activity into picture-in-picture mode or was
- * already in picture-in-picture mode (@see {@link #isInPictureInPictureMode()). If the device
+ * already in picture-in-picture mode (see {@link #isInPictureInPictureMode()}). If the device
* does not support picture-in-picture, return false.
*/
public boolean enterPictureInPictureMode(@NonNull PictureInPictureParams params) {
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index f928501b7c1a..b42d53ad10f6 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -306,6 +306,6 @@ public abstract class ActivityManagerInternal {
public abstract void setDebugFlagsForStartingActivity(ActivityInfo aInfo, int startFlags,
ProfilerInfo profilerInfo, Object wmLock);
- /** Checks if process running with given pid has access to full external storage or not */
- public abstract boolean isAppStorageSandboxed(int pid, int uid);
+ /** Returns mount mode for process running with given pid */
+ public abstract int getStorageMountMode(int pid, int uid);
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 67d9ad6e93c6..2b81c86e1b0d 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -44,6 +44,7 @@ import android.content.pm.InstantAppInfo;
import android.content.pm.InstrumentationInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.KeySet;
+import android.content.pm.ModuleInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageItemInfo;
@@ -791,6 +792,16 @@ public class ApplicationPackageManager extends PackageManager {
throw new NameNotFoundException("No shared userid for user:"+sharedUserName);
}
+ @Override
+ public List<ModuleInfo> getInstalledModules(int flags) {
+ return null;
+ }
+
+ @Override
+ public ModuleInfo getModuleInfo(String packageName, int flags) throws NameNotFoundException {
+ return null;
+ }
+
@SuppressWarnings("unchecked")
@Override
public List<PackageInfo> getInstalledPackages(int flags) {
diff --git a/core/java/android/app/RemoteInput.java b/core/java/android/app/RemoteInput.java
index ebbf317ad05d..392921e813f9 100644
--- a/core/java/android/app/RemoteInput.java
+++ b/core/java/android/app/RemoteInput.java
@@ -173,7 +173,7 @@ public final class RemoteInput implements Parcelable {
/**
* Returns true if the input only accepts data, meaning {@link #getAllowFreeFormInput}
- * is false, {@link #getChoices} is null or empty, and {@link #getAllowedDataTypes is
+ * is false, {@link #getChoices} is null or empty, and {@link #getAllowedDataTypes} is
* non-null and not empty.
*/
public boolean isDataOnly() {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 43e183665435..f4fd5d132069 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -154,7 +154,7 @@ import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.euicc.EuiccCardManager;
import android.telephony.euicc.EuiccManager;
-import android.telephony.rcs.RcsManager;
+import android.telephony.ims.RcsManager;
import android.util.ArrayMap;
import android.util.Log;
import android.view.ContextThemeWrapper;
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index ca60e140ba8e..0ccd49f2e028 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -209,7 +209,7 @@ public abstract class SliceProvider extends ContentProvider {
*
* @param sliceUri Uri to bind.
* @param supportedSpecs List of supported specs.
- * @see Slice.
+ * @see Slice
* @see Slice#HINT_PARTIAL
*/
public Slice onBindSlice(Uri sliceUri, Set<SliceSpec> supportedSpecs) {
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 5a12e4ecca1b..8b973946eafa 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -1182,12 +1182,12 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
* Implement this to handle query requests where the arguments are packed into a {@link Bundle}.
* Arguments may include traditional SQL style query arguments. When present these
* should be handled according to the contract established in
- * {@link #query(Uri, String[], String, String[], String, CancellationSignal).
+ * {@link #query(Uri, String[], String, String[], String, CancellationSignal)}.
*
* <p>Traditional SQL arguments can be found in the bundle using the following keys:
- * <li>{@link ContentResolver#QUERY_ARG_SQL_SELECTION}
- * <li>{@link ContentResolver#QUERY_ARG_SQL_SELECTION_ARGS}
- * <li>{@link ContentResolver#QUERY_ARG_SQL_SORT_ORDER}
+ * <li>{@link android.content.ContentResolver#QUERY_ARG_SQL_SELECTION}
+ * <li>{@link android.content.ContentResolver#QUERY_ARG_SQL_SELECTION_ARGS}
+ * <li>{@link android.content.ContentResolver#QUERY_ARG_SQL_SORT_ORDER}
*
* <p>This method can be called from multiple threads, as described in
* <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
@@ -1244,8 +1244,8 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
return cursor;</pre>
* <p>
- * @see #query(Uri, String[], String, String[], String, CancellationSignal) for
- * implementation details.
+ * See {@link #query(Uri, String[], String, String[], String, CancellationSignal)}
+ * for implementation details.
*
* @param uri The URI to query. This will be the full URI sent by the client.
* @param projection The list of columns to put into the cursor.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index d7d3cb543af9..b39010d9d14e 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4462,7 +4462,7 @@ public abstract class Context {
/**
* Use with {@link #getSystemService(String)} to retrieve an
- * {@link android.telephony.rcs.RcsManager}.
+ * {@link android.telephony.ims.RcsManager}.
* @hide
*/
public static final String TELEPHONY_RCS_SERVICE = "ircs";
diff --git a/core/java/android/content/pm/ModuleInfo.java b/core/java/android/content/pm/ModuleInfo.java
new file mode 100644
index 000000000000..07e640b1ba61
--- /dev/null
+++ b/core/java/android/content/pm/ModuleInfo.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Information you can retrieve about a particular system
+ * module.
+ */
+public final class ModuleInfo implements Parcelable {
+
+ // NOTE: When adding new data members be sure to update the copy-constructor, Parcel
+ // constructor, and writeToParcel.
+
+ /** Public name of this module. */
+ private String mName;
+
+ /** The package name of this module. */
+ private String mPackageName;
+
+ /** Whether or not this module is hidden from the user. */
+ private boolean mHidden;
+
+ // TODO: Decide whether we need an additional metadata bundle to support out of band
+ // updates to ModuleInfo.
+ //
+ // private Bundle mMetadata;
+
+ /** @hide */
+ public ModuleInfo() {
+ }
+
+ /** @hide */
+ public ModuleInfo(ModuleInfo orig) {
+ mName = orig.mName;
+ mPackageName = orig.mPackageName;
+ mHidden = orig.mHidden;
+ }
+
+ /** @hide Sets the public name of this module. */
+ public ModuleInfo setName(String name) {
+ mName = name;
+ return this;
+ }
+
+ /** Gets the public name of this module. */
+ public @Nullable String getName() {
+ return mName;
+ }
+
+ /** @hide Sets the package name of this module. */
+ public ModuleInfo setPackageName(String packageName) {
+ mPackageName = packageName;
+ return this;
+ }
+
+ /** Gets the package name of this module. */
+ public @Nullable String getPackageName() {
+ return mPackageName;
+ }
+
+ /** @hide Sets whether or not this package is hidden. */
+ public ModuleInfo setHidden(boolean hidden) {
+ mHidden = hidden;
+ return this;
+ }
+
+ /** Gets whether or not this package is hidden. */
+ public boolean isHidden() {
+ return mHidden;
+ }
+
+ /** Returns a string representation of this object. */
+ public String toString() {
+ return "ModuleInfo{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " " + mName + "}";
+ }
+
+ /** Describes the kinds of special objects contained in this object. */
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public int hashCode() {
+ int hashCode = 0;
+ hashCode = 31 * hashCode + Objects.hashCode(mName);
+ hashCode = 31 * hashCode + Objects.hashCode(mPackageName);
+ hashCode = 31 * hashCode + Boolean.hashCode(mHidden);
+ return hashCode;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ModuleInfo)) {
+ return false;
+ }
+ final ModuleInfo other = (ModuleInfo) obj;
+ return Objects.equals(mName, other.mName)
+ && Objects.equals(mPackageName, other.mPackageName)
+ && mHidden == other.mHidden;
+ }
+
+ /** Flattens this object into the given {@link Parcel}. */
+ public void writeToParcel(Parcel dest, int parcelableFlags) {
+ dest.writeString(mName);
+ dest.writeString(mPackageName);
+ dest.writeBoolean(mHidden);
+ }
+
+ private ModuleInfo(Parcel source) {
+ mName = source.readString();
+ mPackageName = source.readString();
+ mHidden = source.readBoolean();
+ }
+
+ public static final Parcelable.Creator<ModuleInfo> CREATOR =
+ new Parcelable.Creator<ModuleInfo>() {
+ public ModuleInfo createFromParcel(Parcel source) {
+ return new ModuleInfo(source);
+ }
+ public ModuleInfo[] newArray(int size) {
+ return new ModuleInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 34cdfee3f959..566017b7372e 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -220,6 +220,12 @@ public abstract class PackageManager {
/** @hide */
@IntDef(flag = true, prefix = { "GET_", "MATCH_" }, value = {
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ModuleInfoFlags {}
+
+ /** @hide */
+ @IntDef(flag = true, prefix = { "GET_", "MATCH_" }, value = {
GET_META_DATA,
})
@Retention(RetentionPolicy.SOURCE)
@@ -3467,6 +3473,35 @@ public abstract class PackageManager {
@ComponentInfoFlags int flags) throws NameNotFoundException;
/**
+ * Retrieve information for a particular module.
+ *
+ * @param packageName The name of the module.
+ * @param flags Additional option flags to modify the data returned.
+ * @return A {@link ModuleInfo} object containing information about the
+ * module.
+ * @throws NameNotFoundException if a module with the given name cannot be
+ * found on the system.
+ */
+ public ModuleInfo getModuleInfo(String packageName, @ModuleInfoFlags int flags)
+ throws NameNotFoundException {
+ throw new UnsupportedOperationException(
+ "getModuleInfo not implemented in subclass");
+ }
+
+ /**
+ * Return a List of all modules that are installed.
+ *
+ * @param flags Additional option flags to modify the data returned.
+ * @return A {@link List} of {@link ModuleInfo} objects, one for each installed
+ * module, containing information about the module. In the unlikely case
+ * there are no installed modules, an empty list is returned.
+ */
+ public @NonNull List<ModuleInfo> getInstalledModules(@ModuleInfoFlags int flags) {
+ throw new UnsupportedOperationException(
+ "getInstalledModules not implemented in subclass");
+ }
+
+ /**
* Return a List of all packages that are installed for the current user.
*
* @param flags Additional option flags to modify the data returned.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 17ce79b83aa8..0a60764428dc 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1515,11 +1515,11 @@ public class UserManager {
* background user; the result here does not distinguish between the two.
*
* <p>Note prior to Android Nougat MR1 (SDK version <= 24;
- * {@link android.os.Build.VERSION_CODES#N), this API required a system permission
+ * {@link android.os.Build.VERSION_CODES#N}, this API required a system permission
* in order to check other profile's status.
* Since Android Nougat MR1 (SDK version >= 25;
- * {@link android.os.Build.VERSION_CODES#N_MR1)), the restriction has been relaxed, and now
- * it'll accept any {@link UserHandle} within the same profile group as the caller.
+ * {@link android.os.Build.VERSION_CODES#N_MR1}), the restriction has been relaxed, and now
+ * it'll accept any {@link android.os.UserHandle} within the same profile group as the caller.
*
* @param user The user to retrieve the running state for.
*/
@@ -1544,11 +1544,11 @@ public class UserManager {
* (but is not yet fully stopped, and still running some code).
*
* <p>Note prior to Android Nougat MR1 (SDK version <= 24;
- * {@link android.os.Build.VERSION_CODES#N), this API required a system permission
+ * {@link android.os.Build.VERSION_CODES#N}, this API required a system permission
* in order to check other profile's status.
* Since Android Nougat MR1 (SDK version >= 25;
- * {@link android.os.Build.VERSION_CODES#N_MR1)), the restriction has been relaxed, and now
- * it'll accept any {@link UserHandle} within the same profile group as the caller.
+ * {@link android.os.Build.VERSION_CODES#N_MR1}), the restriction has been relaxed, and now
+ * it'll accept any {@link android.os.UserHandle} within the same profile group as the caller.
*
* @param user The user to retrieve the running state for.
*/
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 7fd0a4b66d66..f136cd6699a7 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -398,6 +398,8 @@ public class ZygoteProcess {
argsForZygote.add("--mount-external-write");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_FULL) {
argsForZygote.add("--mount-external-full");
+ } else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
+ argsForZygote.add("--mount-external-installer");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index a8726e9de3d0..cd991cc0d6fc 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -1275,7 +1275,7 @@ public final class DocumentsContract {
}
}
- /** @removed */
+ @Deprecated
public static Bitmap getDocumentThumbnail(ContentResolver content, Uri documentUri, Point size,
CancellationSignal signal) throws FileNotFoundException {
return getDocumentThumbnail((ContentInterface) content, documentUri, size, signal);
@@ -1307,7 +1307,7 @@ public final class DocumentsContract {
}
}
- /** @removed */
+ @Deprecated
public static Uri createDocument(ContentResolver content, Uri parentDocumentUri,
String mimeType, String displayName) throws FileNotFoundException {
return createDocument((ContentInterface) content, parentDocumentUri, mimeType, displayName);
@@ -1345,7 +1345,7 @@ public final class DocumentsContract {
}
}
- /** @removed */
+ @Deprecated
public static boolean isChildDocument(ContentResolver content, Uri parentDocumentUri,
Uri childDocumentUri) throws FileNotFoundException {
return isChildDocument((ContentInterface) content, parentDocumentUri, childDocumentUri);
@@ -1382,7 +1382,7 @@ public final class DocumentsContract {
}
}
- /** @removed */
+ @Deprecated
public static Uri renameDocument(ContentResolver content, Uri documentUri,
String displayName) throws FileNotFoundException {
return renameDocument((ContentInterface) content, documentUri, displayName);
@@ -1410,7 +1410,7 @@ public final class DocumentsContract {
}
}
- /** @removed */
+ @Deprecated
public static boolean deleteDocument(ContentResolver content, Uri documentUri)
throws FileNotFoundException {
return deleteDocument((ContentInterface) content, documentUri);
@@ -1441,7 +1441,7 @@ public final class DocumentsContract {
}
}
- /** @removed */
+ @Deprecated
public static Uri copyDocument(ContentResolver content, Uri sourceDocumentUri,
Uri targetParentDocumentUri) throws FileNotFoundException {
return copyDocument((ContentInterface) content, sourceDocumentUri, targetParentDocumentUri);
@@ -1474,7 +1474,7 @@ public final class DocumentsContract {
}
}
- /** @removed */
+ @Deprecated
public static Uri moveDocument(ContentResolver content, Uri sourceDocumentUri,
Uri sourceParentDocumentUri, Uri targetParentDocumentUri) throws FileNotFoundException {
return moveDocument((ContentInterface) content, sourceDocumentUri, sourceParentDocumentUri,
@@ -1508,7 +1508,7 @@ public final class DocumentsContract {
}
}
- /** @removed */
+ @Deprecated
public static boolean removeDocument(ContentResolver content, Uri documentUri,
Uri parentDocumentUri) throws FileNotFoundException {
return removeDocument((ContentInterface) content, documentUri, parentDocumentUri);
@@ -1531,7 +1531,7 @@ public final class DocumentsContract {
}
}
- /** @removed */
+ @Deprecated
public static void ejectRoot(ContentResolver content, Uri rootUri) {
ejectRoot((ContentInterface) content, rootUri);
}
@@ -1581,7 +1581,7 @@ public final class DocumentsContract {
}
}
- /** @removed */
+ @Deprecated
public static Bundle getDocumentMetadata(ContentResolver content, Uri documentUri)
throws FileNotFoundException {
return getDocumentMetadata((ContentInterface) content, documentUri);
@@ -1618,7 +1618,7 @@ public final class DocumentsContract {
}
}
- /** @removed */
+ @Deprecated
public static Path findDocumentPath(ContentResolver content, Uri treeUri)
throws FileNotFoundException {
return findDocumentPath((ContentInterface) content, treeUri);
@@ -1697,7 +1697,7 @@ public final class DocumentsContract {
}
}
- /** @removed */
+ @Deprecated
public static IntentSender createWebLinkIntent(ContentResolver content, Uri uri,
Bundle options) throws FileNotFoundException {
return createWebLinkIntent((ContentInterface) content, uri, options);
diff --git a/core/java/android/text/style/ImageSpan.java b/core/java/android/text/style/ImageSpan.java
index d4edde9ec589..13ac9ff2ddaf 100644
--- a/core/java/android/text/style/ImageSpan.java
+++ b/core/java/android/text/style/ImageSpan.java
@@ -259,7 +259,8 @@ public class ImageSpan extends DynamicDrawableSpan {
* Returns the source string that was saved during construction.
*
* @return the source string that was saved during construction
- * @see #ImageSpan(Drawable, String) and this{@link #ImageSpan(Context, Uri)}
+ * @see #ImageSpan(Drawable, String)
+ * @see #ImageSpan(Context, Uri)
*/
@Nullable
public String getSource() {
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 1889692ea831..cc0264ac0bc9 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -31,7 +31,9 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.util.Log;
+import android.util.TimeUtils;
import android.view.View;
import android.view.ViewStructure;
import android.view.autofill.AutofillId;
@@ -98,6 +100,12 @@ public final class ContentCaptureManager {
*/
public static final int STATE_DISABLED = 3;
+ /**
+ * Handler message used to flush the buffer.
+ */
+ private static final int MSG_FLUSH = 1;
+
+
private static final String BG_THREAD_NAME = "intel_svc_streamer_thread";
/**
@@ -106,6 +114,12 @@ public final class ContentCaptureManager {
// TODO(b/111276913): use settings
private static final int MAX_BUFFER_SIZE = 100;
+ /**
+ * Frequency the buffer is flushed if stale.
+ */
+ // TODO(b/111276913): use settings
+ private static final int FLUSHING_FREQUENCY_MS = 5_000;
+
@NonNull
private final AtomicBoolean mDisabled = new AtomicBoolean();
@@ -136,6 +150,9 @@ public final class ContentCaptureManager {
// held at the Application level
private final Handler mHandler;
+ // Used just for debugging purposes (on dump)
+ private long mNextFlush;
+
/** @hide */
public ContentCaptureManager(@NonNull Context context,
@Nullable IContentCaptureManager service) {
@@ -207,9 +224,17 @@ public final class ContentCaptureManager {
mEvents = new ArrayList<>(MAX_BUFFER_SIZE);
}
mEvents.add(event);
+
final int numberEvents = mEvents.size();
- if (numberEvents < MAX_BUFFER_SIZE && !forceFlush) {
- // Buffering events, return right away...
+
+ // TODO(b/120784831): need to optimize it so we buffer changes until a number of X are
+ // buffered (either total or per autofillid). For
+ // example, if the user typed "a", "b", "c" and the threshold is 3, we should buffer
+ // "a" and "b" then send "abc".
+ final boolean bufferEvent = numberEvents < MAX_BUFFER_SIZE;
+
+ if (bufferEvent && !forceFlush) {
+ handleScheduleFlush();
return;
}
@@ -236,10 +261,38 @@ public final class ContentCaptureManager {
return;
}
+ handleForceFlush();
+ }
+
+ private void handleScheduleFlush() {
+ if (mHandler.hasMessages(MSG_FLUSH)) {
+ // "Renew" the flush message by removing the previous one
+ mHandler.removeMessages(MSG_FLUSH);
+ }
+ mNextFlush = SystemClock.elapsedRealtime() + FLUSHING_FREQUENCY_MS;
+ if (VERBOSE) {
+ Log.v(TAG, "Scheduled to flush in " + FLUSHING_FREQUENCY_MS + "ms: " + mNextFlush);
+ }
+ mHandler.sendMessageDelayed(
+ obtainMessage(ContentCaptureManager::handleFlushIfNeeded, this).setWhat(MSG_FLUSH),
+ FLUSHING_FREQUENCY_MS);
+ }
+
+ private void handleFlushIfNeeded() {
+ if (mEvents.isEmpty()) {
+ if (VERBOSE) Log.v(TAG, "Nothing to flush");
+ return;
+ }
+ handleForceFlush();
+ }
+
+ private void handleForceFlush() {
+ final int numberEvents = mEvents.size();
try {
if (DEBUG) {
Log.d(TAG, "Flushing " + numberEvents + " event(s) for " + getActivityDebugName());
}
+ mHandler.removeMessages(MSG_FLUSH);
mService.sendEvents(mContext.getUserId(), mId, mEvents);
// TODO(b/111276913): decide whether we should clear or set it to null, as each has
// its own advantages: clearing will save extra allocations while the session is
@@ -307,6 +360,7 @@ public final class ContentCaptureManager {
mApplicationToken = null;
mComponentName = null;
mEvents = null;
+ mHandler.removeMessages(MSG_FLUSH);
}
/**
@@ -443,7 +497,7 @@ public final class ContentCaptureManager {
pw.print(prefix2); pw.print("component name: ");
pw.println(mComponentName.flattenToShortString());
}
- if (mEvents != null) {
+ if (mEvents != null && !mEvents.isEmpty()) {
final int numberEvents = mEvents.size();
pw.print(prefix2); pw.print("buffered events: "); pw.print(numberEvents);
pw.print('/'); pw.println(MAX_BUFFER_SIZE);
@@ -455,6 +509,9 @@ public final class ContentCaptureManager {
pw.println();
}
}
+ pw.print(prefix2); pw.print("flush frequency: "); pw.println(FLUSHING_FREQUENCY_MS);
+ pw.print(prefix2); pw.print("next flush: ");
+ TimeUtils.formatDuration(mNextFlush - SystemClock.elapsedRealtime(), pw); pw.println();
}
}
diff --git a/core/java/com/android/internal/app/procstats/AssociationState.java b/core/java/com/android/internal/app/procstats/AssociationState.java
index 3842f6659704..4da339165655 100644
--- a/core/java/com/android/internal/app/procstats/AssociationState.java
+++ b/core/java/com/android/internal/app/procstats/AssociationState.java
@@ -445,8 +445,18 @@ public final class AssociationState {
}
}
+ public boolean hasProcess(String procName) {
+ final int NSRC = mSources.size();
+ for (int isrc = 0; isrc < NSRC; isrc++) {
+ if (mSources.keyAt(isrc).mProcess.equals(procName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public void dumpStats(PrintWriter pw, String prefix, String prefixInner, String headerPrefix,
- long now, long totalTime, boolean dumpDetails, boolean dumpAll) {
+ long now, long totalTime, String reqPackage, boolean dumpDetails, boolean dumpAll) {
if (dumpAll) {
pw.print(prefix);
pw.print("mNumActive=");
@@ -456,6 +466,9 @@ public final class AssociationState {
for (int isrc = 0; isrc < NSRC; isrc++) {
final SourceKey key = mSources.keyAt(isrc);
final SourceState src = mSources.valueAt(isrc);
+ if (reqPackage != null && !reqPackage.equals(key.mProcess)) {
+ continue;
+ }
pw.print(prefixInner);
pw.print("<- ");
pw.print(key.mProcess);
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
index 19d8a836fc4c..9ee583a97b8d 100644
--- a/core/java/com/android/internal/app/procstats/ProcessStats.java
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -1396,10 +1396,10 @@ public final class ProcessStats implements Parcelable {
return as;
}
- // See b/118826162 -- to avoid logspaming, we rate limit the WTF.
- private static final long INVERSE_PROC_STATE_WTF_MIN_INTERVAL_MS = 10_000L;
- private long mNextInverseProcStateWtfUptime;
- private int mSkippedInverseProcStateWtfCount;
+ // See b/118826162 -- to avoid logspaming, we rate limit the warnings.
+ private static final long INVERSE_PROC_STATE_WARNING_MIN_INTERVAL_MS = 10_000L;
+ private long mNextInverseProcStateWarningUptime;
+ private int mSkippedInverseProcStateWarningCount;
public void updateTrackingAssociationsLocked(int curSeq, long now) {
final int NUM = mTrackingAssociations.size();
@@ -1423,18 +1423,19 @@ public final class ProcessStats implements Parcelable {
act.stopActive(now);
if (act.mProcState < procState) {
final long nowUptime = SystemClock.uptimeMillis();
- if (mNextInverseProcStateWtfUptime > nowUptime) {
- mSkippedInverseProcStateWtfCount++;
+ if (mNextInverseProcStateWarningUptime > nowUptime) {
+ mSkippedInverseProcStateWarningCount++;
} else {
// TODO We still see it during boot related to GMS-core.
// b/118826162
- Slog.wtf(TAG, "Tracking association " + act + " whose proc state "
+ Slog.w(TAG, "Tracking association " + act + " whose proc state "
+ act.mProcState + " is better than process " + proc
+ " proc state " + procState
- + " (" + mSkippedInverseProcStateWtfCount + " skipped)");
- mSkippedInverseProcStateWtfCount = 0;
- mNextInverseProcStateWtfUptime =
- nowUptime + INVERSE_PROC_STATE_WTF_MIN_INTERVAL_MS;
+ + " (" + mSkippedInverseProcStateWarningCount
+ + " skipped)");
+ mSkippedInverseProcStateWarningCount = 0;
+ mNextInverseProcStateWarningUptime =
+ nowUptime + INVERSE_PROC_STATE_WARNING_MIN_INTERVAL_MS;
}
}
}
@@ -1474,6 +1475,7 @@ public final class ProcessStats implements Parcelable {
final int NSRVS = pkgState.mServices.size();
final int NASCS = pkgState.mAssociations.size();
final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
+ boolean onlyAssociations = false;
if (!pkgMatch) {
boolean procMatch = false;
for (int iproc = 0; iproc < NPROCS; iproc++) {
@@ -1484,7 +1486,18 @@ public final class ProcessStats implements Parcelable {
}
}
if (!procMatch) {
- continue;
+ // Check if this app has any associations with the requested
+ // package, so that if so we print those.
+ for (int iasc = 0; iasc < NASCS; iasc++) {
+ AssociationState asc = pkgState.mAssociations.valueAt(iasc);
+ if (asc.hasProcess(reqPackage)) {
+ onlyAssociations = true;
+ break;
+ }
+ }
+ if (!onlyAssociations) {
+ continue;
+ }
}
}
if (NPROCS > 0 || NSRVS > 0 || NASCS > 0) {
@@ -1502,7 +1515,7 @@ public final class ProcessStats implements Parcelable {
pw.print(vers);
pw.println(":");
}
- if ((section & REPORT_PKG_PROC_STATS) != 0) {
+ if ((section & REPORT_PKG_PROC_STATS) != 0 && !onlyAssociations) {
if (!dumpSummary || dumpAll) {
for (int iproc = 0; iproc < NPROCS; iproc++) {
ProcessState proc = pkgState.mProcesses.valueAt(iproc);
@@ -1549,7 +1562,7 @@ public final class ProcessStats implements Parcelable {
now, totalTime);
}
}
- if ((section & REPORT_PKG_SVC_STATS) != 0) {
+ if ((section & REPORT_PKG_SVC_STATS) != 0 && !onlyAssociations) {
for (int isvc = 0; isvc < NSRVS; isvc++) {
ServiceState svc = pkgState.mServices.valueAt(isvc);
if (!pkgMatch && !reqPackage.equals(svc.getProcessName())) {
@@ -1578,7 +1591,9 @@ public final class ProcessStats implements Parcelable {
for (int iasc = 0; iasc < NASCS; iasc++) {
AssociationState asc = pkgState.mAssociations.valueAt(iasc);
if (!pkgMatch && !reqPackage.equals(asc.getProcessName())) {
- continue;
+ if (!onlyAssociations || !asc.hasProcess(reqPackage)) {
+ continue;
+ }
}
if (activeOnly && !asc.isInUse()) {
pw.print(" (Not active association: ");
@@ -1596,7 +1611,8 @@ public final class ProcessStats implements Parcelable {
pw.print(" Process: ");
pw.println(asc.getProcessName());
asc.dumpStats(pw, " ", " ", " ",
- now, totalTime, dumpDetails, dumpAll);
+ now, totalTime, onlyAssociations ? reqPackage : null,
+ dumpDetails, dumpAll);
}
}
}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 65213c0a1085..65b9fad97d89 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -81,6 +81,11 @@ public final class Zygote {
public static final int MOUNT_EXTERNAL_READ = IVold.REMOUNT_MODE_READ;
/** Read-write external storage should be mounted. */
public static final int MOUNT_EXTERNAL_WRITE = IVold.REMOUNT_MODE_WRITE;
+ /**
+ * Mount mode for package installers which should give them access to
+ * all obb dirs in addition to their package sandboxes
+ */
+ public static final int MOUNT_EXTERNAL_INSTALLER = IVold.REMOUNT_MODE_INSTALLER;
/** Read-write external storage should be mounted instead of package sandbox */
public static final int MOUNT_EXTERNAL_FULL = IVold.REMOUNT_MODE_FULL;
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 4a94ec4a4071..f182c4d447df 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -656,7 +656,9 @@ class ZygoteConnection {
mountExternal = Zygote.MOUNT_EXTERNAL_WRITE;
} else if (arg.equals("--mount-external-full")) {
mountExternal = Zygote.MOUNT_EXTERNAL_FULL;
- } else if (arg.equals("--query-abi-list")) {
+ } else if (arg.equals("--mount-external-installer")) {
+ mountExternal = Zygote.MOUNT_EXTERNAL_INSTALLER;
+ } else if (arg.equals("--query-abi-list")) {
abiListQuery = true;
} else if (arg.equals("--get-pid")) {
pidQuery = true;
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index 151901be7b5b..470533f2d002 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -326,4 +326,8 @@ public class CollectionUtils {
throw ExceptionUtils.propagate(e);
}
}
+
+ public static @NonNull <T> List<T> defeatNullable(@Nullable List<T> val) {
+ return (val != null) ? val : Collections.emptyList();
+ }
}
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 2e674a5892c6..841e5b679f5f 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -67,6 +67,7 @@ public class SystemConfig {
private static final int ALLOW_PRIVAPP_PERMISSIONS = 0x10;
private static final int ALLOW_OEM_PERMISSIONS = 0x20;
private static final int ALLOW_HIDDENAPI_WHITELISTING = 0x40;
+ private static final int ALLOW_ASSOCIATIONS = 0x80;
private static final int ALLOW_ALL = ~0;
// property for runtime configuration differentiation
@@ -195,6 +196,12 @@ public class SystemConfig {
final ArrayMap<String, ArrayMap<String, Boolean>> mOemPermissions = new ArrayMap<>();
+ // Allowed associations between applications. If there are any entries
+ // for an app, those are the only associations allowed; otherwise, all associations
+ // are allowed. Allowing an association from app A to app B means app A can not
+ // associate with any other apps, but does not limit what apps B can associate with.
+ final ArrayMap<String, ArraySet<String>> mAllowedAssociations = new ArrayMap<>();
+
public static SystemConfig getInstance() {
synchronized (SystemConfig.class) {
if (sInstance == null) {
@@ -320,6 +327,10 @@ public class SystemConfig {
return Collections.emptyMap();
}
+ public ArrayMap<String, ArraySet<String>> getAllowedAssociations() {
+ return mAllowedAssociations;
+ }
+
SystemConfig() {
// Read configuration from system
readPermissions(Environment.buildPath(
@@ -329,8 +340,9 @@ public class SystemConfig {
readPermissions(Environment.buildPath(
Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
- // Vendors are only allowed to customze libs, features and privapp permissions
- int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS;
+ // Vendors are only allowed to customize these
+ int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS
+ | ALLOW_ASSOCIATIONS;
if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.O_MR1) {
// For backward compatibility
vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS);
@@ -359,8 +371,8 @@ public class SystemConfig {
odmPermissionFlag);
}
- // Allow OEM to customize features and OEM permissions
- int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS;
+ // Allow OEM to customize these
+ int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS;
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag);
readPermissions(Environment.buildPath(
@@ -423,6 +435,11 @@ public class SystemConfig {
}
}
+ private void logNotAllowedInPartition(String name, File permFile, XmlPullParser parser) {
+ Slog.w(TAG, "<" + name + "> not allowed in partition of "
+ + permFile + " at " + parser.getPositionDescription());
+ }
+
private void readPermissionsFromXml(File permFile, int permissionFlag) {
FileReader permReader = null;
try {
@@ -453,14 +470,17 @@ public class SystemConfig {
+ ": found " + parser.getName() + ", expected 'permissions' or 'config'");
}
- boolean allowAll = permissionFlag == ALLOW_ALL;
- boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0;
- boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0;
- boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0;
- boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0;
- boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS) != 0;
- boolean allowOemPermissions = (permissionFlag & ALLOW_OEM_PERMISSIONS) != 0;
- boolean allowApiWhitelisting = (permissionFlag & ALLOW_HIDDENAPI_WHITELISTING) != 0;
+ final boolean allowAll = permissionFlag == ALLOW_ALL;
+ final boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0;
+ final boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0;
+ final boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0;
+ final boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0;
+ final boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS)
+ != 0;
+ final boolean allowOemPermissions = (permissionFlag & ALLOW_OEM_PERMISSIONS) != 0;
+ final boolean allowApiWhitelisting = (permissionFlag & ALLOW_HIDDENAPI_WHITELISTING)
+ != 0;
+ final boolean allowAssociations = (permissionFlag & ALLOW_ASSOCIATIONS) != 0;
while (true) {
XmlUtils.nextElement(parser);
if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
@@ -468,297 +488,425 @@ public class SystemConfig {
}
String name = parser.getName();
- if ("group".equals(name) && allowAll) {
- String gidStr = parser.getAttributeValue(null, "gid");
- if (gidStr != null) {
- int gid = android.os.Process.getGidForName(gidStr);
- mGlobalGids = appendInt(mGlobalGids, gid);
- } else {
- Slog.w(TAG, "<group> without gid in " + permFile + " at "
- + parser.getPositionDescription());
- }
-
+ if (name == null) {
XmlUtils.skipCurrentTag(parser);
continue;
- } else if ("permission".equals(name) && allowPermissions) {
- String perm = parser.getAttributeValue(null, "name");
- if (perm == null) {
- Slog.w(TAG, "<permission> without name in " + permFile + " at "
- + parser.getPositionDescription());
+ }
+ switch (name) {
+ case "group": {
+ if (allowAll) {
+ String gidStr = parser.getAttributeValue(null, "gid");
+ if (gidStr != null) {
+ int gid = android.os.Process.getGidForName(gidStr);
+ mGlobalGids = appendInt(mGlobalGids, gid);
+ } else {
+ Slog.w(TAG, "<" + name + "> without gid in " + permFile + " at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ }
XmlUtils.skipCurrentTag(parser);
- continue;
- }
- perm = perm.intern();
- readPermission(parser, perm);
-
- } else if ("assign-permission".equals(name) && allowPermissions) {
- String perm = parser.getAttributeValue(null, "name");
- if (perm == null) {
- Slog.w(TAG, "<assign-permission> without name in " + permFile + " at "
- + parser.getPositionDescription());
+ } break;
+ case "permission": {
+ if (allowPermissions) {
+ String perm = parser.getAttributeValue(null, "name");
+ if (perm == null) {
+ Slog.w(TAG, "<" + name + "> without name in " + permFile + " at "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ break;
+ }
+ perm = perm.intern();
+ readPermission(parser, perm);
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ XmlUtils.skipCurrentTag(parser);
+ }
+ } break;
+ case "assign-permission": {
+ if (allowPermissions) {
+ String perm = parser.getAttributeValue(null, "name");
+ if (perm == null) {
+ Slog.w(TAG, "<" + name + "> without name in " + permFile
+ + " at " + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ break;
+ }
+ String uidStr = parser.getAttributeValue(null, "uid");
+ if (uidStr == null) {
+ Slog.w(TAG, "<" + name + "> without uid in " + permFile
+ + " at " + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ break;
+ }
+ int uid = Process.getUidForName(uidStr);
+ if (uid < 0) {
+ Slog.w(TAG, "<" + name + "> with unknown uid \""
+ + uidStr + " in " + permFile + " at "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ break;
+ }
+ perm = perm.intern();
+ ArraySet<String> perms = mSystemPermissions.get(uid);
+ if (perms == null) {
+ perms = new ArraySet<String>();
+ mSystemPermissions.put(uid, perms);
+ }
+ perms.add(perm);
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ }
XmlUtils.skipCurrentTag(parser);
- continue;
- }
- String uidStr = parser.getAttributeValue(null, "uid");
- if (uidStr == null) {
- Slog.w(TAG, "<assign-permission> without uid in " + permFile + " at "
- + parser.getPositionDescription());
+ } break;
+ case "split-permission": {
+ if (allowPermissions) {
+ readSplitPermission(parser, permFile);
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ XmlUtils.skipCurrentTag(parser);
+ }
+ } break;
+ case "library": {
+ if (allowLibs) {
+ String lname = parser.getAttributeValue(null, "name");
+ String lfile = parser.getAttributeValue(null, "file");
+ String ldependency = parser.getAttributeValue(null, "dependency");
+ if (lname == null) {
+ Slog.w(TAG, "<" + name + "> without name in " + permFile + " at "
+ + parser.getPositionDescription());
+ } else if (lfile == null) {
+ Slog.w(TAG, "<" + name + "> without file in " + permFile + " at "
+ + parser.getPositionDescription());
+ } else {
+ //Log.i(TAG, "Got library " + lname + " in " + lfile);
+ SharedLibraryEntry entry = new SharedLibraryEntry(lname, lfile,
+ ldependency == null ? new String[0] : ldependency.split(":"));
+ mSharedLibraries.put(lname, entry);
+ }
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ }
XmlUtils.skipCurrentTag(parser);
- continue;
- }
- int uid = Process.getUidForName(uidStr);
- if (uid < 0) {
- Slog.w(TAG, "<assign-permission> with unknown uid \""
- + uidStr + " in " + permFile + " at "
- + parser.getPositionDescription());
+ } break;
+ case "feature": {
+ if (allowFeatures) {
+ String fname = parser.getAttributeValue(null, "name");
+ int fversion = XmlUtils.readIntAttribute(parser, "version", 0);
+ boolean allowed;
+ if (!lowRam) {
+ allowed = true;
+ } else {
+ String notLowRam = parser.getAttributeValue(null, "notLowRam");
+ allowed = !"true".equals(notLowRam);
+ }
+ if (fname == null) {
+ Slog.w(TAG, "<" + name + "> without name in " + permFile + " at "
+ + parser.getPositionDescription());
+ } else if (allowed) {
+ addFeature(fname, fversion);
+ }
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ }
XmlUtils.skipCurrentTag(parser);
- continue;
- }
- perm = perm.intern();
- ArraySet<String> perms = mSystemPermissions.get(uid);
- if (perms == null) {
- perms = new ArraySet<String>();
- mSystemPermissions.put(uid, perms);
- }
- perms.add(perm);
- XmlUtils.skipCurrentTag(parser);
-
- } else if ("split-permission".equals(name) && allowPermissions) {
- readSplitPermission(parser, permFile);
- } else if ("library".equals(name) && allowLibs) {
- String lname = parser.getAttributeValue(null, "name");
- String lfile = parser.getAttributeValue(null, "file");
- String ldependency = parser.getAttributeValue(null, "dependency");
- if (lname == null) {
- Slog.w(TAG, "<library> without name in " + permFile + " at "
- + parser.getPositionDescription());
- } else if (lfile == null) {
- Slog.w(TAG, "<library> without file in " + permFile + " at "
- + parser.getPositionDescription());
- } else {
- //Log.i(TAG, "Got library " + lname + " in " + lfile);
- SharedLibraryEntry entry = new SharedLibraryEntry(lname, lfile,
- ldependency == null ? new String[0] : ldependency.split(":"));
- mSharedLibraries.put(lname, entry);
- }
- XmlUtils.skipCurrentTag(parser);
- continue;
- } else if ("feature".equals(name) && allowFeatures) {
- String fname = parser.getAttributeValue(null, "name");
- int fversion = XmlUtils.readIntAttribute(parser, "version", 0);
- boolean allowed;
- if (!lowRam) {
- allowed = true;
- } else {
- String notLowRam = parser.getAttributeValue(null, "notLowRam");
- allowed = !"true".equals(notLowRam);
- }
- if (fname == null) {
- Slog.w(TAG, "<feature> without name in " + permFile + " at "
- + parser.getPositionDescription());
- } else if (allowed) {
- addFeature(fname, fversion);
- }
- XmlUtils.skipCurrentTag(parser);
- continue;
-
- } else if ("unavailable-feature".equals(name) && allowFeatures) {
- String fname = parser.getAttributeValue(null, "name");
- if (fname == null) {
- Slog.w(TAG, "<unavailable-feature> without name in " + permFile + " at "
- + parser.getPositionDescription());
- } else {
- mUnavailableFeatures.add(fname);
- }
- XmlUtils.skipCurrentTag(parser);
- continue;
-
- } else if ("allow-in-power-save-except-idle".equals(name) && allowAll) {
- String pkgname = parser.getAttributeValue(null, "package");
- if (pkgname == null) {
- Slog.w(TAG, "<allow-in-power-save-except-idle> without package in "
- + permFile + " at " + parser.getPositionDescription());
- } else {
- mAllowInPowerSaveExceptIdle.add(pkgname);
- }
- XmlUtils.skipCurrentTag(parser);
- continue;
-
- } else if ("allow-in-power-save".equals(name) && allowAll) {
- String pkgname = parser.getAttributeValue(null, "package");
- if (pkgname == null) {
- Slog.w(TAG, "<allow-in-power-save> without package in " + permFile + " at "
- + parser.getPositionDescription());
- } else {
- mAllowInPowerSave.add(pkgname);
- }
- XmlUtils.skipCurrentTag(parser);
- continue;
-
- } else if ("allow-in-data-usage-save".equals(name) && allowAll) {
- String pkgname = parser.getAttributeValue(null, "package");
- if (pkgname == null) {
- Slog.w(TAG, "<allow-in-data-usage-save> without package in " + permFile
- + " at " + parser.getPositionDescription());
- } else {
- mAllowInDataUsageSave.add(pkgname);
- }
- XmlUtils.skipCurrentTag(parser);
- continue;
-
- } else if ("allow-unthrottled-location".equals(name) && allowAll) {
- String pkgname = parser.getAttributeValue(null, "package");
- if (pkgname == null) {
- Slog.w(TAG, "<allow-unthrottled-location> without package in "
- + permFile + " at " + parser.getPositionDescription());
- } else {
- mAllowUnthrottledLocation.add(pkgname);
- }
- XmlUtils.skipCurrentTag(parser);
- continue;
-
- } else if ("allow-implicit-broadcast".equals(name) && allowAll) {
- String action = parser.getAttributeValue(null, "action");
- if (action == null) {
- Slog.w(TAG, "<allow-implicit-broadcast> without action in " + permFile
- + " at " + parser.getPositionDescription());
- } else {
- mAllowImplicitBroadcasts.add(action);
- }
- XmlUtils.skipCurrentTag(parser);
- continue;
-
- } else if ("app-link".equals(name) && allowAppConfigs) {
- String pkgname = parser.getAttributeValue(null, "package");
- if (pkgname == null) {
- Slog.w(TAG, "<app-link> without package in " + permFile + " at "
- + parser.getPositionDescription());
- } else {
- mLinkedApps.add(pkgname);
- }
- XmlUtils.skipCurrentTag(parser);
- } else if ("system-user-whitelisted-app".equals(name) && allowAppConfigs) {
- String pkgname = parser.getAttributeValue(null, "package");
- if (pkgname == null) {
- Slog.w(TAG, "<system-user-whitelisted-app> without package in " + permFile
- + " at " + parser.getPositionDescription());
- } else {
- mSystemUserWhitelistedApps.add(pkgname);
- }
- XmlUtils.skipCurrentTag(parser);
- } else if ("system-user-blacklisted-app".equals(name) && allowAppConfigs) {
- String pkgname = parser.getAttributeValue(null, "package");
- if (pkgname == null) {
- Slog.w(TAG, "<system-user-blacklisted-app without package in " + permFile
- + " at " + parser.getPositionDescription());
- } else {
- mSystemUserBlacklistedApps.add(pkgname);
- }
- XmlUtils.skipCurrentTag(parser);
- } else if ("default-enabled-vr-app".equals(name) && allowAppConfigs) {
- String pkgname = parser.getAttributeValue(null, "package");
- String clsname = parser.getAttributeValue(null, "class");
- if (pkgname == null) {
- Slog.w(TAG, "<default-enabled-vr-app without package in " + permFile
- + " at " + parser.getPositionDescription());
- } else if (clsname == null) {
- Slog.w(TAG, "<default-enabled-vr-app without class in " + permFile
- + " at " + parser.getPositionDescription());
- } else {
- mDefaultVrComponents.add(new ComponentName(pkgname, clsname));
- }
- XmlUtils.skipCurrentTag(parser);
- } else if ("backup-transport-whitelisted-service".equals(name) && allowFeatures) {
- String serviceName = parser.getAttributeValue(null, "service");
- if (serviceName == null) {
- Slog.w(TAG, "<backup-transport-whitelisted-service> without service in "
- + permFile + " at " + parser.getPositionDescription());
- } else {
- ComponentName cn = ComponentName.unflattenFromString(serviceName);
- if (cn == null) {
- Slog.w(TAG,
- "<backup-transport-whitelisted-service> with invalid service name "
- + serviceName + " in "+ permFile
- + " at " + parser.getPositionDescription());
+ } break;
+ case "unavailable-feature": {
+ if (allowFeatures) {
+ String fname = parser.getAttributeValue(null, "name");
+ if (fname == null) {
+ Slog.w(TAG, "<" + name + "> without name in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else {
+ mUnavailableFeatures.add(fname);
+ }
} else {
- mBackupTransportWhitelist.add(cn);
+ logNotAllowedInPartition(name, permFile, parser);
}
- }
- XmlUtils.skipCurrentTag(parser);
- } else if ("disabled-until-used-preinstalled-carrier-associated-app".equals(name)
- && allowAppConfigs) {
- String pkgname = parser.getAttributeValue(null, "package");
- String carrierPkgname = parser.getAttributeValue(null, "carrierAppPackage");
- if (pkgname == null || carrierPkgname == null) {
- Slog.w(TAG, "<disabled-until-used-preinstalled-carrier-associated-app"
- + " without package or carrierAppPackage in " + permFile + " at "
- + parser.getPositionDescription());
- } else {
- List<String> associatedPkgs =
- mDisabledUntilUsedPreinstalledCarrierAssociatedApps.get(
- carrierPkgname);
- if (associatedPkgs == null) {
- associatedPkgs = new ArrayList<>();
- mDisabledUntilUsedPreinstalledCarrierAssociatedApps.put(
- carrierPkgname, associatedPkgs);
+ XmlUtils.skipCurrentTag(parser);
+ } break;
+ case "allow-in-power-save-except-idle": {
+ if (allowAll) {
+ String pkgname = parser.getAttributeValue(null, "package");
+ if (pkgname == null) {
+ Slog.w(TAG, "<" + name + "> without package in "
+ + permFile + " at " + parser.getPositionDescription());
+ } else {
+ mAllowInPowerSaveExceptIdle.add(pkgname);
+ }
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
}
- associatedPkgs.add(pkgname);
- }
- XmlUtils.skipCurrentTag(parser);
- } else if ("disabled-until-used-preinstalled-carrier-app".equals(name)
- && allowAppConfigs) {
- String pkgname = parser.getAttributeValue(null, "package");
- if (pkgname == null) {
- Slog.w(TAG,
- "<disabled-until-used-preinstalled-carrier-app> without "
- + "package in " + permFile + " at "
- + parser.getPositionDescription());
- } else {
- mDisabledUntilUsedPreinstalledCarrierApps.add(pkgname);
- }
- XmlUtils.skipCurrentTag(parser);
- } else if ("privapp-permissions".equals(name) && allowPrivappPermissions) {
- // privapp permissions from system, vendor, product and product_services
- // partitions are stored separately. This is to prevent xml files in the vendor
- // partition from granting permissions to priv apps in the system partition and
- // vice versa.
- boolean vendor = permFile.toPath().startsWith(
- Environment.getVendorDirectory().toPath() + "/")
- || permFile.toPath().startsWith(
- Environment.getOdmDirectory().toPath() + "/");
- boolean product = permFile.toPath().startsWith(
- Environment.getProductDirectory().toPath() + "/");
- boolean productServices = permFile.toPath().startsWith(
- Environment.getProductServicesDirectory().toPath() + "/");
- if (vendor) {
- readPrivAppPermissions(parser, mVendorPrivAppPermissions,
- mVendorPrivAppDenyPermissions);
- } else if (product) {
- readPrivAppPermissions(parser, mProductPrivAppPermissions,
- mProductPrivAppDenyPermissions);
- } else if (productServices) {
- readPrivAppPermissions(parser, mProductServicesPrivAppPermissions,
- mProductServicesPrivAppDenyPermissions);
- } else {
- readPrivAppPermissions(parser, mPrivAppPermissions,
- mPrivAppDenyPermissions);
- }
- } else if ("oem-permissions".equals(name) && allowOemPermissions) {
- readOemPermissions(parser);
- } else if ("hidden-api-whitelisted-app".equals(name) && allowApiWhitelisting) {
- String pkgname = parser.getAttributeValue(null, "package");
- if (pkgname == null) {
- Slog.w(TAG, "<hidden-api-whitelisted-app> without package in " + permFile
- + " at " + parser.getPositionDescription());
- } else {
- mHiddenApiPackageWhitelist.add(pkgname);
- }
- XmlUtils.skipCurrentTag(parser);
- } else {
- Slog.w(TAG, "Tag " + name + " is unknown or not allowed in "
- + permFile.getParent());
- XmlUtils.skipCurrentTag(parser);
- continue;
+ XmlUtils.skipCurrentTag(parser);
+ } break;
+ case "allow-in-power-save": {
+ if (allowAll) {
+ String pkgname = parser.getAttributeValue(null, "package");
+ if (pkgname == null) {
+ Slog.w(TAG, "<" + name + "> without package in "
+ + permFile + " at " + parser.getPositionDescription());
+ } else {
+ mAllowInPowerSave.add(pkgname);
+ }
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } break;
+ case "allow-in-data-usage-save": {
+ if (allowAll) {
+ String pkgname = parser.getAttributeValue(null, "package");
+ if (pkgname == null) {
+ Slog.w(TAG, "<" + name + "> without package in "
+ + permFile + " at " + parser.getPositionDescription());
+ } else {
+ mAllowInDataUsageSave.add(pkgname);
+ }
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } break;
+ case "allow-unthrottled-location": {
+ if (allowAll) {
+ String pkgname = parser.getAttributeValue(null, "package");
+ if (pkgname == null) {
+ Slog.w(TAG, "<" + name + "> without package in "
+ + permFile + " at " + parser.getPositionDescription());
+ } else {
+ mAllowUnthrottledLocation.add(pkgname);
+ }
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } break;
+ case "allow-implicit-broadcast": {
+ if (allowAll) {
+ String action = parser.getAttributeValue(null, "action");
+ if (action == null) {
+ Slog.w(TAG, "<" + name + "> without action in "
+ + permFile + " at " + parser.getPositionDescription());
+ } else {
+ mAllowImplicitBroadcasts.add(action);
+ }
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } break;
+ case "app-link": {
+ if (allowAppConfigs) {
+ String pkgname = parser.getAttributeValue(null, "package");
+ if (pkgname == null) {
+ Slog.w(TAG, "<" + name + "> without package in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else {
+ mLinkedApps.add(pkgname);
+ }
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } break;
+ case "system-user-whitelisted-app": {
+ if (allowAppConfigs) {
+ String pkgname = parser.getAttributeValue(null, "package");
+ if (pkgname == null) {
+ Slog.w(TAG, "<" + name + "> without package in "
+ + permFile + " at " + parser.getPositionDescription());
+ } else {
+ mSystemUserWhitelistedApps.add(pkgname);
+ }
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } break;
+ case "system-user-blacklisted-app": {
+ if (allowAppConfigs) {
+ String pkgname = parser.getAttributeValue(null, "package");
+ if (pkgname == null) {
+ Slog.w(TAG, "<" + name + "> without package in "
+ + permFile + " at " + parser.getPositionDescription());
+ } else {
+ mSystemUserBlacklistedApps.add(pkgname);
+ }
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } break;
+ case "default-enabled-vr-app": {
+ if (allowAppConfigs) {
+ String pkgname = parser.getAttributeValue(null, "package");
+ String clsname = parser.getAttributeValue(null, "class");
+ if (pkgname == null) {
+ Slog.w(TAG, "<" + name + "> without package in "
+ + permFile + " at " + parser.getPositionDescription());
+ } else if (clsname == null) {
+ Slog.w(TAG, "<" + name + "> without class in "
+ + permFile + " at " + parser.getPositionDescription());
+ } else {
+ mDefaultVrComponents.add(new ComponentName(pkgname, clsname));
+ }
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } break;
+ case "backup-transport-whitelisted-service": {
+ if (allowFeatures) {
+ String serviceName = parser.getAttributeValue(null, "service");
+ if (serviceName == null) {
+ Slog.w(TAG, "<" + name + "> without service in "
+ + permFile + " at " + parser.getPositionDescription());
+ } else {
+ ComponentName cn = ComponentName.unflattenFromString(serviceName);
+ if (cn == null) {
+ Slog.w(TAG, "<" + name + "> with invalid service name "
+ + serviceName + " in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else {
+ mBackupTransportWhitelist.add(cn);
+ }
+ }
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } break;
+ case "disabled-until-used-preinstalled-carrier-associated-app": {
+ if (allowAppConfigs) {
+ String pkgname = parser.getAttributeValue(null, "package");
+ String carrierPkgname = parser.getAttributeValue(null,
+ "carrierAppPackage");
+ if (pkgname == null || carrierPkgname == null) {
+ Slog.w(TAG, "<" + name
+ + "> without package or carrierAppPackage in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else {
+ List<String> associatedPkgs =
+ mDisabledUntilUsedPreinstalledCarrierAssociatedApps.get(
+ carrierPkgname);
+ if (associatedPkgs == null) {
+ associatedPkgs = new ArrayList<>();
+ mDisabledUntilUsedPreinstalledCarrierAssociatedApps.put(
+ carrierPkgname, associatedPkgs);
+ }
+ associatedPkgs.add(pkgname);
+ }
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } break;
+ case "disabled-until-used-preinstalled-carrier-app": {
+ if (allowAppConfigs) {
+ String pkgname = parser.getAttributeValue(null, "package");
+ if (pkgname == null) {
+ Slog.w(TAG,
+ "<" + name + "> without "
+ + "package in " + permFile + " at "
+ + parser.getPositionDescription());
+ } else {
+ mDisabledUntilUsedPreinstalledCarrierApps.add(pkgname);
+ }
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } break;
+ case "privapp-permissions": {
+ if (allowPrivappPermissions) {
+ // privapp permissions from system, vendor, product and product_services
+ // partitions are stored separately. This is to prevent xml files in
+ // the vendor partition from granting permissions to priv apps in the
+ // system partition and vice versa.
+ boolean vendor = permFile.toPath().startsWith(
+ Environment.getVendorDirectory().toPath() + "/")
+ || permFile.toPath().startsWith(
+ Environment.getOdmDirectory().toPath() + "/");
+ boolean product = permFile.toPath().startsWith(
+ Environment.getProductDirectory().toPath() + "/");
+ boolean productServices = permFile.toPath().startsWith(
+ Environment.getProductServicesDirectory().toPath() + "/");
+ if (vendor) {
+ readPrivAppPermissions(parser, mVendorPrivAppPermissions,
+ mVendorPrivAppDenyPermissions);
+ } else if (product) {
+ readPrivAppPermissions(parser, mProductPrivAppPermissions,
+ mProductPrivAppDenyPermissions);
+ } else if (productServices) {
+ readPrivAppPermissions(parser, mProductServicesPrivAppPermissions,
+ mProductServicesPrivAppDenyPermissions);
+ } else {
+ readPrivAppPermissions(parser, mPrivAppPermissions,
+ mPrivAppDenyPermissions);
+ }
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ XmlUtils.skipCurrentTag(parser);
+ }
+ } break;
+ case "oem-permissions": {
+ if (allowOemPermissions) {
+ readOemPermissions(parser);
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ XmlUtils.skipCurrentTag(parser);
+ }
+ } break;
+ case "hidden-api-whitelisted-app": {
+ if (allowApiWhitelisting) {
+ String pkgname = parser.getAttributeValue(null, "package");
+ if (pkgname == null) {
+ Slog.w(TAG, "<" + name + "> without package in "
+ + permFile + " at " + parser.getPositionDescription());
+ } else {
+ mHiddenApiPackageWhitelist.add(pkgname);
+ }
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } break;
+ case "allow-association": {
+ if (allowAssociations) {
+ String target = parser.getAttributeValue(null, "target");
+ if (target == null) {
+ Slog.w(TAG, "<" + name + "> without target in " + permFile
+ + " at " + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ break;
+ }
+ String allowed = parser.getAttributeValue(null, "allowed");
+ if (allowed == null) {
+ Slog.w(TAG, "<" + name + "> without allowed in " + permFile
+ + " at " + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ break;
+ }
+ target = target.intern();
+ allowed = allowed.intern();
+ ArraySet<String> associations = mAllowedAssociations.get(target);
+ if (associations == null) {
+ associations = new ArraySet<>();
+ mAllowedAssociations.put(target, associations);
+ }
+ Slog.i(TAG, "Adding association: " + target + " <- " + allowed);
+ associations.add(allowed);
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } break;
+ default: {
+ Slog.w(TAG, "Tag " + name + " is unknown in "
+ + permFile + " at " + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ } break;
}
}
} catch (XmlPullParserException e) {
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index 6ebf35c8e1dc..a54571b539da 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -36,7 +36,7 @@ public:
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&SafeUnref));
}
- static jlong CreatePorterDuffFilter(JNIEnv* env, jobject, jint srcColor, jint modeHandle) {
+ static jlong CreateBlendModeFilter(JNIEnv* env, jobject, jint srcColor, jint modeHandle) {
SkBlendMode mode = static_cast<SkBlendMode>(modeHandle);
return reinterpret_cast<jlong>(SkColorFilter::MakeModeFilter(srcColor, mode).release());
}
@@ -61,8 +61,8 @@ static const JNINativeMethod colorfilter_methods[] = {
{"nativeGetFinalizer", "()J", (void*) SkColorFilterGlue::GetNativeFinalizer }
};
-static const JNINativeMethod porterduff_methods[] = {
- { "native_CreatePorterDuffFilter", "(II)J", (void*) SkColorFilterGlue::CreatePorterDuffFilter },
+static const JNINativeMethod blendmode_methods[] = {
+ { "native_CreateBlendModeFilter", "(II)J", (void*) SkColorFilterGlue::CreateBlendModeFilter },
};
static const JNINativeMethod lighting_methods[] = {
@@ -76,8 +76,10 @@ static const JNINativeMethod colormatrix_methods[] = {
int register_android_graphics_ColorFilter(JNIEnv* env) {
android::RegisterMethodsOrDie(env, "android/graphics/ColorFilter", colorfilter_methods,
NELEM(colorfilter_methods));
- android::RegisterMethodsOrDie(env, "android/graphics/PorterDuffColorFilter", porterduff_methods,
- NELEM(porterduff_methods));
+ android::RegisterMethodsOrDie(env, "android/graphics/PorterDuffColorFilter", blendmode_methods,
+ NELEM(blendmode_methods));
+ android::RegisterMethodsOrDie(env, "android/graphics/BlendModeColorFilter", blendmode_methods,
+ NELEM(blendmode_methods));
android::RegisterMethodsOrDie(env, "android/graphics/LightingColorFilter", lighting_methods,
NELEM(lighting_methods));
android::RegisterMethodsOrDie(env, "android/graphics/ColorMatrixColorFilter",
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index c249e209b29f..df24bc4d2abc 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -845,12 +845,23 @@ namespace PaintGlue {
static_assert(9 == static_cast<int>(SkBlendMode::kSrcATop), "xfermode_mismatch");
static_assert(10 == static_cast<int>(SkBlendMode::kDstATop), "xfermode_mismatch");
static_assert(11 == static_cast<int>(SkBlendMode::kXor), "xfermode_mismatch");
- static_assert(16 == static_cast<int>(SkBlendMode::kDarken), "xfermode_mismatch");
- static_assert(17 == static_cast<int>(SkBlendMode::kLighten), "xfermode_mismatch");
+ static_assert(12 == static_cast<int>(SkBlendMode::kPlus), "xfermode_mismatch");
static_assert(13 == static_cast<int>(SkBlendMode::kModulate), "xfermode_mismatch");
static_assert(14 == static_cast<int>(SkBlendMode::kScreen), "xfermode_mismatch");
- static_assert(12 == static_cast<int>(SkBlendMode::kPlus), "xfermode_mismatch");
static_assert(15 == static_cast<int>(SkBlendMode::kOverlay), "xfermode_mismatch");
+ static_assert(16 == static_cast<int>(SkBlendMode::kDarken), "xfermode_mismatch");
+ static_assert(17 == static_cast<int>(SkBlendMode::kLighten), "xfermode_mismatch");
+ static_assert(18 == static_cast<int>(SkBlendMode::kColorDodge), "xfermode mismatch");
+ static_assert(19 == static_cast<int>(SkBlendMode::kColorBurn), "xfermode mismatch");
+ static_assert(20 == static_cast<int>(SkBlendMode::kHardLight), "xfermode mismatch");
+ static_assert(21 == static_cast<int>(SkBlendMode::kSoftLight), "xfermode mismatch");
+ static_assert(22 == static_cast<int>(SkBlendMode::kDifference), "xfermode mismatch");
+ static_assert(23 == static_cast<int>(SkBlendMode::kExclusion), "xfermode mismatch");
+ static_assert(24 == static_cast<int>(SkBlendMode::kMultiply), "xfermode mismatch");
+ static_assert(25 == static_cast<int>(SkBlendMode::kHue), "xfermode mismatch");
+ static_assert(26 == static_cast<int>(SkBlendMode::kSaturation), "xfermode mismatch");
+ static_assert(27 == static_cast<int>(SkBlendMode::kColor), "xfermode mismatch");
+ static_assert(28 == static_cast<int>(SkBlendMode::kLuminosity), "xfermode mismatch");
SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle);
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index b708735616c4..24bafca9c386 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -35,7 +35,6 @@
#include "bpf/BpfUtils.h"
#include "netdbpf/BpfNetworkStats.h"
-using android::bpf::hasBpfSupport;
using android::bpf::parseBpfNetworkStatsDetail;
using android::bpf::stats_line;
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 4aa88e7558cd..7032081ef6a0 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -99,7 +99,8 @@ enum MountExternalKind {
MOUNT_EXTERNAL_DEFAULT = 1,
MOUNT_EXTERNAL_READ = 2,
MOUNT_EXTERNAL_WRITE = 3,
- MOUNT_EXTERNAL_FULL = 4,
+ MOUNT_EXTERNAL_INSTALLER = 4,
+ MOUNT_EXTERNAL_FULL = 5,
};
// Must match values in com.android.internal.os.Zygote.
@@ -446,29 +447,35 @@ static bool createPkgSandbox(uid_t uid, const std::string& package_name, std::st
return true;
}
-static bool mountPkgSpecificDir(const std::string& mntSourceRoot,
- const std::string& mntTargetRoot, const std::string& packageName,
- const char* dirName, std::string* error_msg) {
- std::string mntSourceDir = StringPrintf("%s/Android/%s/%s",
- mntSourceRoot.c_str(), dirName, packageName.c_str());
- std::string mntTargetDir = StringPrintf("%s/Android/%s/%s",
- mntTargetRoot.c_str(), dirName, packageName.c_str());
- if (TEMP_FAILURE_RETRY(mount(mntSourceDir.c_str(), mntTargetDir.c_str(),
+static bool bindMount(const std::string& sourceDir, const std::string& targetDir,
+ std::string* error_msg) {
+ if (TEMP_FAILURE_RETRY(mount(sourceDir.c_str(), targetDir.c_str(),
nullptr, MS_BIND | MS_REC, nullptr)) == -1) {
*error_msg = CREATE_ERROR("Failed to mount %s to %s: %s",
- mntSourceDir.c_str(), mntTargetDir.c_str(), strerror(errno));
+ sourceDir.c_str(), targetDir.c_str(), strerror(errno));
return false;
}
- if (TEMP_FAILURE_RETRY(mount(nullptr, mntTargetDir.c_str(),
+ if (TEMP_FAILURE_RETRY(mount(nullptr, targetDir.c_str(),
nullptr, MS_SLAVE | MS_REC, nullptr)) == -1) {
- *error_msg = CREATE_ERROR("Failed to set MS_SLAVE for %s", mntTargetDir.c_str());
+ *error_msg = CREATE_ERROR("Failed to set MS_SLAVE for %s", targetDir.c_str());
return false;
}
return true;
}
+static bool mountPkgSpecificDir(const std::string& mntSourceRoot,
+ const std::string& mntTargetRoot, const std::string& packageName,
+ const char* dirName, std::string* error_msg) {
+ std::string mntSourceDir = StringPrintf("%s/Android/%s/%s",
+ mntSourceRoot.c_str(), dirName, packageName.c_str());
+ std::string mntTargetDir = StringPrintf("%s/Android/%s/%s",
+ mntTargetRoot.c_str(), dirName, packageName.c_str());
+ return bindMount(mntSourceDir, mntTargetDir, error_msg);
+}
+
static bool preparePkgSpecificDirs(const std::vector<std::string>& packageNames,
- const std::vector<std::string>& volumeLabels, userid_t userId, std::string* error_msg) {
+ const std::vector<std::string>& volumeLabels, bool mountAllObbs,
+ userid_t userId, std::string* error_msg) {
for (auto& label : volumeLabels) {
std::string mntSource = StringPrintf("/mnt/runtime/write/%s", label.c_str());
std::string mntTarget = StringPrintf("/storage/%s", label.c_str());
@@ -479,7 +486,14 @@ static bool preparePkgSpecificDirs(const std::vector<std::string>& packageNames,
for (auto& package : packageNames) {
mountPkgSpecificDir(mntSource, mntTarget, package, "data", error_msg);
mountPkgSpecificDir(mntSource, mntTarget, package, "media", error_msg);
- mountPkgSpecificDir(mntSource, mntTarget, package, "obb", error_msg);
+ if (!mountAllObbs) {
+ mountPkgSpecificDir(mntSource, mntTarget, package, "obb", error_msg);
+ }
+ }
+ if (mountAllObbs) {
+ StringAppendF(&mntSource, "/Android/obb");
+ StringAppendF(&mntTarget, "/Android/obb");
+ bindMount(mntSource, mntTarget, error_msg);
}
}
return true;
@@ -500,7 +514,7 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode,
storageSource = "/mnt/runtime/read";
} else if (mount_mode == MOUNT_EXTERNAL_WRITE) {
storageSource = "/mnt/runtime/write";
- } else if (mount_mode != MOUNT_EXTERNAL_FULL && !force_mount_namespace) {
+ } else if (mount_mode == MOUNT_EXTERNAL_NONE && !force_mount_namespace) {
// Sane default of no storage visible
return true;
}
@@ -568,12 +582,28 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode,
pkgSandboxDir.c_str(), strerror(errno));
return false;
}
+ if (access("/storage/obb_mount", F_OK) == 0) {
+ if (mount_mode != MOUNT_EXTERNAL_INSTALLER) {
+ remove("/storage/obb_mount");
+ }
+ } else {
+ if (mount_mode == MOUNT_EXTERNAL_INSTALLER) {
+ int fd = TEMP_FAILURE_RETRY(open("/storage/obb_mount",
+ O_RDWR | O_CREAT, 0660));
+ if (fd == -1) {
+ *error_msg = CREATE_ERROR("Couldn't create /storage/obb_mount: %s",
+ strerror(errno));
+ return false;
+ }
+ close(fd);
+ }
+ }
// If the sandbox was already created by vold, only then set up the bind mounts for
// pkg specific directories. Otherwise, leave as is and bind mounts will be taken
// care of by vold later.
if (sandboxAlreadyCreated) {
if (!preparePkgSpecificDirs(packages_for_uid, visible_vol_ids,
- user_id, error_msg)) {
+ mount_mode == MOUNT_EXTERNAL_INSTALLER, user_id, error_msg)) {
return false;
}
}
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 514f306953a5..3e1c5a334184 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -82,5 +82,7 @@ enum PageId {
// OPEN: WifiDppEnrolleeActivity (android.settings.WIFI_DPP_ENROLLEE_XXX action intents)
SETTINGS_WIFI_DPP_ENROLLEE = 1596;
-}
+ // OPEN: Settings > Apps & Notifications -> Special app access -> Financial Apps Sms Access
+ SETTINGS_FINANCIAL_APPS_SMS_ACCESS = 1597;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b99b2dd41439..dca15bd49ca4 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1121,10 +1121,10 @@
android:protectionLevel="normal" />
<!--Allows an app which implements the
- {@link InCallService} API to be eligible to be enabled as a calling companion app. This
- means that the Telecom framework will bind to the app's InCallService implementation when
- there are calls active. The app can use the InCallService API to view information about
- calls on the system and control these calls.
+ {@link android.telecom.InCallService InCallService} API to be eligible to be enabled as a
+ calling companion app. This means that the Telecom framework will bind to the app's
+ InCallService implementation when there are calls active. The app can use the InCallService
+ API to view information about calls on the system and control these calls.
<p>Protection level: normal
-->
<permission android:name="android.permission.CALL_COMPANION_APP"
diff --git a/core/tests/coretests/src/android/os/BinderWorkSourceTest.java b/core/tests/coretests/src/android/os/BinderWorkSourceTest.java
index ef14b00f9775..5664df6e9744 100644
--- a/core/tests/coretests/src/android/os/BinderWorkSourceTest.java
+++ b/core/tests/coretests/src/android/os/BinderWorkSourceTest.java
@@ -23,6 +23,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.platform.test.annotations.Presubmit;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
@@ -37,6 +38,7 @@ import org.junit.runner.RunWith;
* Test whether Binder calls work source is propagated correctly.
*/
@LargeTest
+@Presubmit
@RunWith(AndroidJUnit4.class)
public class BinderWorkSourceTest {
private static Context sContext;
diff --git a/docs/html/reference/images/graphics/blendmode_CLEAR.png b/docs/html/reference/images/graphics/blendmode_CLEAR.png
new file mode 100644
index 000000000000..979782adef58
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_CLEAR.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_COLOR.png b/docs/html/reference/images/graphics/blendmode_COLOR.png
new file mode 100644
index 000000000000..2f41bfb03cfb
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_COLOR.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_COLOR_BURN.png b/docs/html/reference/images/graphics/blendmode_COLOR_BURN.png
new file mode 100644
index 000000000000..26059ce858ee
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_COLOR_BURN.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_COLOR_DODGE.png b/docs/html/reference/images/graphics/blendmode_COLOR_DODGE.png
new file mode 100644
index 000000000000..922f1d9e474d
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_COLOR_DODGE.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_DARKEN.png b/docs/html/reference/images/graphics/blendmode_DARKEN.png
new file mode 100644
index 000000000000..6c04aa3a129f
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_DARKEN.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_DIFFERENCE.png b/docs/html/reference/images/graphics/blendmode_DIFFERENCE.png
new file mode 100644
index 000000000000..aab2bcb8833a
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_DIFFERENCE.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_DST.png b/docs/html/reference/images/graphics/blendmode_DST.png
new file mode 100644
index 000000000000..16f96b4752b8
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_DST.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_DST_ATOP.png b/docs/html/reference/images/graphics/blendmode_DST_ATOP.png
new file mode 100644
index 000000000000..d0ae2cde7b0f
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_DST_ATOP.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_DST_IN.png b/docs/html/reference/images/graphics/blendmode_DST_IN.png
new file mode 100644
index 000000000000..9befe279af73
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_DST_IN.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_DST_OUT.png b/docs/html/reference/images/graphics/blendmode_DST_OUT.png
new file mode 100644
index 000000000000..e9227e9f06d3
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_DST_OUT.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_DST_OVER.png b/docs/html/reference/images/graphics/blendmode_DST_OVER.png
new file mode 100644
index 000000000000..015be0a4a730
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_DST_OVER.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_EXCLUSION.png b/docs/html/reference/images/graphics/blendmode_EXCLUSION.png
new file mode 100644
index 000000000000..307dec90ec33
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_EXCLUSION.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_HARD_LIGHT.png b/docs/html/reference/images/graphics/blendmode_HARD_LIGHT.png
new file mode 100644
index 000000000000..3b62b9855bf4
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_HARD_LIGHT.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_HUE.png b/docs/html/reference/images/graphics/blendmode_HUE.png
new file mode 100644
index 000000000000..012bd3332358
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_HUE.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_LIGHTEN.png b/docs/html/reference/images/graphics/blendmode_LIGHTEN.png
new file mode 100644
index 000000000000..1c3be656e40a
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_LIGHTEN.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_LUMINOSITY.png b/docs/html/reference/images/graphics/blendmode_LUMINOSITY.png
new file mode 100644
index 000000000000..3549082e4c62
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_LUMINOSITY.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_MODULATE.png b/docs/html/reference/images/graphics/blendmode_MODULATE.png
new file mode 100644
index 000000000000..ed1b59d140e8
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_MODULATE.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_MULTIPLY.png b/docs/html/reference/images/graphics/blendmode_MULTIPLY.png
new file mode 100644
index 000000000000..c8c7ccb1e21a
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_MULTIPLY.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_OVERLAY.png b/docs/html/reference/images/graphics/blendmode_OVERLAY.png
new file mode 100644
index 000000000000..6962f928dc7e
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_OVERLAY.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_PLUS.png b/docs/html/reference/images/graphics/blendmode_PLUS.png
new file mode 100644
index 000000000000..015fa2b5d0e4
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_PLUS.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_SATURATION.png b/docs/html/reference/images/graphics/blendmode_SATURATION.png
new file mode 100644
index 000000000000..5ac96c32f648
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_SATURATION.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_SCREEN.png b/docs/html/reference/images/graphics/blendmode_SCREEN.png
new file mode 100644
index 000000000000..d2d70d25850d
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_SCREEN.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_SOFT_LIGHT.png b/docs/html/reference/images/graphics/blendmode_SOFT_LIGHT.png
new file mode 100644
index 000000000000..89fbacd24dcc
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_SOFT_LIGHT.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_SRC.png b/docs/html/reference/images/graphics/blendmode_SRC.png
new file mode 100644
index 000000000000..990ec94301b3
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_SRC.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_SRC_ATOP.png b/docs/html/reference/images/graphics/blendmode_SRC_ATOP.png
new file mode 100644
index 000000000000..d574dfd923f2
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_SRC_ATOP.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_SRC_IN.png b/docs/html/reference/images/graphics/blendmode_SRC_IN.png
new file mode 100644
index 000000000000..dda45d7319a4
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_SRC_IN.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_SRC_OUT.png b/docs/html/reference/images/graphics/blendmode_SRC_OUT.png
new file mode 100644
index 000000000000..f5d43c103dc2
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_SRC_OUT.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_SRC_OVER.png b/docs/html/reference/images/graphics/blendmode_SRC_OVER.png
new file mode 100644
index 000000000000..b1a405bc878d
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_SRC_OVER.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/blendmode_XOR.png b/docs/html/reference/images/graphics/blendmode_XOR.png
new file mode 100644
index 000000000000..31c110d98d27
--- /dev/null
+++ b/docs/html/reference/images/graphics/blendmode_XOR.png
Binary files differ
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index 3db240b54299..ca9dc475f7a1 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -241,10 +241,22 @@ public abstract class BaseCanvas {
nDrawColor(mNativeCanvasWrapper, color, PorterDuff.Mode.SRC_OVER.nativeInt);
}
+ /**
+ * @deprecated use {@link Canvas#drawColor(int, BlendMode)}
+ */
+ @Deprecated
public void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
nDrawColor(mNativeCanvasWrapper, color, mode.nativeInt);
}
+ /**
+ * Make lint happy.
+ * See {@link Canvas#drawColor(int, BlendMode)}
+ */
+ public void drawColor(@ColorInt int color, @NonNull BlendMode mode) {
+ nDrawColor(mNativeCanvasWrapper, color, mode.getXfermode().porterDuffMode);
+ }
+
public void drawLine(float startX, float startY, float stopX, float stopY,
@NonNull Paint paint) {
throwIfHasHwBitmapInSwMode(paint);
diff --git a/graphics/java/android/graphics/BaseRecordingCanvas.java b/graphics/java/android/graphics/BaseRecordingCanvas.java
index 4de7ca708eb6..901c2116884b 100644
--- a/graphics/java/android/graphics/BaseRecordingCanvas.java
+++ b/graphics/java/android/graphics/BaseRecordingCanvas.java
@@ -201,12 +201,21 @@ public class BaseRecordingCanvas extends Canvas {
nDrawColor(mNativeCanvasWrapper, color, PorterDuff.Mode.SRC_OVER.nativeInt);
}
+ /**
+ * @deprecated use {@link #drawColor(int, BlendMode)} instead
+ */
+ @Deprecated
@Override
public final void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
nDrawColor(mNativeCanvasWrapper, color, mode.nativeInt);
}
@Override
+ public final void drawColor(@ColorInt int color, @NonNull BlendMode mode) {
+ nDrawColor(mNativeCanvasWrapper, color, mode.getXfermode().porterDuffMode);
+ }
+
+ @Override
public final void drawLine(float startX, float startY, float stopX, float stopY,
@NonNull Paint paint) {
nDrawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.getNativeInstance());
diff --git a/graphics/java/android/graphics/BlendMode.java b/graphics/java/android/graphics/BlendMode.java
new file mode 100644
index 000000000000..39392c89d170
--- /dev/null
+++ b/graphics/java/android/graphics/BlendMode.java
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+public enum BlendMode {
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_CLEAR.png" />
+ * <figcaption>Destination pixels covered by the source are cleared to 0.</figcaption>
+ * </p>
+ * <p>\(\alpha_{out} = 0\)</p>
+ * <p>\(C_{out} = 0\)</p>
+ */
+ CLEAR(0),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC.png" />
+ * <figcaption>The source pixels replace the destination pixels.</figcaption>
+ * </p>
+ * <p>\(\alpha_{out} = \alpha_{src}\)</p>
+ * <p>\(C_{out} = C_{src}\)</p>
+ */
+ SRC(1),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_DST.png" />
+ * <figcaption>The source pixels are discarded, leaving the destination intact.</figcaption>
+ * </p>
+ * <p>\(\alpha_{out} = \alpha_{dst}\)</p>
+ * <p>\(C_{out} = C_{dst}\)</p>
+ */
+ DST(2),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC_OVER.png" />
+ * <figcaption>The source pixels are drawn over the destination pixels.</figcaption>
+ * </p>
+ * <p>\(\alpha_{out} = \alpha_{src} + (1 - \alpha_{src}) * \alpha_{dst}\)</p>
+ * <p>\(C_{out} = C_{src} + (1 - \alpha_{src}) * C_{dst}\)</p>
+ */
+ SRC_OVER(3),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_DST_OVER.png" />
+ * <figcaption>The source pixels are drawn behind the destination pixels.</figcaption>
+ * </p>
+ * <p>\(\alpha_{out} = \alpha_{dst} + (1 - \alpha_{dst}) * \alpha_{src}\)</p>
+ * <p>\(C_{out} = C_{dst} + (1 - \alpha_{dst}) * C_{src}\)</p>
+ */
+ DST_OVER(4),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC_IN.png" />
+ * <figcaption>Keeps the source pixels that cover the destination pixels,
+ * discards the remaining source and destination pixels.</figcaption>
+ * </p>
+ * <p>\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)</p>
+ * <p>\(C_{out} = C_{src} * \alpha_{dst}\)</p>
+ */
+ SRC_IN(5),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_DST_IN.png" />
+ * <figcaption>Keeps the destination pixels that cover source pixels,
+ * discards the remaining source and destination pixels.</figcaption>
+ * </p>
+ * <p>\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)</p>
+ * <p>\(C_{out} = C_{dst} * \alpha_{src}\)</p>
+ */
+ DST_IN(6),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC_OUT.png" />
+ * <figcaption>Keeps the source pixels that do not cover destination pixels.
+ * Discards source pixels that cover destination pixels. Discards all
+ * destination pixels.</figcaption>
+ * </p>
+ * <p>\(\alpha_{out} = (1 - \alpha_{dst}) * \alpha_{src}\)</p>
+ * <p>\(C_{out} = (1 - \alpha_{dst}) * C_{src}\)</p>
+ */
+ SRC_OUT(7),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_DST_OUT.png" />
+ * <figcaption>Keeps the destination pixels that are not covered by source pixels.
+ * Discards destination pixels that are covered by source pixels. Discards all
+ * source pixels.</figcaption>
+ * </p>
+ * <p>\(\alpha_{out} = (1 - \alpha_{src}) * \alpha_{dst}\)</p>
+ * <p>\(C_{out} = (1 - \alpha_{src}) * C_{dst}\)</p>
+ */
+ DST_OUT(8),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC_ATOP.png" />
+ * <figcaption>Discards the source pixels that do not cover destination pixels.
+ * Draws remaining source pixels over destination pixels.</figcaption>
+ * </p>
+ * <p>\(\alpha_{out} = \alpha_{dst}\)</p>
+ * <p>\(C_{out} = \alpha_{dst} * C_{src} + (1 - \alpha_{src}) * C_{dst}\)</p>
+ */
+ SRC_ATOP(9),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_DST_ATOP.png" />
+ * <figcaption>Discards the destination pixels that are not covered by source pixels.
+ * Draws remaining destination pixels over source pixels.</figcaption>
+ * </p>
+ * <p>\(\alpha_{out} = \alpha_{src}\)</p>
+ * <p>\(C_{out} = \alpha_{src} * C_{dst} + (1 - \alpha_{dst}) * C_{src}\)</p>
+ */
+ DST_ATOP(10),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_XOR.png" />
+ * <figcaption>Discards the source and destination pixels where source pixels
+ * cover destination pixels. Draws remaining source pixels.</figcaption>
+ * </p>
+ * <p>
+ * \(\alpha_{out} = (1 - \alpha_{dst}) * \alpha_{src} + (1 - \alpha_{src}) * \alpha_{dst}\)
+ * </p>
+ * <p>\(C_{out} = (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst}\)</p>
+ */
+ XOR(11),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_PLUS.png" />
+ * <figcaption>Adds the source pixels to the destination pixels and saturates
+ * the result.</figcaption>
+ * </p>
+ * <p>\(\alpha_{out} = max(0, min(\alpha_{src} + \alpha_{dst}, 1))\)</p>
+ * <p>\(C_{out} = max(0, min(C_{src} + C_{dst}, 1))\)</p>
+ */
+ PLUS(12),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_MODULATE.png" />
+ * <figcaption>Multiplies the source and destination pixels.</figcaption>
+ * </p>
+ * <p>\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)</p>
+ * <p>\(C_{out} = C_{src} * C_{dst}\)</p>
+ *
+ */
+ MODULATE(13),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_SCREEN.png" />
+ * <figcaption>
+ * Adds the source and destination pixels, then subtracts the
+ * source pixels multiplied by the destination.
+ * </figcaption>
+ * </p>
+ * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p>
+ * <p>\(C_{out} = C_{src} + C_{dst} - C_{src} * C_{dst}\)</p>
+ */
+ SCREEN(14),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_OVERLAY.png" />
+ * <figcaption>
+ * Multiplies or screens the source and destination depending on the
+ * destination color.
+ * </figcaption>
+ * </p>
+ * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p>
+ * <p>\(\begin{equation}
+ * C_{out} = \begin{cases} 2 * C_{src} * C_{dst} & 2 * C_{dst} \lt \alpha_{dst} \\
+ * \alpha_{src} * \alpha_{dst} - 2 (\alpha_{dst} - C_{src}) (\alpha_{src} - C_{dst}) &
+ * otherwise \end{cases}
+ * \end{equation}\)</p>
+ */
+ OVERLAY(15),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_DARKEN.png" />
+ * <figcaption>
+ * Retains the smallest component of the source and
+ * destination pixels.
+ * </figcaption>
+ * </p>
+ * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p>
+ * <p>
+ * \(C_{out} =
+ * (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst} + min(C_{src}, C_{dst})\)
+ * </p>
+ */
+ DARKEN(16),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_LIGHTEN.png" />
+ * <figcaption>Retains the largest component of the source and
+ * destination pixel.</figcaption>
+ * </p>
+ * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p>
+ * <p>
+ * \(C_{out} =
+ * (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst} + max(C_{src}, C_{dst})\)
+ * </p>
+ */
+ LIGHTEN(17),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_COLOR_DODGE.png" />
+ * <figcaption>Makes destination brighter to reflect source.</figcaption>
+ * </p>
+ * <p>
+ * \(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)
+ * </p>
+ * <p>
+ * \begin{equation}
+ * C_{out} =
+ * \begin{cases}
+ * C_{src} * (1 - \alpha_{dst}) & C_{dst} = 0 \\
+ * C_{src} + \alpha_{dst}*(1 - \alpha_{src}) & C_{src} = \alpha_{src} \\
+ * \alpha_{src} * min(\alpha_{dst}, C_{dst} * \alpha_{src}/(\alpha_{src} - C_{src}))
+ * + C_{src} *(1 - \alpha_{dst} + \alpha_{dst}*(1 - \alpha_{src}) & otherwise
+ * \end{cases}
+ * \end{equation}
+ * </p>
+ */
+ COLOR_DODGE(18),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_COLOR_BURN.png" />
+ * <figcaption>Makes destination darker to reflect source.</figcaption>
+ * </p>
+ * <p>
+ * \(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)
+ * </p>
+ * <p>
+ * \begin{equation}
+ * C_{out} =
+ * \begin{cases}
+ * C_{dst} + C_{src}*(1 - \alpha_{dst}) & C_{dst} = \alpha_{dst} \\
+ * \alpha_{dst}*(1 - \alpha_{src}) & C_{src} = 0 \\
+ * \alpha_{src}*(\alpha_{dst} - min(\alpha_{dst}, (\alpha_{dst}
+ * - C_{dst})*\alpha_{src}/C_{src}))
+ * + C_{src} * (1 - \alpha_{dst}) + \alpha_{dst}*(1-\alpha_{src}) & otherwise
+ * \end{cases}
+ * \end{equation}
+ * </p>
+ */
+ COLOR_BURN(19),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_HARD_LIGHT.png" />
+ * <figcaption>Makes destination lighter or darker, depending on source.</figcaption>
+ * </p>
+ * <p>
+ * \(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)
+ * </p>
+ * <p>
+ * \begin{equation}
+ * C_{out} =
+ * \begin{cases}
+ * 2*C_{src}*C_{dst} & C_{src}*(1-\alpha_{dst}) + C_{dst}*(1-\alpha_{src}) + 2*C_{src}
+ * \leq \alpha_{src} \\
+ * \alpha_{src}*\alpha_{dst}- 2*(\alpha_{dst} - C_{dst})*(\alpha_{src} - C_{src})
+ * & otherwise
+ * \end{cases}
+ * \end{equation}
+ * </p>
+ */
+ HARD_LIGHT(20),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_SOFT_LIGHT.png" />
+ * <figcaption>Makes destination lighter or darker, depending on source.</figcaption>
+ * </p>
+ * <p>
+ * Where
+ * \begin{equation}
+ * m =
+ * \begin{cases}
+ * C_{dst} / \alpha_{dst} & \alpha_{dst} \gt 0 \\
+ * 0 & otherwise
+ * \end{cases}
+ * \end{equation}
+ * </p>
+ * <p>
+ * \begin{equation}
+ * g =
+ * \begin{cases}
+ * (16 * m * m + 4 * m) * (m - 1) + 7 * m & 4 * C_{dst} \leq \alpha_{dst} \\
+ * \sqrt m - m & otherwise
+ * \end{cases}
+ * \end{equation}
+ * </p>
+ * <p>
+ * \begin{equation}
+ * f =
+ * \begin{cases}
+ * C_{dst} * (\alpha_{src} + (2 * C_{src} - \alpha_{src}) * (1 - m))
+ * & 2 * C_{src} \leq \alpha_{src} \\
+ * C_{dst} * \alpha_{src} + \alpha_{dst} * (2 * C_{src} - \alpha_{src}) * g
+ * & otherwise
+ * \end{cases}
+ * \end{equation}
+ * </p>
+ * <p>
+ * \begin{equation}
+ * \alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}
+ * \end{equation}
+ * \begin{equation}
+ * C_{out} = C_{src} / \alpha_{dst} + C_{dst} / \alpha_{src} + f
+ * \end{equation}
+ * </p>
+ */
+ SOFT_LIGHT(21),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_DIFFERENCE.png" />
+ * <figcaption>Subtracts darker from lighter with higher contrast.</figcaption>
+ * </p>
+ * <p>
+ * \begin{equation}
+ * \alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}
+ * \end{equation}
+ * </p>
+ * <p>
+ * \begin{equation}
+ * C_{out} = C_{src} + C_{dst} - 2 * min(C_{src}
+ * * \alpha_{dst}, C_{dst} * \alpha_{src})
+ * \end{equation}
+ * </p>
+ */
+ DIFFERENCE(22),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_DIFFERENCE.png" />
+ * <figcaption>Subtracts darker from lighter with lower contrast.</figcaption>
+ * </p>
+ * <p>
+ * \begin{equation}
+ * \alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}
+ * \end{equation}
+ * </p>
+ * <p>
+ * \begin{equation}
+ * C_{out} = C_{src} + C_{dst} - 2 * C_{src} * C_{dst}
+ * \end{equation}
+ * </p>
+ */
+ EXCLUSION(23),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_MODULATE.png" />
+ * <figcaption>Multiplies the source and destination pixels.</figcaption>
+ * </p>
+ * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p>
+ * <p>\(C_{out} =
+ * C_{src} * (1 - \alpha_{dst}) + C_{dst} * (1 - \alpha_{src}) + (C_{src} * C_{dst})\)
+ * </p>
+ */
+ MULTIPLY(24),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_HUE.png" />
+ * <figcaption>
+ * Replaces hue of destination with hue of source, leaving saturation
+ * and luminosity unchanged.
+ * </figcaption>
+ * </p>
+ */
+ HUE(25),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_SATURATION.png" />
+ * <figcaption>
+ * Replaces saturation of destination saturation hue of source, leaving hue and
+ * luminosity unchanged.
+ * </figcaption>
+ * </p>
+ */
+ SATURATION(26),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_COLOR.png" />
+ * <figcaption>
+ * Replaces hue and saturation of destination with hue and saturation of source,
+ * leaving luminosity unchanged.
+ * </figcaption>
+ * </p>
+ */
+ COLOR(27),
+
+ /**
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/blendmode_LUMINOSITY.png" />
+ * <figcaption>
+ * Replaces luminosity of destination with luminosity of source, leaving hue and
+ * saturation unchanged.
+ * </figcaption>
+ * </p>
+ */
+ LUMINOSITY(28);
+
+ private static final BlendMode[] BLEND_MODES = values();
+
+ /**
+ * @hide
+ */
+ public static @Nullable BlendMode fromValue(int value) {
+ for (BlendMode mode : BLEND_MODES) {
+ if (mode.mXfermode.porterDuffMode == value) {
+ return mode;
+ }
+ }
+ return null;
+ }
+
+ @NonNull
+ private final Xfermode mXfermode;
+
+ BlendMode(int mode) {
+ mXfermode = new Xfermode();
+ mXfermode.porterDuffMode = mode;
+ }
+
+ /**
+ * @hide
+ */
+ @NonNull
+ public Xfermode getXfermode() {
+ return mXfermode;
+ }
+}
diff --git a/graphics/java/android/graphics/BlendModeColorFilter.java b/graphics/java/android/graphics/BlendModeColorFilter.java
new file mode 100644
index 000000000000..7caeb4267ad2
--- /dev/null
+++ b/graphics/java/android/graphics/BlendModeColorFilter.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import android.annotation.ColorInt;
+import android.annotation.NonNull;
+
+/**
+ * A color filter that can be used to tint the source pixels using a single
+ * color and a specific {@link BlendMode}.
+ */
+public final class BlendModeColorFilter extends ColorFilter {
+
+ @ColorInt final int mColor;
+ private final BlendMode mMode;
+
+ public BlendModeColorFilter(@ColorInt int color, @NonNull BlendMode mode) {
+ mColor = color;
+ mMode = mode;
+ }
+
+
+ /**
+ * Returns the ARGB color used to tint the source pixels when this filter
+ * is applied.
+ *
+ * @see Color
+ *
+ */
+ @ColorInt
+ public int getColor() {
+ return mColor;
+ }
+
+ /**
+ * Returns the Porter-Duff mode used to composite this color filter's
+ * color with the source pixel when this filter is applied.
+ *
+ * @see BlendMode
+ *
+ */
+ public BlendMode getMode() {
+ return mMode;
+ }
+
+ @Override
+ long createNativeInstance() {
+ return native_CreateBlendModeFilter(mColor, mMode.getXfermode().porterDuffMode);
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (object == null || getClass() != object.getClass()) {
+ return false;
+ }
+ final BlendModeColorFilter other = (BlendModeColorFilter) object;
+ return other.mMode == mMode;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * mMode.hashCode() + mColor;
+ }
+
+ private static native long native_CreateBlendModeFilter(int srcColor, int blendmode);
+
+}
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 135c13703131..6798ab216734 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1684,12 +1684,26 @@ public class Canvas extends BaseCanvas {
*
* @param color the color to draw with
* @param mode the porter-duff mode to apply to the color
+ *
+ * @deprecated use {@link #drawColor(int, BlendMode)} instead
*/
+ @Deprecated
public void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
super.drawColor(color, mode);
}
/**
+ * Fill the entire canvas' bitmap (restricted to the current clip) with the specified color and
+ * blendmode.
+ *
+ * @param color the color to draw with
+ * @param mode the blendmode to apply to the color
+ */
+ public void drawColor(@ColorInt int color, @NonNull BlendMode mode) {
+ super.drawColor(color, mode);
+ }
+
+ /**
* Draw a line segment with the specified start and stop x,y coordinates, using the specified
* paint.
* <p>
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 69ff3bca6528..6821282bd0a7 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1168,12 +1168,29 @@ public class Paint {
* Get the paint's transfer mode object.
*
* @return the paint's transfer mode (or null)
+ *
+ * @deprecated use {@link #getBlendMode()} instead
*/
+ @Deprecated
public Xfermode getXfermode() {
return mXfermode;
}
/**
+ * Get the paint's blend mode object.
+ *
+ * @return the paint's blend mode (or null)
+ */
+ @Nullable
+ public BlendMode getBlendMode() {
+ if (mXfermode == null) {
+ return null;
+ } else {
+ return BlendMode.fromValue(mXfermode.porterDuffMode);
+ }
+ }
+
+ /**
* Set or clear the transfer mode object. A transfer mode defines how
* source pixels (generate by a drawing command) are composited with
* the destination pixels (content of the render target).
@@ -1185,8 +1202,17 @@ public class Paint {
*
* @param xfermode May be null. The xfermode to be installed in the paint
* @return xfermode
+ *
+ * @deprecated Use {@link #setBlendMode} to apply a Xfermode directly
+ * through usage of {@link BlendMode}
*/
+ @Deprecated
public Xfermode setXfermode(Xfermode xfermode) {
+ return installXfermode(xfermode);
+ }
+
+ @Nullable
+ private Xfermode installXfermode(Xfermode xfermode) {
int newMode = xfermode != null ? xfermode.porterDuffMode : Xfermode.DEFAULT;
int curMode = mXfermode != null ? mXfermode.porterDuffMode : Xfermode.DEFAULT;
if (newMode != curMode) {
@@ -1197,6 +1223,23 @@ public class Paint {
}
/**
+ * Set or clear the blend mode. A blend mode defines how source pixels
+ * (generated by a drawing command) are composited with the destination pixels
+ * (content of the render target).
+ * <p />
+ * Pass null to clear any previous blend mode.
+ * As a convenience, the parameter passed is also returned.
+ * <p />
+ *
+ * @see BlendMode
+ *
+ * @param blendmode May be null. The blend mode to be installed in the paint
+ */
+ public void setBlendMode(@Nullable BlendMode blendmode) {
+ installXfermode(blendmode != null ? blendmode.getXfermode() : null);
+ }
+
+ /**
* Get the paint's patheffect object.
*
* @return the paint's patheffect (or null)
diff --git a/graphics/java/android/graphics/PorterDuffColorFilter.java b/graphics/java/android/graphics/PorterDuffColorFilter.java
index 6665220c293c..c2a8eb7dbab1 100644
--- a/graphics/java/android/graphics/PorterDuffColorFilter.java
+++ b/graphics/java/android/graphics/PorterDuffColorFilter.java
@@ -23,7 +23,11 @@ import android.annotation.UnsupportedAppUsage;
/**
* A color filter that can be used to tint the source pixels using a single
* color and a specific {@link PorterDuff Porter-Duff composite mode}.
+ *
+ * @deprecated Consider using {@link BlendModeColorFilter} instead as it supports a wider
+ * set of blend modes than those defined in {@link PorterDuff.Mode}
*/
+@Deprecated
public class PorterDuffColorFilter extends ColorFilter {
@ColorInt
private int mColor;
@@ -71,7 +75,7 @@ public class PorterDuffColorFilter extends ColorFilter {
@Override
long createNativeInstance() {
- return native_CreatePorterDuffFilter(mColor, mMode.nativeInt);
+ return native_CreateBlendModeFilter(mColor, mMode.nativeInt);
}
@Override
@@ -91,5 +95,5 @@ public class PorterDuffColorFilter extends ColorFilter {
return 31 * mMode.hashCode() + mColor;
}
- private static native long native_CreatePorterDuffFilter(int srcColor, int porterDuffMode);
+ private static native long native_CreateBlendModeFilter(int srcColor, int blendmode);
}
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 5bd59d479876..09d0a581c2fc 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -595,7 +595,12 @@ public abstract class Drawable {
* <p class="note"><strong>Note:</strong> Setting a color filter disables
* {@link #setTintList(ColorStateList) tint}.
* </p>
+ *
+ * @see {@link #setColorFilter(ColorFilter)} }
+ * @deprecated use {@link #setColorFilter(ColorFilter)} with an instance
+ * of {@link android.graphics.BlendModeColorFilter}
*/
+ @Deprecated
public void setColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
if (getColorFilter() instanceof PorterDuffColorFilter) {
PorterDuffColorFilter existing = (PorterDuffColorFilter) getColorFilter();
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index f244f9f88684..74d6605a1ffb 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -26,6 +26,7 @@ android_app {
],
static_libs: [
+ "CarNotificationLib",
"SystemUI-core",
"SystemUIPluginLib",
"SystemUISharedLib",
diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml
index 452d61df5322..572737f92370 100644
--- a/packages/CarSystemUI/res/values/config.xml
+++ b/packages/CarSystemUI/res/values/config.xml
@@ -28,4 +28,31 @@
<bool name="config_enableRightNavigationBar">false</bool>
<bool name="config_enableBottomNavigationBar">true</bool>
+ <!-- SystemUI Services: The classes of the stuff to start. This is duplicated from core
+ SystemUi b/c it can't be overlayed at this level for now
+ -->
+ <string-array name="config_systemUIServiceComponents" translatable="false">
+ <item>com.android.systemui.Dependency</item>
+ <item>com.android.systemui.util.NotificationChannels</item>
+ <item>com.android.systemui.statusbar.CommandQueue$CommandQueueStart</item>
+ <item>com.android.systemui.keyguard.KeyguardViewMediator</item>
+ <item>com.android.systemui.recents.Recents</item>
+ <item>com.android.systemui.volume.VolumeUI</item>
+ <item>com.android.systemui.stackdivider.Divider</item>
+ <item>com.android.systemui.SystemBars</item>
+ <item>com.android.systemui.usb.StorageNotification</item>
+ <item>com.android.systemui.power.PowerUI</item>
+ <item>com.android.systemui.media.RingtonePlayer</item>
+ <item>com.android.systemui.keyboard.KeyboardUI</item>
+ <item>com.android.systemui.pip.PipUI</item>
+ <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
+ <item>@string/config_systemUIVendorServiceComponent</item>
+ <item>com.android.systemui.util.leak.GarbageMonitor$Service</item>
+ <item>com.android.systemui.LatencyTester</item>
+ <item>com.android.systemui.globalactions.GlobalActionsComponent</item>
+ <item>com.android.systemui.ScreenDecorations</item>
+ <item>com.android.systemui.fingerprint.FingerprintDialogImpl</item>
+ <item>com.android.systemui.SliceBroadcastRelayHandler</item>
+ <item>com.android.systemui.notifications.NotificationsUI</item>
+ </string-array>
</resources>
diff --git a/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java b/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java
new file mode 100644
index 000000000000..cb92c4259504
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.notifications;
+
+import android.car.Car;
+import android.car.CarNotConnectedException;
+import android.car.drivingstate.CarUxRestrictionsManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ServiceConnection;
+import android.graphics.PixelFormat;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+
+import com.android.car.notification.CarNotificationListener;
+import com.android.car.notification.CarUxRestrictionManagerWrapper;
+import com.android.car.notification.NotificationViewController;
+import com.android.car.notification.PreprocessingManager;
+import com.android.systemui.R;
+import com.android.systemui.SystemUI;
+
+/**
+ * Standalone SystemUI for displaying Notifications that have been designed to be used in the car
+ */
+public class NotificationsUI extends SystemUI {
+
+ private static final String TAG = "NotificationsUI";
+ private CarNotificationListener mCarNotificationListener;
+ private CarUxRestrictionsManager mCarUxRestrictionsManager;
+ private Car mCar;
+ private ViewGroup mCarNotificationWindow;
+ private NotificationViewController mNotificationViewController;
+ private boolean mIsShowing;
+ private CarUxRestrictionManagerWrapper mCarUxRestrictionManagerWrapper =
+ new CarUxRestrictionManagerWrapper();
+
+ /**
+ * Inits the window that hosts the notifications and establishes the connections
+ * to the car related services.
+ */
+ @Override
+ public void start() {
+ WindowManager windowManager =
+ (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+ mCarNotificationListener = new CarNotificationListener();
+ mCarNotificationListener.registerAsSystemService(mContext, mCarUxRestrictionManagerWrapper);
+ mCar = Car.createCar(mContext, mCarConnectionListener);
+ mCar.connect();
+
+
+ mCarNotificationWindow = (ViewGroup) View.inflate(mContext,
+ R.layout.navigation_bar_window, null);
+ View.inflate(mContext,
+ com.android.car.notification.R.layout.notification_center_activity,
+ mCarNotificationWindow);
+ mCarNotificationWindow.findViewById(
+ com.android.car.notification.R.id.exit_button_container)
+ .setOnClickListener(v -> toggleShowingCarNotifications());
+
+ WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+ PixelFormat.TRANSLUCENT);
+ layoutParams.setTitle("Car Notification Window");
+ // start in the hidden state
+ mCarNotificationWindow.setVisibility(View.GONE);
+ windowManager.addView(mCarNotificationWindow, layoutParams);
+ mNotificationViewController = new NotificationViewController(
+ mCarNotificationWindow
+ .findViewById(com.android.car.notification.R.id.notification_view),
+ PreprocessingManager.getInstance(mContext),
+ mCarNotificationListener,
+ mCarUxRestrictionManagerWrapper
+ );
+ // Add to the SystemUI component registry
+ putComponent(NotificationsUI.class, this);
+ }
+
+ /**
+ * Connection callback to establish UX Restrictions
+ */
+ private ServiceConnection mCarConnectionListener = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ try {
+ mCarUxRestrictionsManager = (CarUxRestrictionsManager) mCar.getCarManager(
+ Car.CAR_UX_RESTRICTION_SERVICE);
+ mCarUxRestrictionManagerWrapper
+ .setCarUxRestrictionsManager(mCarUxRestrictionsManager);
+ PreprocessingManager preprocessingManager = PreprocessingManager.getInstance(
+ mContext);
+ preprocessingManager
+ .setCarUxRestrictionManagerWrapper(mCarUxRestrictionManagerWrapper);
+ } catch (CarNotConnectedException e) {
+ Log.e(TAG, "Car not connected in CarConnectionListener", e);
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Log.e(TAG, "Car service disconnected unexpectedly");
+ }
+ };
+
+ /**
+ * Toggles the visiblity of the notifications
+ */
+ public void toggleShowingCarNotifications() {
+ if (mCarNotificationWindow.getVisibility() == View.VISIBLE) {
+ closeCarNotifications();
+ return;
+ }
+ openCarNotifications();
+ }
+
+ /**
+ * Hides the notifications
+ */
+ public void closeCarNotifications() {
+ mCarNotificationWindow.setVisibility(View.GONE);
+ mNotificationViewController.disable();
+ mIsShowing = false;
+ }
+
+ /**
+ * Sets the notifications to visible
+ */
+ public void openCarNotifications() {
+ mCarNotificationWindow.setVisibility(View.VISIBLE);
+ mNotificationViewController.enable();
+ mIsShowing = true;
+ }
+
+ /**
+ * Returns {@code true} if notifications are currently on the screen
+ */
+ public boolean isShowing() {
+ return mIsShowing;
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
index 81f7846b357d..0cba351a8a9c 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
@@ -21,7 +21,6 @@ import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
-import com.android.keyguard.AlphaOptimizedImageButton;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -34,7 +33,7 @@ import com.android.systemui.statusbar.phone.StatusBarIconController;
*/
class CarNavigationBarView extends LinearLayout {
private View mNavButtons;
- private AlphaOptimizedImageButton mNotificationsButton;
+ private CarFacetButton mNotificationsButton;
private CarStatusBar mCarStatusBar;
private Context mContext;
private View mLockScreenButtons;
@@ -71,7 +70,7 @@ class CarNavigationBarView extends LinearLayout {
}
protected void onNotificationsClick(View v) {
- mCarStatusBar.togglePanel();
+ mCarStatusBar.toggleCarNotifications();
}
/**
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 2d90f8f0afd9..5da236ceb211 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -35,6 +35,7 @@ import com.android.systemui.R;
import com.android.systemui.classifier.FalsingLog;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.notifications.NotificationsUI;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qs.car.CarQSFragment;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -587,4 +588,9 @@ public class CarStatusBar extends StatusBar implements
private Drawable getDefaultWallpaper() {
return mContext.getDrawable(com.android.internal.R.drawable.default_wallpaper);
}
+
+ public void toggleCarNotifications() {
+ getComponent(NotificationsUI.class).toggleShowingCarNotifications();
+ }
+
}
diff --git a/packages/ExtServices/AndroidManifest.xml b/packages/ExtServices/AndroidManifest.xml
index ff70e9712bcc..010a810cd791 100644
--- a/packages/ExtServices/AndroidManifest.xml
+++ b/packages/ExtServices/AndroidManifest.xml
@@ -63,6 +63,13 @@
android:resource="@array/autofill_field_classification_available_algorithms" />
</service>
+ <service android:name=".sms.FinancialSmsServiceImpl"
+ android:permission="android.permission.BIND_FINANCIAL_SMS_SERVICE">
+ <intent-filter>
+ <action android:name="android.service.sms.action.FINANCIAL_SERVICE_INTENT" />
+ </intent-filter>
+ </service>
+
<library android:name="android.ext.services"/>
</application>
diff --git a/packages/ExtServices/src/android/ext/services/sms/FinancialSmsServiceImpl.java b/packages/ExtServices/src/android/ext/services/sms/FinancialSmsServiceImpl.java
new file mode 100644
index 000000000000..ab71802102ae
--- /dev/null
+++ b/packages/ExtServices/src/android/ext/services/sms/FinancialSmsServiceImpl.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.ext.services.sms;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.database.Cursor;
+import android.database.CursorWindow;
+import android.net.Uri;
+import android.os.Bundle;
+import android.service.sms.FinancialSmsService;
+import android.util.Log;
+
+import java.util.ArrayList;
+/**
+ * Service to provide financial apps access to sms messages.
+ */
+public class FinancialSmsServiceImpl extends FinancialSmsService {
+
+ private static final String TAG = "FinancialSmsServiceImpl";
+ private static final String KEY_COLUMN_NAMES = "column_names";
+
+ @Nullable
+ @Override
+ public CursorWindow onGetSmsMessages(@NonNull Bundle params) {
+ ArrayList<String> columnNames = params.getStringArrayList(KEY_COLUMN_NAMES);
+ if (columnNames == null || columnNames.size() <= 0) {
+ return null;
+ }
+
+ Uri inbox = Uri.parse("content://sms/inbox");
+
+ try (Cursor cursor = getContentResolver().query(inbox, null, null, null, null);
+ CursorWindow window = new CursorWindow("FinancialSmsMessages")) {
+ int messageCount = cursor.getCount();
+ if (messageCount > 0 && cursor.moveToFirst()) {
+ window.setNumColumns(columnNames.size());
+ for (int row = 0; row < messageCount; row++) {
+ if (!window.allocRow()) {
+ Log.e(TAG, "CursorWindow ran out of memory.");
+ return null;
+ }
+ for (int col = 0; col < columnNames.size(); col++) {
+ String columnName = columnNames.get(col);
+ int inboxColumnIndex = cursor.getColumnIndexOrThrow(columnName);
+ String inboxColumnValue = cursor.getString(inboxColumnIndex);
+ boolean addedToCursorWindow = window.putString(inboxColumnValue, row, col);
+ if (!addedToCursorWindow) {
+ Log.e(TAG, "Failed to add:"
+ + inboxColumnValue
+ + ";column:"
+ + columnName);
+ return null;
+ }
+ }
+ cursor.moveToNext();
+ }
+ } else {
+ Log.w(TAG, "No sms messages.");
+ }
+ return window;
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to get sms messages.");
+ return null;
+ }
+ }
+}
diff --git a/packages/ExtServices/tests/src/android/ext/services/sms/FinancialSmsServiceImplTest.java b/packages/ExtServices/tests/src/android/ext/services/sms/FinancialSmsServiceImplTest.java
new file mode 100644
index 000000000000..12575a63d0ad
--- /dev/null
+++ b/packages/ExtServices/tests/src/android/ext/services/sms/FinancialSmsServiceImplTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.ext.services.sms;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Bundle;
+
+import org.junit.Test;
+
+/**
+ * Contains the base tests for FinancialSmsServiceImpl.
+ */
+public class FinancialSmsServiceImplTest {
+
+ private final FinancialSmsServiceImpl mService = new FinancialSmsServiceImpl();
+
+ @Test
+ public void testOnGetSmsMessages_nullWithNoParamData() {
+ assertThat(mService.onGetSmsMessages(new Bundle())).isNull();
+ }
+}
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
index 0b9a7b226105..294bd50fcf8b 100644
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -24,7 +24,8 @@
android:orientation="vertical"
android:paddingBottom="8dp"
android:visibility="invisible"
- android:elevation="4dp" >
+ android:elevation="4dp"
+ android:importantForAccessibility="no" >
<include
android:id="@+id/qs_detail_header"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 6cec36a81e5a..91b34fc875bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -916,6 +916,10 @@ public class NotificationShelf extends ActivatableNotificationView implements
updateRelativeOffset();
}
+ public void onUiModeChanged() {
+ updateBackgroundColors();
+ }
+
private class ShelfState extends ExpandableViewState {
private float openedAmount;
private boolean hasItemsInStableShelf;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 7876b24112e0..1d79152bb1cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -225,7 +225,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
initDimens();
}
- public void onUiModeChanged() {
+ protected void updateBackgroundColors() {
updateColors();
initBackground();
updateBackgroundTint();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 8bed3663cf49..383446c00d37 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -121,6 +121,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private static final int MENU_VIEW_INDEX = 0;
private static final String TAG = "ExpandableNotifRow";
public static final float DEFAULT_HEADER_VISIBLE_AMOUNT = 1.0f;
+ private boolean mUpdateBackgroundOnUpdate;
/**
* Listener for when {@link ExpandableNotificationRow} is laid out.
@@ -587,6 +588,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
updateIconVisibilities();
updateShelfIconColor();
updateRippleAllowed();
+ if (mUpdateBackgroundOnUpdate) {
+ mUpdateBackgroundOnUpdate = false;
+ updateBackgroundColors();
+ }
}
/** Called when the notification's ranking was changed (but nothing else changed). */
@@ -1212,9 +1217,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
- @Override
public void onUiModeChanged() {
- super.onUiModeChanged();
+ mUpdateBackgroundOnUpdate = true;
reInflateViews();
if (mChildrenContainer != null) {
for (ExpandableNotificationRow child : mChildrenContainer.getNotificationChildren()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index eca1a1411212..dbe6e8ec764d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -641,15 +641,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
public void onUiModeChanged() {
mBgColor = mContext.getColor(R.color.notification_shade_background_color);
updateBackgroundDimming();
-
- // Re-inflate all notification views
- int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = getChildAt(i);
- if (child instanceof ActivatableNotificationView) {
- ((ActivatableNotificationView) child).onUiModeChanged();
- }
- }
+ mShelf.onUiModeChanged();
}
@ShadeViewRefactor(RefactorComponent.DECORATOR)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index a2a11bbfd650..c7e4d340b7d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -105,10 +105,22 @@ public class NotificationPanelView extends PanelView implements
private static final boolean DEBUG = false;
- private static final boolean EXPAND_ON_WAKE_UP = SystemProperties.getBoolean(
+ /**
+ * If passive interrupts expand the NSSL or not
+ */
+ private static final boolean EXPAND_ON_PASSIVE_INTERRUPT = SystemProperties.getBoolean(
"persist.sysui.expand_shade_on_wake_up", true);
+ /**
+ * If the notification panel should remain collapsed when the phone wakes up, even if the user
+ * presses power.
+ */
+ private static final boolean NEVER_EXPAND_WHEN_WAKING_UP = SystemProperties.getBoolean(
+ "persist.sysui.defer_notifications_on_lock_screen", false);
+ /**
+ * If waking up the phone should take you to SHADE_LOCKED instead of KEYGUARD
+ */
private static final boolean WAKE_UP_TO_SHADE = SystemProperties.getBoolean(
- "persist.sysui.go_to_shade_on_wake_up", true);
+ "persist.sysui.go_to_shade_on_wake_up", false);
/**
* Fling expanding QS.
@@ -2774,10 +2786,12 @@ public class NotificationPanelView extends PanelView implements
}
public void setDozing(boolean dozing, boolean animate, PointF wakeUpTouchLocation,
- boolean passiveInterrupted) {
+ boolean passivelyInterrupted) {
if (dozing == mDozing) return;
mDozing = dozing;
- mSemiAwake = !EXPAND_ON_WAKE_UP && !mDozing && passiveInterrupted;
+ boolean doNotExpand = (!EXPAND_ON_PASSIVE_INTERRUPT && passivelyInterrupted)
+ || NEVER_EXPAND_WHEN_WAKING_UP;
+ mSemiAwake = doNotExpand && !mDozing;
if (!mSemiAwake) {
mNotificationStackScroller.setDark(mDozing, animate, wakeUpTouchLocation);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index acdd5e995322..261f117b58b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -67,6 +67,8 @@ import com.android.systemui.statusbar.notification.stack.NotificationListContain
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import java.util.ArrayList;
+
public class StatusBarNotificationPresenter implements NotificationPresenter,
ConfigurationController.ConfigurationListener {
@@ -105,6 +107,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
private final int mMaxAllowedKeyguardNotifications;
private final IStatusBarService mBarService;
private boolean mReinflateNotificationsOnUserSwitched;
+ private boolean mDispatchUiModeChangeOnUserSwitched;
private final UnlockMethodCache mUnlockMethodCache;
private TextView mNotificationPanelDebugText;
@@ -187,6 +190,27 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
}
@Override
+ public void onUiModeChanged() {
+ if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) {
+ updateNotificationOnUiModeChanged();
+ } else {
+ mDispatchUiModeChangeOnUserSwitched = true;
+ }
+ }
+
+ private void updateNotificationOnUiModeChanged() {
+ ArrayList<Entry> userNotifications
+ = mEntryManager.getNotificationData().getNotificationsForCurrentUser();
+ for (int i = 0; i < userNotifications.size(); i++) {
+ Entry entry = userNotifications.get(i);
+ ExpandableNotificationRow row = entry.getRow();
+ if (row != null) {
+ row.onUiModeChanged();
+ }
+ }
+ }
+
+ @Override
public boolean isCollapsing() {
return mNotificationPanel.isCollapsing()
|| mActivityLaunchAnimator.isAnimationPending()
@@ -301,6 +325,10 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
mEntryManager.updateNotificationsOnDensityOrFontScaleChanged();
mReinflateNotificationsOnUserSwitched = false;
}
+ if (mDispatchUiModeChangeOnUserSwitched) {
+ updateNotificationOnUiModeChanged();
+ mDispatchUiModeChangeOnUserSwitched = false;
+ }
updateNotificationViews();
mMediaManager.clearCurrentMediaNotification();
mShadeController.setLockscreenUser(newUserId);
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 2d3064017719..eb0090be4747 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6637,6 +6637,11 @@ message MetricsEvent {
// OS: Q
SETTINGS_WIFI_DPP_ENROLLEE = 1596;
+ // OPEN: Settings > Apps & Notifications -> Special app access -> Financial Apps Sms Access
+ // CATEGORY: SETTINGS
+ // OS: Q
+ SETTINGS_FINANCIAL_APPS_SMS_ACCESS = 1597;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 4b092b299029..33a74d35cf85 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -16,6 +16,15 @@
package com.android.server;
+import static android.Manifest.permission.INSTALL_PACKAGES;
+import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
+import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
import static android.os.storage.OnObbStateChangeListener.ERROR_ALREADY_MOUNTED;
@@ -27,9 +36,11 @@ import static android.os.storage.OnObbStateChangeListener.ERROR_PERMISSION_DENIE
import static android.os.storage.OnObbStateChangeListener.MOUNTED;
import static android.os.storage.OnObbStateChangeListener.UNMOUNTED;
+import static com.android.internal.util.XmlUtils.readBooleanAttribute;
import static com.android.internal.util.XmlUtils.readIntAttribute;
import static com.android.internal.util.XmlUtils.readLongAttribute;
import static com.android.internal.util.XmlUtils.readStringAttribute;
+import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.internal.util.XmlUtils.writeStringAttribute;
@@ -51,7 +62,9 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
import android.content.pm.IPackageMoveObserver;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ProviderInfo;
@@ -116,12 +129,14 @@ import android.util.TimeUtils;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.IAppOpsService;
import com.android.internal.os.AppFuseMount;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.FuseUnavailableMountException;
import com.android.internal.os.SomeArgs;
import com.android.internal.os.Zygote;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.HexDump;
@@ -204,7 +219,9 @@ class StorageManagerService extends IStorageManager.Stub
@Override
public void onBootPhase(int phase) {
- if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+ mStorageManagerService.servicesReady();
+ } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
mStorageManagerService.systemReady();
} else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
mStorageManagerService.bootCompleted();
@@ -261,6 +278,7 @@ class StorageManagerService extends IStorageManager.Stub
private static final String TAG_VOLUMES = "volumes";
private static final String ATTR_VERSION = "version";
private static final String ATTR_PRIMARY_STORAGE_UUID = "primaryStorageUuid";
+ private static final String ATTR_ISOLATED_STORAGE = "isolatedStorage";
private static final String TAG_VOLUME = "volume";
private static final String ATTR_TYPE = "type";
private static final String ATTR_FS_UUID = "fsUuid";
@@ -311,6 +329,10 @@ class StorageManagerService extends IStorageManager.Stub
@GuardedBy("mLock")
private String mPrimaryStorageUuid;
+ /** Flag indicating isolated storage state of last boot */
+ @GuardedBy("mLock")
+ private boolean mLastIsolatedStorage = false;
+
/** Map from disk ID to latches */
@GuardedBy("mLock")
private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();
@@ -453,6 +475,9 @@ class StorageManagerService extends IStorageManager.Stub
private UserManagerInternal mUmInternal;
private ActivityManagerInternal mAmInternal;
+ private IPackageManager mIPackageManager;
+ private IAppOpsService mIAppOpsService;
+
private final Callbacks mCallbacks;
private final LockPatternUtils mLockPatternUtils;
@@ -1565,11 +1590,83 @@ class StorageManagerService extends IStorageManager.Stub
}
}
+ private void servicesReady() {
+ synchronized (mLock) {
+ final boolean thisIsolatedStorage = StorageManager.hasIsolatedStorage();
+ if (mLastIsolatedStorage == thisIsolatedStorage) {
+ // Nothing changed since last boot; keep rolling forward
+ return;
+ } else if (thisIsolatedStorage) {
+ // This boot enables isolated storage; apply legacy behavior
+ applyLegacyStorage();
+ }
+
+ // Always remember the new state we just booted with
+ writeSettingsLocked();
+ }
+ }
+
+ /**
+ * If we're enabling isolated storage, we need to remember which existing
+ * apps have already been using shared storage, and grant them legacy access
+ * to keep them running smoothly.
+ */
+ private void applyLegacyStorage() {
+ final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
+ final UserManagerInternal um = LocalServices.getService(UserManagerInternal.class);
+ for (int userId : um.getUserIds()) {
+ final PackageManager pm;
+ try {
+ pm = mContext.createPackageContextAsUser(mContext.getPackageName(),
+ 0, UserHandle.of(userId)).getPackageManager();
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+
+ final List<PackageInfo> pkgs = pm.getPackagesHoldingPermissions(new String[] {
+ android.Manifest.permission.READ_EXTERNAL_STORAGE,
+ android.Manifest.permission.WRITE_EXTERNAL_STORAGE
+ }, MATCH_UNINSTALLED_PACKAGES | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
+ for (PackageInfo pkg : pkgs) {
+ final int uid = pkg.applicationInfo.uid;
+ final String packageName = pkg.applicationInfo.packageName;
+
+ final long lastAccess = getLastAccessTime(appOps, uid, packageName, new int[] {
+ AppOpsManager.OP_READ_EXTERNAL_STORAGE,
+ AppOpsManager.OP_WRITE_EXTERNAL_STORAGE,
+ });
+
+ Log.d(TAG, "Found " + uid + " " + packageName
+ + " with granted storage access, last accessed " + lastAccess);
+ if (lastAccess > 0) {
+ appOps.setMode(AppOpsManager.OP_LEGACY_STORAGE,
+ uid, packageName, AppOpsManager.MODE_ALLOWED);
+ }
+ }
+ }
+ }
+
+ private static long getLastAccessTime(AppOpsManager manager,
+ int uid, String packageName, int[] ops) {
+ long maxTime = 0;
+ final List<AppOpsManager.PackageOps> pkgs = manager.getOpsForPackage(uid, packageName, ops);
+ for (AppOpsManager.PackageOps pkg : CollectionUtils.defeatNullable(pkgs)) {
+ for (AppOpsManager.OpEntry op : CollectionUtils.defeatNullable(pkg.getOps())) {
+ maxTime = Math.max(maxTime, op.getLastAccessTime());
+ }
+ }
+ return maxTime;
+ }
+
private void systemReady() {
LocalServices.getService(ActivityTaskManagerInternal.class)
.registerScreenObserver(this);
mSystemReady = true;
+ mIPackageManager = IPackageManager.Stub.asInterface(
+ ServiceManager.getService("package"));
+ mIAppOpsService = IAppOpsService.Stub.asInterface(
+ ServiceManager.getService(Context.APP_OPS_SERVICE));
mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
}
@@ -1589,6 +1686,7 @@ class StorageManagerService extends IStorageManager.Stub
private void readSettingsLocked() {
mRecords.clear();
mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
+ mLastIsolatedStorage = false;
FileInputStream fis = null;
try {
@@ -1610,6 +1708,8 @@ class StorageManagerService extends IStorageManager.Stub
mPrimaryStorageUuid = readStringAttribute(in,
ATTR_PRIMARY_STORAGE_UUID);
}
+ mLastIsolatedStorage = readBooleanAttribute(in,
+ ATTR_ISOLATED_STORAGE, false);
} else if (TAG_VOLUME.equals(tag)) {
final VolumeRecord rec = readVolumeRecord(in);
@@ -1640,6 +1740,7 @@ class StorageManagerService extends IStorageManager.Stub
out.startTag(null, TAG_VOLUMES);
writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY);
writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
+ writeBooleanAttribute(out, ATTR_ISOLATED_STORAGE, StorageManager.hasIsolatedStorage());
final int size = mRecords.size();
for (int i = 0; i < size; i++) {
final VolumeRecord rec = mRecords.valueAt(i);
@@ -2906,7 +3007,7 @@ class StorageManagerService extends IStorageManager.Stub
}
if (!foundPrimary) {
- Log.w(TAG, "No primary storage defined yet; hacking together a stub");
+ Slog.w(TAG, "No primary storage defined yet; hacking together a stub");
final boolean primaryPhysical = SystemProperties.getBoolean(
StorageManager.PROP_PRIMARY_PHYSICAL, false);
@@ -3117,7 +3218,8 @@ class StorageManagerService extends IStorageManager.Stub
throw new SecurityException("Shady looking path " + path);
}
- if (!mAmInternal.isAppStorageSandboxed(pid, uid)) {
+ final int mountMode = mAmInternal.getStorageMountMode(pid, uid);
+ if (mountMode == Zygote.MOUNT_EXTERNAL_FULL) {
return path;
}
@@ -3126,6 +3228,11 @@ class StorageManagerService extends IStorageManager.Stub
final String device = m.group(1);
final String devicePath = m.group(2);
+ if (mountMode == Zygote.MOUNT_EXTERNAL_INSTALLER
+ && devicePath.startsWith("Android/obb/")) {
+ return path;
+ }
+
// Does path belong to any packages belonging to this UID? If so,
// they get to go straight through to legacy paths.
final String[] pkgs = mContext.getPackageManager().getPackagesForUid(uid);
@@ -3477,6 +3584,31 @@ class StorageManagerService extends IStorageManager.Stub
}
}
+ private int getMountMode(int uid, String packageName) {
+ try {
+ if (Process.isIsolated(uid)) {
+ return Zygote.MOUNT_EXTERNAL_NONE;
+ }
+ if (mIPackageManager.checkUidPermission(WRITE_MEDIA_STORAGE, uid)
+ == PERMISSION_GRANTED) {
+ return Zygote.MOUNT_EXTERNAL_FULL;
+ } else if (mIAppOpsService.checkOperation(OP_LEGACY_STORAGE, uid,
+ packageName) == MODE_ALLOWED) {
+ // TODO: define a specific "legacy" mount mode
+ return Zygote.MOUNT_EXTERNAL_FULL;
+ } else if (mIPackageManager.checkUidPermission(INSTALL_PACKAGES, uid)
+ == PERMISSION_GRANTED || mIAppOpsService.checkOperation(
+ OP_REQUEST_INSTALL_PACKAGES, uid, packageName) == MODE_ALLOWED) {
+ return Zygote.MOUNT_EXTERNAL_INSTALLER;
+ } else {
+ return Zygote.MOUNT_EXTERNAL_WRITE;
+ }
+ } catch (RemoteException e) {
+ // Should not happen
+ }
+ return Zygote.MOUNT_EXTERNAL_NONE;
+ }
+
private static class Callbacks extends Handler {
private static final int MSG_STORAGE_STATE_CHANGED = 1;
private static final int MSG_VOLUME_STATE_CHANGED = 2;
@@ -3718,6 +3850,9 @@ class StorageManagerService extends IStorageManager.Stub
@Override
public int getExternalStorageMountMode(int uid, String packageName) {
+ if (ENABLE_ISOLATED_STORAGE) {
+ return getMountMode(uid, packageName);
+ }
// No locking - CopyOnWriteArrayList
int mountMode = Integer.MAX_VALUE;
for (ExternalStorageMountPolicy policy : mPolicies) {
@@ -3754,6 +3889,9 @@ class StorageManagerService extends IStorageManager.Stub
if (uid == Process.SYSTEM_UID) {
return true;
}
+ if (ENABLE_ISOLATED_STORAGE) {
+ return getMountMode(uid, packageName) != Zygote.MOUNT_EXTERNAL_NONE;
+ }
// No locking - CopyOnWriteArrayList
for (ExternalStorageMountPolicy policy : mPolicies) {
final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index f7acf7e83200..8751d24bcf67 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2019,6 +2019,13 @@ public final class ActiveServices {
ComponentName className = new ComponentName(
sInfo.applicationInfo.packageName, sInfo.name);
ComponentName name = comp != null ? comp : className;
+ if (!mAm.validateAssociationAllowedLocked(callingPackage, callingUid,
+ name.getPackageName(), sInfo.applicationInfo.uid)) {
+ String msg = "association not allowed between packages "
+ + callingPackage + " and " + r.packageName;
+ Slog.w(TAG, "Service lookup failed: " + msg);
+ return new ServiceLookupResult(null, msg);
+ }
if ((sInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0) {
if (isBindExternal) {
if (!sInfo.exported) {
@@ -2099,6 +2106,17 @@ public final class ActiveServices {
}
}
if (r != null) {
+ if (!mAm.validateAssociationAllowedLocked(callingPackage, callingUid, r.packageName,
+ r.appInfo.uid)) {
+ String msg = "association not allowed between packages "
+ + callingPackage + " and " + r.packageName;
+ Slog.w(TAG, "Service lookup failed: " + msg);
+ return new ServiceLookupResult(null, msg);
+ }
+ if (!mAm.mIntentFirewall.checkService(r.name, service, callingUid, callingPid,
+ resolvedType, r.appInfo)) {
+ return new ServiceLookupResult(null, "blocked by firewall");
+ }
if (mAm.checkComponentPermission(r.permission,
callingPid, callingUid, r.appInfo.uid, r.exported) != PERMISSION_GRANTED) {
if (!r.exported) {
@@ -2125,11 +2143,6 @@ public final class ActiveServices {
return null;
}
}
-
- if (!mAm.mIntentFirewall.checkService(r.name, service, callingUid, callingPid,
- resolvedType, r.appInfo)) {
- return null;
- }
return new ServiceLookupResult(r, null);
}
return null;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 69cfcc21cb19..6700a530edc0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -658,6 +658,12 @@ public class ActivityManagerService extends IActivityManager.Stub
ArraySet<String> mBackgroundLaunchBroadcasts;
/**
+ * When an app has restrictions on the other apps that can have associations with it,
+ * it appears here with a set of the allowed apps.
+ */
+ ArrayMap<String, ArraySet<String>> mAllowedAssociations;
+
+ /**
* All of the processes we currently have running organized by pid.
* The keys are the pid running the application.
*
@@ -2396,6 +2402,34 @@ public class ActivityManagerService extends IActivityManager.Stub
return mBackgroundLaunchBroadcasts;
}
+ boolean validateAssociationAllowedLocked(String pkg1, int uid1, String pkg2, int uid2) {
+ if (mAllowedAssociations == null) {
+ mAllowedAssociations = SystemConfig.getInstance().getAllowedAssociations();
+ }
+ // Interactions with the system uid are always allowed, since that is the core system
+ // that everyone needs to be able to interact with.
+ if (UserHandle.getAppId(uid1) == SYSTEM_UID) {
+ return true;
+ }
+ if (UserHandle.getAppId(uid2) == SYSTEM_UID) {
+ return true;
+ }
+ // We won't allow this association if either pkg1 or pkg2 has a limit on the
+ // associations that are allowed with it, and the other package is not explicitly
+ // specified as one of those associations.
+ ArraySet<String> pkgs = mAllowedAssociations.get(pkg1);
+ if (pkgs != null) {
+ if (!pkgs.contains(pkg2)) {
+ return false;
+ }
+ }
+ pkgs = mAllowedAssociations.get(pkg2);
+ if (pkgs != null) {
+ return pkgs.contains(pkg1);
+ }
+ return true;
+ }
+
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
@@ -6264,6 +6298,21 @@ public class ActivityManagerService extends IActivityManager.Stub
return state != 'Z' && state != 'X' && state != 'x' && state != 'K';
}
+ private String checkContentProviderAssociation(ProcessRecord callingApp, int callingUid,
+ ProviderInfo cpi) {
+ if (callingApp == null) {
+ return validateAssociationAllowedLocked(cpi.packageName, cpi.applicationInfo.uid,
+ null, callingUid) ? null : "<null>";
+ }
+ for (int i = callingApp.pkgList.size() - 1; i >= 0; i--) {
+ if (!validateAssociationAllowedLocked(callingApp.pkgList.keyAt(i), callingApp.uid,
+ cpi.packageName, cpi.applicationInfo.uid)) {
+ return cpi.packageName;
+ }
+ }
+ return null;
+ }
+
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, int callingUid, String callingTag, boolean stable,
int userId) {
@@ -6335,6 +6384,11 @@ public class ActivityManagerService extends IActivityManager.Stub
String msg;
if (r != null && cpr.canRunHere(r)) {
+ if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
+ throw new SecurityException("Content provider lookup "
+ + cpr.name.flattenToShortString()
+ + " failed: association not allowed with package " + msg);
+ }
checkTime(startTime,
"getContentProviderImpl: before checkContentProviderPermission");
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
@@ -6364,6 +6418,11 @@ public class ActivityManagerService extends IActivityManager.Stub
} catch (RemoteException e) {
}
+ if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
+ throw new SecurityException("Content provider lookup "
+ + cpr.name.flattenToShortString()
+ + " failed: association not allowed with package " + msg);
+ }
checkTime(startTime,
"getContentProviderImpl: before checkContentProviderPermission");
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
@@ -6461,6 +6520,11 @@ public class ActivityManagerService extends IActivityManager.Stub
checkTime(startTime, "getContentProviderImpl: got app info for user");
String msg;
+ if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
+ throw new SecurityException("Content provider lookup "
+ + cpr.name.flattenToShortString()
+ + " failed: association not allowed with package " + msg);
+ }
checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
!= null) {
@@ -9207,6 +9271,12 @@ public class ActivityManagerService extends IActivityManager.Stub
pw.println("-------------------------------------------------------------------------------");
}
+ dumpAllowedAssociationsLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+
+ }
mPendingIntentController.dumpPendingIntents(pw, dumpAll, dumpPackage);
pw.println();
if (dumpAll) {
@@ -9474,6 +9544,14 @@ public class ActivityManagerService extends IActivityManager.Stub
System.gc();
pw.println(BinderInternal.nGetBinderProxyCount(Integer.parseInt(uid)));
}
+ } else if ("allowed-associations".equals(cmd)) {
+ if (opti < args.length) {
+ dumpPackage = args[opti];
+ opti++;
+ }
+ synchronized (this) {
+ dumpAllowedAssociationsLocked(fd, pw, args, opti, true, dumpPackage);
+ }
} else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
if (opti < args.length) {
dumpPackage = args[opti];
@@ -10824,6 +10902,44 @@ public class ActivityManagerService extends IActivityManager.Stub
proto.end(handlerToken);
}
+ void dumpAllowedAssociationsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ int opti, boolean dumpAll, String dumpPackage) {
+ boolean needSep = false;
+ boolean printedAnything = false;
+
+ pw.println("ACTIVITY MANAGER ALLOWED ASSOCIATION STATE (dumpsys activity allowed-associations)");
+ boolean printed = false;
+ if (mAllowedAssociations != null) {
+ for (int i = 0; i < mAllowedAssociations.size(); i++) {
+ final String pkg = mAllowedAssociations.keyAt(i);
+ final ArraySet<String> asc = mAllowedAssociations.valueAt(i);
+ boolean printedHeader = false;
+ for (int j = 0; j < asc.size(); j++) {
+ if (dumpPackage == null || pkg.equals(dumpPackage)
+ || asc.valueAt(j).equals(dumpPackage)) {
+ if (!printed) {
+ pw.println(" Allowed associations (by restricted package):");
+ printed = true;
+ needSep = true;
+ printedAnything = true;
+ }
+ if (!printedHeader) {
+ pw.print(" * ");
+ pw.print(pkg);
+ pw.println(":");
+ printedHeader = true;
+ }
+ pw.print(" Allow: ");
+ pw.println(asc.valueAt(j));
+ }
+ }
+ }
+ }
+ if (!printed) {
+ pw.println(" (No association restrictions)");
+ }
+ }
+
void dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, String dumpPackage) {
boolean needSep = false;
@@ -19441,16 +19557,13 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public boolean isAppStorageSandboxed(int pid, int uid) {
- if (!StorageManager.hasIsolatedStorage()) {
- return false;
- }
+ public int getStorageMountMode(int pid, int uid) {
if (uid == SHELL_UID || uid == ROOT_UID) {
- return false;
+ return Zygote.MOUNT_EXTERNAL_FULL;
}
synchronized (mPidsSelfLocked) {
final ProcessRecord pr = mPidsSelfLocked.get(pid);
- return pr == null || pr.mountMode != Zygote.MOUNT_EXTERNAL_FULL;
+ return pr == null ? Zygote.MOUNT_EXTERNAL_NONE : pr.mountMode;
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 67a4d14a6edb..98a82acd79a6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2852,6 +2852,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" prov[iders] [COMP_SPEC ...]: content provider state");
pw.println(" provider [COMP_SPEC]: provider client-side state");
pw.println(" s[ervices] [COMP_SPEC ...]: service state");
+ pw.println(" allowed-associations: current package association restrictions");
pw.println(" as[sociations]: tracked app associations");
pw.println(" lmk: stats on low memory killer");
pw.println(" lru: raw LRU process list");
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 3a0899de75c3..c290fbe09864 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -527,6 +527,24 @@ public final class BroadcastQueue {
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered, int index) {
boolean skip = false;
+ if (!mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid,
+ filter.packageName, filter.owningUid)) {
+ Slog.w(TAG, "Association not allowed: broadcasting "
+ + r.intent.toString()
+ + " from " + r.callerPackage + " (pid=" + r.callingPid
+ + ", uid=" + r.callingUid + ") to " + filter.packageName + " through "
+ + filter);
+ skip = true;
+ }
+ if (!skip && !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
+ r.callingPid, r.resolvedType, filter.receiverList.uid)) {
+ Slog.w(TAG, "Firewall blocked: broadcasting "
+ + r.intent.toString()
+ + " from " + r.callerPackage + " (pid=" + r.callingPid
+ + ", uid=" + r.callingUid + ") to " + filter.packageName + " through "
+ + filter);
+ skip = true;
+ }
if (filter.requiredPermission != null) {
int perm = mService.checkComponentPermission(filter.requiredPermission,
r.callingPid, r.callingUid, -1, true);
@@ -619,11 +637,6 @@ public final class BroadcastQueue {
skip = true;
}
- if (!mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
- r.callingPid, r.resolvedType, filter.receiverList.uid)) {
- skip = true;
- }
-
if (!skip && (filter.receiverList.app == null || filter.receiverList.app.killed
|| filter.receiverList.app.isCrashing())) {
Slog.w(TAG, "Skipping deliver [" + mQueueName + "] " + r
@@ -1082,6 +1095,24 @@ public final class BroadcastQueue {
> brOptions.getMaxManifestReceiverApiLevel())) {
skip = true;
}
+ if (!skip && !mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid,
+ component.getPackageName(), info.activityInfo.applicationInfo.uid)) {
+ Slog.w(TAG, "Association not allowed: broadcasting "
+ + r.intent.toString()
+ + " from " + r.callerPackage + " (pid=" + r.callingPid
+ + ", uid=" + r.callingUid + ") to " + component.flattenToShortString());
+ skip = true;
+ }
+ if (!skip) {
+ skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
+ r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid);
+ if (skip) {
+ Slog.w(TAG, "Firewall blocked: broadcasting "
+ + r.intent.toString()
+ + " from " + r.callerPackage + " (pid=" + r.callingPid
+ + ", uid=" + r.callingUid + ") to " + component.flattenToShortString());
+ }
+ }
int perm = mService.checkComponentPermission(info.activityInfo.permission,
r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
info.activityInfo.exported);
@@ -1170,10 +1201,6 @@ public final class BroadcastQueue {
+ " (uid " + r.callingUid + ")");
skip = true;
}
- if (!skip) {
- skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
- r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid);
- }
boolean isSingleton = false;
try {
isSingleton = mService.isSingleton(info.activityInfo.processName,
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 78e18e91ae73..1325f049e737 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -861,6 +861,11 @@ public class JobSchedulerService extends com.android.server.SystemService
Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
}
cancelJobsForPackageAndUid(pkgName, uidRemoved, "app uninstalled");
+ synchronized (mLock) {
+ for (int c = 0; c < mControllers.size(); ++c) {
+ mControllers.get(c).onAppRemovedLocked(pkgName, pkgUid);
+ }
+ }
}
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
@@ -868,6 +873,11 @@ public class JobSchedulerService extends com.android.server.SystemService
Slog.d(TAG, "Removing jobs for user: " + userId);
}
cancelJobsForUser(userId);
+ synchronized (mLock) {
+ for (int c = 0; c < mControllers.size(); ++c) {
+ mControllers.get(c).onUserRemovedLocked(userId);
+ }
+ }
} else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
// Has this package scheduled any jobs, such that we will take action
// if it were to be force-stopped?
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index 8f104e4a1525..aca02bf1fb7c 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -296,6 +296,12 @@ public final class ConnectivityController extends StateController implements
mRequestedWhitelistJobs.remove(uid);
}
+ @GuardedBy("mLock")
+ @Override
+ public void onAppRemovedLocked(String pkgName, int uid) {
+ mTrackedJobs.delete(uid);
+ }
+
/**
* Test to see if running the given job on the given network is insane.
* <p>
diff --git a/services/core/java/com/android/server/job/controllers/QuotaController.java b/services/core/java/com/android/server/job/controllers/QuotaController.java
index 660c2383ea2f..58ee21795d99 100644
--- a/services/core/java/com/android/server/job/controllers/QuotaController.java
+++ b/services/core/java/com/android/server/job/controllers/QuotaController.java
@@ -98,6 +98,19 @@ public final class QuotaController extends StateController {
data.put(packageName, obj);
}
+ /** Removes all the data for the user, if there was any. */
+ public void delete(int userId) {
+ mData.delete(userId);
+ }
+
+ /** Removes the data for the user and package, if there was any. */
+ public void delete(int userId, @NonNull String packageName) {
+ ArrayMap<String, T> data = mData.get(userId);
+ if (data != null) {
+ data.remove(packageName);
+ }
+ }
+
@Nullable
public T get(int userId, @NonNull String packageName) {
ArrayMap<String, T> data = mData.get(userId);
@@ -371,6 +384,38 @@ public final class QuotaController extends StateController {
}
}
+ @Override
+ public void onAppRemovedLocked(String packageName, int uid) {
+ if (packageName == null) {
+ Slog.wtf(TAG, "Told app removed but given null package name.");
+ return;
+ }
+ final int userId = UserHandle.getUserId(uid);
+ mTrackedJobs.delete(userId, packageName);
+ Timer timer = mPkgTimers.get(userId, packageName);
+ if (timer != null) {
+ if (timer.isActive()) {
+ Slog.wtf(TAG, "onAppRemovedLocked called before Timer turned off.");
+ timer.dropEverything();
+ }
+ mPkgTimers.delete(userId, packageName);
+ }
+ mTimingSessions.delete(userId, packageName);
+ QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, packageName);
+ if (alarmListener != null) {
+ mAlarmManager.cancel(alarmListener);
+ mInQuotaAlarmListeners.delete(userId, packageName);
+ }
+ }
+
+ @Override
+ public void onUserRemovedLocked(int userId) {
+ mTrackedJobs.delete(userId);
+ mPkgTimers.delete(userId);
+ mTimingSessions.delete(userId);
+ mInQuotaAlarmListeners.delete(userId);
+ }
+
/**
* Returns an appropriate standby bucket for the job, taking into account any standby
* exemptions.
@@ -882,6 +927,15 @@ public final class QuotaController extends StateController {
}
}
+ /**
+ * Stops tracking all jobs and cancels any pending alarms. This should only be called if
+ * the Timer is not going to be used anymore.
+ */
+ void dropEverything() {
+ mRunningBgJobs.clear();
+ cancelCutoff();
+ }
+
private void emitSessionLocked(long nowElapsed) {
if (mBgJobCount <= 0) {
// Nothing to emit.
diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java
index 61dc4799f221..97c3bac4ddbb 100644
--- a/services/core/java/com/android/server/job/controllers/StateController.java
+++ b/services/core/java/com/android/server/job/controllers/StateController.java
@@ -83,21 +83,12 @@ public abstract class StateController {
public void onConstantsUpdatedLocked() {
}
- protected boolean wouldBeReadyWithConstraintLocked(JobStatus jobStatus, int constraint) {
- // This is very cheap to check (just a few conditions on data in JobStatus).
- final boolean jobWouldBeReady = jobStatus.wouldBeReadyWithConstraint(constraint);
- if (DEBUG) {
- Slog.v(TAG, "wouldBeReadyWithConstraintLocked: " + jobStatus.toShortString()
- + " readyWithConstraint=" + jobWouldBeReady);
- }
- if (!jobWouldBeReady) {
- // If the job wouldn't be ready, nothing to do here.
- return false;
- }
+ /** Called when a package is uninstalled from the device (not for an update). */
+ public void onAppRemovedLocked(String packageName, int uid) {
+ }
- // This is potentially more expensive since JSS may have to query component
- // presence.
- return mService.areComponentsInPlaceLocked(jobStatus);
+ /** Called when a user is removed from the device. */
+ public void onUserRemovedLocked(int userId) {
}
/**
@@ -114,6 +105,23 @@ public abstract class StateController {
public void reevaluateStateLocked(int uid) {
}
+ protected boolean wouldBeReadyWithConstraintLocked(JobStatus jobStatus, int constraint) {
+ // This is very cheap to check (just a few conditions on data in JobStatus).
+ final boolean jobWouldBeReady = jobStatus.wouldBeReadyWithConstraint(constraint);
+ if (DEBUG) {
+ Slog.v(TAG, "wouldBeReadyWithConstraintLocked: " + jobStatus.toShortString()
+ + " readyWithConstraint=" + jobWouldBeReady);
+ }
+ if (!jobWouldBeReady) {
+ // If the job wouldn't be ready, nothing to do here.
+ return false;
+ }
+
+ // This is potentially more expensive since JSS may have to query component
+ // presence.
+ return mService.areComponentsInPlaceLocked(jobStatus);
+ }
+
public abstract void dumpControllerStateLocked(IndentingPrintWriter pw,
Predicate<JobStatus> predicate);
public abstract void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7d0f98c6930e..6cfb846e3ade 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -24,7 +24,6 @@ import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
-import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
import static android.content.Intent.ACTION_MAIN;
import static android.content.Intent.CATEGORY_DEFAULT;
import static android.content.Intent.CATEGORY_HOME;
@@ -20181,11 +20180,6 @@ public class PackageManagerService extends IPackageManager.Stub
if (Process.isIsolated(uid)) {
return Zygote.MOUNT_EXTERNAL_NONE;
}
- if (StorageManager.hasIsolatedStorage()) {
- return checkUidPermission(WRITE_MEDIA_STORAGE, uid) == PERMISSION_GRANTED
- ? Zygote.MOUNT_EXTERNAL_FULL
- : Zygote.MOUNT_EXTERNAL_WRITE;
- }
if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
return Zygote.MOUNT_EXTERNAL_DEFAULT;
}
diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
index 649f1a56f011..4d4a7b41643c 100644
--- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp
+++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
@@ -34,7 +34,6 @@
#include "netdbpf/BpfNetworkStats.h"
using android::bpf::Stats;
-using android::bpf::hasBpfSupport;
using android::bpf::bpfGetUidStats;
using android::bpf::bpfGetIfaceStats;
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index a7209a076461..b9cc372c5138 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -111,7 +111,7 @@ public class ApfFilter {
* the last writable 32bit word.
*/
@VisibleForTesting
- private static enum Counter {
+ public static enum Counter {
RESERVED_OOB, // Points to offset 0 from the end of the buffer (out-of-bounds)
TOTAL_PACKETS,
PASSED_ARP,
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 71aec235640b..effb5a72bd66 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -270,6 +270,60 @@ public class QuotaControllerTest {
}
@Test
+ public void testOnAppRemovedLocked() {
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ mQuotaController.saveTimingSession(0, "com.android.test.remove",
+ createTimingSession(now - (6 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5));
+ mQuotaController.saveTimingSession(0, "com.android.test.remove",
+ createTimingSession(
+ now - (2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 6 * MINUTE_IN_MILLIS, 5));
+ mQuotaController.saveTimingSession(0, "com.android.test.remove",
+ createTimingSession(now - (HOUR_IN_MILLIS), MINUTE_IN_MILLIS, 1));
+ // Test that another app isn't affected.
+ TimingSession one = createTimingSession(
+ now - 10 * MINUTE_IN_MILLIS, 9 * MINUTE_IN_MILLIS, 3);
+ TimingSession two = createTimingSession(
+ now - (70 * MINUTE_IN_MILLIS), 9 * MINUTE_IN_MILLIS, 1);
+ List<TimingSession> expected = new ArrayList<>();
+ // Added in correct (chronological) order.
+ expected.add(two);
+ expected.add(one);
+ mQuotaController.saveTimingSession(0, "com.android.test.stay", two);
+ mQuotaController.saveTimingSession(0, "com.android.test.stay", one);
+
+ mQuotaController.onAppRemovedLocked("com.android.test.remove", 10001);
+ assertNull(mQuotaController.getTimingSessions(0, "com.android.test.remove"));
+ assertEquals(expected, mQuotaController.getTimingSessions(0, "com.android.test.stay"));
+ }
+
+ @Test
+ public void testOnUserRemovedLocked() {
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - (6 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5));
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(
+ now - (2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 6 * MINUTE_IN_MILLIS, 5));
+ mQuotaController.saveTimingSession(0, "com.android.test",
+ createTimingSession(now - (HOUR_IN_MILLIS), MINUTE_IN_MILLIS, 1));
+ // Test that another user isn't affected.
+ TimingSession one = createTimingSession(
+ now - 10 * MINUTE_IN_MILLIS, 9 * MINUTE_IN_MILLIS, 3);
+ TimingSession two = createTimingSession(
+ now - (70 * MINUTE_IN_MILLIS), 9 * MINUTE_IN_MILLIS, 1);
+ List<TimingSession> expected = new ArrayList<>();
+ // Added in correct (chronological) order.
+ expected.add(two);
+ expected.add(one);
+ mQuotaController.saveTimingSession(10, "com.android.test", two);
+ mQuotaController.saveTimingSession(10, "com.android.test", one);
+
+ mQuotaController.onUserRemovedLocked(0);
+ assertNull(mQuotaController.getTimingSessions(0, "com.android.test"));
+ assertEquals(expected, mQuotaController.getTimingSessions(10, "com.android.test"));
+ }
+
+ @Test
public void testGetTrailingExecutionTimeLocked_NoTimer() {
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
// Added in chronological order.
diff --git a/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
index e6b328a128b7..ec5d93edc126 100644
--- a/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
@@ -29,8 +29,7 @@ import android.content.pm.PackageManagerInternal;
import android.os.UserManagerInternal;
import android.os.storage.StorageManagerInternal;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.os.Zygote;
import org.junit.Before;
import org.junit.Test;
@@ -38,6 +37,9 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class StorageManagerServiceTest {
@@ -97,15 +99,15 @@ public class StorageManagerServiceTest {
when(mPm.getPackagesForUid(eq(UID_GREY))).thenReturn(new String[] { PKG_GREY });
when(mPm.getPackagesForUid(eq(UID_COLORS))).thenReturn(new String[] { PKG_RED, PKG_BLUE });
- setIsAppStorageSandboxed(PID_BLUE, UID_COLORS, true);
- setIsAppStorageSandboxed(PID_GREY, UID_GREY, true);
- setIsAppStorageSandboxed(PID_RED, UID_COLORS, true);
+ setStorageMountMode(PID_BLUE, UID_COLORS, Zygote.MOUNT_EXTERNAL_WRITE);
+ setStorageMountMode(PID_GREY, UID_GREY, Zygote.MOUNT_EXTERNAL_WRITE);
+ setStorageMountMode(PID_RED, UID_COLORS, Zygote.MOUNT_EXTERNAL_WRITE);
mService = new StorageManagerService(mContext);
}
- private void setIsAppStorageSandboxed(int pid, int uid, boolean sandboxed) {
- when(mAmi.isAppStorageSandboxed(pid, uid)).thenReturn(sandboxed);
+ private void setStorageMountMode(int pid, int uid, int mountMode) {
+ when(mAmi.getStorageMountMode(pid, uid)).thenReturn(mountMode);
}
@Test
@@ -210,7 +212,7 @@ public class StorageManagerServiceTest {
@Test
public void testPackageNotSandboxed() throws Exception {
- setIsAppStorageSandboxed(PID_RED, UID_COLORS, false);
+ setStorageMountMode(PID_RED, UID_COLORS, Zygote.MOUNT_EXTERNAL_FULL);
// Both app and system have the same view
assertTranslation(
@@ -224,6 +226,29 @@ public class StorageManagerServiceTest {
PID_RED, UID_COLORS);
}
+ @Test
+ public void testInstallerPackage() throws Exception {
+ setStorageMountMode(PID_GREY, UID_GREY, Zygote.MOUNT_EXTERNAL_INSTALLER);
+
+ assertTranslation(
+ "/storage/emulated/0/Android/obb/com.grey/foo.jpg",
+ "/storage/emulated/0/Android/obb/com.grey/foo.jpg",
+ PID_GREY, UID_GREY);
+ assertTranslation(
+ "/storage/emulated/0/Android/obb/com.blue/bar.jpg",
+ "/storage/emulated/0/Android/obb/com.blue/bar.jpg",
+ PID_GREY, UID_GREY);
+
+ assertTranslation(
+ "/storage/emulated/0/Android/data/com.grey/foo.jpg",
+ "/storage/emulated/0/Android/data/com.grey/foo.jpg",
+ PID_GREY, UID_GREY);
+ assertTranslation(
+ "/storage/emulated/0/Android/sandbox/com.grey/Android/data/com.blue/bar.jpg",
+ "/storage/emulated/0/Android/data/com.blue/bar.jpg",
+ PID_GREY, UID_GREY);
+ }
+
private void assertTranslation(String system, String sandbox,
int pid, int uid) throws Exception {
assertEquals(system,
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 49030f59064a..fb371c176352 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -476,7 +476,7 @@ public class TelecomManager {
/**
* A boolean meta-data value indicating whether an {@link InCallService} implements an
* in-call user interface to be used while the device is in car-mode (see
- * {@link android.content.res.Configuration.UI_MODE_TYPE_CAR}).
+ * {@link android.content.res.Configuration#UI_MODE_TYPE_CAR}).
*/
public static final String METADATA_IN_CALL_SERVICE_CAR_MODE_UI =
"android.telecom.IN_CALL_SERVICE_CAR_MODE_UI";
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index cfe134fd0ee2..388b5fb43096 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1398,9 +1398,9 @@ public class CarrierConfigManager {
* Example: "default"
*
* {@code ERROR_CODE_1} is an integer defined in
- * {@link com.android.internal.telephony.dataconnection.DcFailCause DcFailure}
+ * {@link DataFailCause DcFailure}
* Example:
- * {@link com.android.internal.telephony.dataconnection.DcFailCause#MISSING_UNKNOWN_APN}
+ * {@link DataFailCause#MISSING_UNKNOWN_APN}
*
* {@code CARRIER_ACTION_IDX_1} is an integer defined in
* {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils}
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
new file mode 100644
index 000000000000..c6f7d0e458db
--- /dev/null
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2006 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.telephony;
+
+import android.content.Context;
+import android.os.PersistableBundle;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+
+/**
+ * Returned as the reason for a connection failure as defined
+ * by RIL_DataCallFailCause in ril.h and some local errors.
+ * @hide
+ */
+public enum DataFailCause {
+ NONE(0),
+
+ // This series of errors as specified by the standards
+ // specified in ril.h
+ OPERATOR_BARRED(0x08), /* no retry */
+ NAS_SIGNALLING(0x0E),
+ LLC_SNDCP(0x19),
+ INSUFFICIENT_RESOURCES(0x1A),
+ MISSING_UNKNOWN_APN(0x1B), /* no retry */
+ UNKNOWN_PDP_ADDRESS_TYPE(0x1C), /* no retry */
+ USER_AUTHENTICATION(0x1D), /* no retry */
+ ACTIVATION_REJECT_GGSN(0x1E), /* no retry */
+ ACTIVATION_REJECT_UNSPECIFIED(0x1F),
+ SERVICE_OPTION_NOT_SUPPORTED(0x20), /* no retry */
+ SERVICE_OPTION_NOT_SUBSCRIBED(0x21), /* no retry */
+ SERVICE_OPTION_OUT_OF_ORDER(0x22),
+ NSAPI_IN_USE(0x23), /* no retry */
+ REGULAR_DEACTIVATION(0x24), /* possibly restart radio, based on config */
+ QOS_NOT_ACCEPTED(0x25),
+ NETWORK_FAILURE(0x26),
+ UMTS_REACTIVATION_REQ(0x27),
+ FEATURE_NOT_SUPP(0x28),
+ TFT_SEMANTIC_ERROR(0x29),
+ TFT_SYTAX_ERROR(0x2A),
+ UNKNOWN_PDP_CONTEXT(0x2B),
+ FILTER_SEMANTIC_ERROR(0x2C),
+ FILTER_SYTAX_ERROR(0x2D),
+ PDP_WITHOUT_ACTIVE_TFT(0x2E),
+ ONLY_IPV4_ALLOWED(0x32), /* no retry */
+ ONLY_IPV6_ALLOWED(0x33), /* no retry */
+ ONLY_SINGLE_BEARER_ALLOWED(0x34),
+ ESM_INFO_NOT_RECEIVED(0x35),
+ PDN_CONN_DOES_NOT_EXIST(0x36),
+ MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED(0x37),
+ MAX_ACTIVE_PDP_CONTEXT_REACHED(0x41),
+ UNSUPPORTED_APN_IN_CURRENT_PLMN(0x42),
+ INVALID_TRANSACTION_ID(0x51),
+ MESSAGE_INCORRECT_SEMANTIC(0x5F),
+ INVALID_MANDATORY_INFO(0x60),
+ MESSAGE_TYPE_UNSUPPORTED(0x61),
+ MSG_TYPE_NONCOMPATIBLE_STATE(0x62),
+ UNKNOWN_INFO_ELEMENT(0x63),
+ CONDITIONAL_IE_ERROR(0x64),
+ MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE(0x65),
+ PROTOCOL_ERRORS(0x6F), /* no retry */
+ APN_TYPE_CONFLICT(0x70),
+ INVALID_PCSCF_ADDR(0x71),
+ INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN(0x72),
+ EMM_ACCESS_BARRED(0x73),
+ EMERGENCY_IFACE_ONLY(0x74),
+ IFACE_MISMATCH(0x75),
+ COMPANION_IFACE_IN_USE(0x76),
+ IP_ADDRESS_MISMATCH(0x77),
+ IFACE_AND_POL_FAMILY_MISMATCH(0x78),
+ EMM_ACCESS_BARRED_INFINITE_RETRY(0x79),
+ AUTH_FAILURE_ON_EMERGENCY_CALL(0x7A),
+
+ // OEM sepecific error codes. To be used by OEMs when they don't
+ // want to reveal error code which would be replaced by ERROR_UNSPECIFIED
+ OEM_DCFAILCAUSE_1(0x1001),
+ OEM_DCFAILCAUSE_2(0x1002),
+ OEM_DCFAILCAUSE_3(0x1003),
+ OEM_DCFAILCAUSE_4(0x1004),
+ OEM_DCFAILCAUSE_5(0x1005),
+ OEM_DCFAILCAUSE_6(0x1006),
+ OEM_DCFAILCAUSE_7(0x1007),
+ OEM_DCFAILCAUSE_8(0x1008),
+ OEM_DCFAILCAUSE_9(0x1009),
+ OEM_DCFAILCAUSE_10(0x100A),
+ OEM_DCFAILCAUSE_11(0x100B),
+ OEM_DCFAILCAUSE_12(0x100C),
+ OEM_DCFAILCAUSE_13(0x100D),
+ OEM_DCFAILCAUSE_14(0x100E),
+ OEM_DCFAILCAUSE_15(0x100F),
+
+ // Local errors generated by Vendor RIL
+ // specified in ril.h
+ REGISTRATION_FAIL(-1),
+ GPRS_REGISTRATION_FAIL(-2),
+ SIGNAL_LOST(-3), /* no retry */
+ PREF_RADIO_TECH_CHANGED(-4),
+ RADIO_POWER_OFF(-5), /* no retry */
+ TETHERED_CALL_ACTIVE(-6), /* no retry */
+ ERROR_UNSPECIFIED(0xFFFF),
+
+ // Errors generated by the Framework
+ // specified here
+ UNKNOWN(0x10000),
+ RADIO_NOT_AVAILABLE(0x10001), /* no retry */
+ UNACCEPTABLE_NETWORK_PARAMETER(0x10002), /* no retry */
+ CONNECTION_TO_DATACONNECTIONAC_BROKEN(0x10003),
+ LOST_CONNECTION(0x10004),
+ RESET_BY_FRAMEWORK(0x10005);
+
+ private final int mErrorCode;
+ private static final HashMap<Integer, DataFailCause> sErrorCodeToFailCauseMap;
+ static {
+ sErrorCodeToFailCauseMap = new HashMap<Integer, DataFailCause>();
+ for (DataFailCause fc : values()) {
+ sErrorCodeToFailCauseMap.put(fc.getErrorCode(), fc);
+ }
+ }
+
+ /**
+ * Map of subId -> set of data call setup permanent failure for the carrier.
+ */
+ private static final HashMap<Integer, HashSet<DataFailCause>> sPermanentFailureCache =
+ new HashMap<>();
+
+ DataFailCause(int errorCode) {
+ mErrorCode = errorCode;
+ }
+
+ public int getErrorCode() {
+ return mErrorCode;
+ }
+
+ /**
+ * Returns whether or not the fail cause is a failure that requires a modem restart
+ *
+ * @param context device context
+ * @param subId subscription index
+ * @return true if the fail cause code needs platform to trigger a modem restart.
+ */
+ public boolean isRadioRestartFailure(Context context, int subId) {
+ CarrierConfigManager configManager = (CarrierConfigManager)
+ context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ if (configManager != null) {
+ PersistableBundle b = configManager.getConfigForSubId(subId);
+
+ if (b != null) {
+ if (this == REGULAR_DEACTIVATION
+ && b.getBoolean(CarrierConfigManager
+ .KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL)) {
+ // This is for backward compatibility support. We need to continue support this
+ // old configuration until it gets removed in the future.
+ return true;
+ }
+ // Check the current configurations.
+ int[] causeCodes = b.getIntArray(CarrierConfigManager
+ .KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY);
+ if (causeCodes != null) {
+ return Arrays.stream(causeCodes).anyMatch(i -> i == getErrorCode());
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public boolean isPermanentFailure(Context context, int subId) {
+
+ synchronized (sPermanentFailureCache) {
+
+ HashSet<DataFailCause> permanentFailureSet = sPermanentFailureCache.get(subId);
+
+ // In case of cache miss, we need to look up the settings from carrier config.
+ if (permanentFailureSet == null) {
+ // Retrieve the permanent failure from carrier config
+ CarrierConfigManager configManager = (CarrierConfigManager)
+ context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ if (configManager != null) {
+ PersistableBundle b = configManager.getConfigForSubId(subId);
+ if (b != null) {
+ String[] permanentFailureStrings = b.getStringArray(CarrierConfigManager.
+ KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS);
+
+ if (permanentFailureStrings != null) {
+ permanentFailureSet = new HashSet<>();
+ for (String failure : permanentFailureStrings) {
+ permanentFailureSet.add(DataFailCause.valueOf(failure));
+ }
+ }
+ }
+ }
+
+ // If we are not able to find the configuration from carrier config, use the default
+ // ones.
+ if (permanentFailureSet == null) {
+ permanentFailureSet = new HashSet<DataFailCause>() {
+ {
+ add(OPERATOR_BARRED);
+ add(MISSING_UNKNOWN_APN);
+ add(UNKNOWN_PDP_ADDRESS_TYPE);
+ add(USER_AUTHENTICATION);
+ add(ACTIVATION_REJECT_GGSN);
+ add(SERVICE_OPTION_NOT_SUPPORTED);
+ add(SERVICE_OPTION_NOT_SUBSCRIBED);
+ add(NSAPI_IN_USE);
+ add(ONLY_IPV4_ALLOWED);
+ add(ONLY_IPV6_ALLOWED);
+ add(PROTOCOL_ERRORS);
+ add(RADIO_POWER_OFF);
+ add(TETHERED_CALL_ACTIVE);
+ add(RADIO_NOT_AVAILABLE);
+ add(UNACCEPTABLE_NETWORK_PARAMETER);
+ add(SIGNAL_LOST);
+ }
+ };
+ }
+
+ sPermanentFailureCache.put(subId, permanentFailureSet);
+ }
+
+ return permanentFailureSet.contains(this);
+ }
+ }
+
+ public boolean isEventLoggable() {
+ return (this == OPERATOR_BARRED) || (this == INSUFFICIENT_RESOURCES) ||
+ (this == UNKNOWN_PDP_ADDRESS_TYPE) || (this == USER_AUTHENTICATION) ||
+ (this == ACTIVATION_REJECT_GGSN) || (this == ACTIVATION_REJECT_UNSPECIFIED) ||
+ (this == SERVICE_OPTION_NOT_SUBSCRIBED) ||
+ (this == SERVICE_OPTION_NOT_SUPPORTED) ||
+ (this == SERVICE_OPTION_OUT_OF_ORDER) || (this == NSAPI_IN_USE) ||
+ (this == ONLY_IPV4_ALLOWED) || (this == ONLY_IPV6_ALLOWED) ||
+ (this == PROTOCOL_ERRORS) || (this == SIGNAL_LOST) ||
+ (this == RADIO_POWER_OFF) || (this == TETHERED_CALL_ACTIVE) ||
+ (this == UNACCEPTABLE_NETWORK_PARAMETER);
+ }
+
+ public static DataFailCause fromInt(int errorCode) {
+ DataFailCause fc = sErrorCodeToFailCauseMap.get(errorCode);
+ if (fc == null) {
+ fc = UNKNOWN;
+ }
+ return fc;
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RcsManager.java b/telephony/java/android/telephony/ims/RcsManager.java
new file mode 100644
index 000000000000..d50b516b8754
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsManager.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.annotation.SystemService;
+import android.content.Context;
+
+/**
+ * The manager class for RCS related utilities.
+ * @hide
+ */
+@SystemService(Context.TELEPHONY_RCS_SERVICE)
+public class RcsManager {
+
+ private static final RcsMessageStore sRcsMessageStoreInstance = new RcsMessageStore();
+
+ /**
+ * Returns an instance of RcsMessageStore.
+ */
+ public RcsMessageStore getRcsMessageStore() {
+ return sRcsMessageStoreInstance;
+ }
+}
diff --git a/telephony/java/android/telephony/rcs/RcsManager.java b/telephony/java/android/telephony/ims/RcsMessageStore.java
index 0ef4e1552085..c89c0bebb1a1 100644
--- a/telephony/java/android/telephony/rcs/RcsManager.java
+++ b/telephony/java/android/telephony/ims/RcsMessageStore.java
@@ -14,24 +14,20 @@
* limitations under the License.
*/
-package android.telephony.rcs;
+package android.telephony.ims;
-import android.annotation.SystemService;
-import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.telephony.Rlog;
-
-import com.android.internal.telephony.rcs.IRcs;
+import android.telephony.ims.aidl.IRcs;
/**
- * RcsManager is the application interface to RcsProvider and provides access methods to
+ * RcsMessageStore is the application interface to RcsProvider and provides access methods to
* RCS related database tables.
* @hide - TODO make this public
*/
-@SystemService(Context.TELEPHONY_RCS_SERVICE)
-public class RcsManager {
- private static final String TAG = "RcsManager";
+public class RcsMessageStore {
+ private static final String TAG = "RcsMessageStore";
private static final boolean VDBG = false;
/**
diff --git a/telephony/java/android/telephony/ims/RcsThread.aidl b/telephony/java/android/telephony/ims/RcsThread.aidl
new file mode 100644
index 000000000000..79d473266272
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThread.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+parcelable RcsThread; \ No newline at end of file
diff --git a/telephony/java/android/telephony/rcs/RcsThread.java b/telephony/java/android/telephony/ims/RcsThread.java
index 83eb973ec12b..b7f440d94583 100644
--- a/telephony/java/android/telephony/rcs/RcsThread.java
+++ b/telephony/java/android/telephony/ims/RcsThread.java
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-package android.telephony.rcs;
+package android.telephony.ims;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
-
-import com.android.internal.telephony.rcs.IRcs;
+import android.telephony.ims.aidl.IRcs;
/**
* RcsThread represents a single RCS conversation thread. It holds messages that were sent and
diff --git a/telephony/java/com/android/internal/telephony/rcs/IRcs.aidl b/telephony/java/android/telephony/ims/aidl/IRcs.aidl
index 4c289acd15ef..b2e2fadca138 100644
--- a/telephony/java/com/android/internal/telephony/rcs/IRcs.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IRcs.aidl
@@ -14,10 +14,14 @@
* limitations under the License.
*/
-package com.android.internal.telephony.rcs;
+package android.telephony.ims.aidl;
+/**
+ * RPC definition between RCS storage APIs and phone process.
+ * {@hide}
+ */
interface IRcs {
- // RcsManager APIs
+ // RcsMessageStore APIs
void deleteThread(int threadId);
// RcsThread APIs
diff --git a/telephony/java/android/telephony/rcs/RcsThread.aidl b/telephony/java/android/telephony/rcs/RcsThread.aidl
deleted file mode 100644
index e2e0da5da347..000000000000
--- a/telephony/java/android/telephony/rcs/RcsThread.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
-**
-** Copyright 2018, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.telephony;
-
-parcelable RcsThread; \ No newline at end of file
diff --git a/tests/RcsTests/src/com/android/tests/rcs/RcsManagerTest.java b/tests/RcsTests/src/com/android/tests/rcs/RcsMessageStoreTest.java
index 7f5f03e0d5a4..290e04ce8abb 100644
--- a/tests/RcsTests/src/com/android/tests/rcs/RcsManagerTest.java
+++ b/tests/RcsTests/src/com/android/tests/rcs/RcsMessageStoreTest.java
@@ -16,17 +16,17 @@
package com.android.tests.rcs;
import android.support.test.runner.AndroidJUnit4;
-import android.telephony.rcs.RcsManager;
+import android.telephony.ims.RcsMessageStore;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
-public class RcsManagerTest {
+public class RcsMessageStoreTest {
//TODO(sahinc): Add meaningful tests once we have more of the implementation in place
@Test
public void testDeleteThreadDoesntCrash() {
- RcsManager mRcsManager = new RcsManager();
- mRcsManager.deleteThread(0);
+ RcsMessageStore mRcsMessageStore = new RcsMessageStore();
+ mRcsMessageStore.deleteThread(0);
}
}
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index 983802035bfb..436dd859beca 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -46,6 +46,7 @@ import android.support.test.runner.AndroidJUnit4;
import android.system.ErrnoException;
import android.system.Os;
import android.text.format.DateUtils;
+import android.util.Log;
import com.android.frameworks.tests.net.R;
import com.android.internal.util.HexDump;
import java.io.File;
@@ -89,6 +90,7 @@ public class ApfTest {
System.loadLibrary("frameworksnettestsjni");
}
+ private static final String TAG = "ApfTest";
// Expected return codes from APF interpreter.
private static final int PASS = 1;
private static final int DROP = 0;
@@ -869,6 +871,37 @@ public class ApfTest {
}
}
+ /**
+ * Generate APF program, run pcap file though APF filter, then check all the packets in the file
+ * should be dropped.
+ */
+ @Test
+ public void testApfFilterPcapFile() throws Exception {
+ final byte[] MOCK_PCAP_IPV4_ADDR = {(byte) 172, 16, 7, (byte) 151};
+ String pcapFilename = stageFile(R.raw.apfPcap);
+ MockIpClientCallback ipClientCallback = new MockIpClientCallback();
+ LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_PCAP_IPV4_ADDR), 16);
+ LinkProperties lp = new LinkProperties();
+ lp.addLinkAddress(link);
+
+ ApfConfiguration config = getDefaultConfig();
+ ApfCapabilities MOCK_APF_PCAP_CAPABILITIES = new ApfCapabilities(4, 1700, ARPHRD_ETHER);
+ config.apfCapabilities = MOCK_APF_PCAP_CAPABILITIES;
+ config.multicastFilter = DROP_MULTICAST;
+ config.ieee802_3Filter = DROP_802_3_FRAMES;
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog);
+ apfFilter.setLinkProperties(lp);
+ byte[] program = ipClientCallback.getApfProgram();
+ byte[] data = new byte[ApfFilter.Counter.totalSize()];
+ final boolean result;
+
+ result = dropsAllPackets(program, data, pcapFilename);
+ Log.i(TAG, "testApfFilterPcapFile(): Data counters: " + HexDump.toHexString(data, false));
+
+ assertTrue("Failed to drop all packets by filter. \nAPF counters:" +
+ HexDump.toHexString(data, false), result);
+ }
+
private class MockIpClientCallback extends IpClient.Callback {
private final ConditionVariable mGotApfProgram = new ConditionVariable();
private byte[] mLastApfProgram;
@@ -1706,6 +1739,14 @@ public class ApfTest {
private native static boolean compareBpfApf(String filter, String pcap_filename,
byte[] apf_program);
+
+ /**
+ * Open packet capture file {@code pcapFilename} and run it through APF filter. Then
+ * checks whether all the packets are dropped and populates data[] {@code data} with
+ * the APF counters.
+ */
+ private native static boolean dropsAllPackets(byte[] program, byte[] data, String pcapFilename);
+
@Test
public void testBroadcastAddress() throws Exception {
assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 0));
diff --git a/tests/net/jni/apf_jni.cpp b/tests/net/jni/apf_jni.cpp
index 1ea9e274ab9e..4222adf9e06b 100644
--- a/tests/net/jni/apf_jni.cpp
+++ b/tests/net/jni/apf_jni.cpp
@@ -21,37 +21,40 @@
#include <stdlib.h>
#include <string>
#include <utils/Log.h>
+#include <vector>
#include "apf_interpreter.h"
+#include "nativehelper/scoped_primitive_array.h"
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
// JNI function acting as simply call-through to native APF interpreter.
static jint com_android_server_ApfTest_apfSimulate(
- JNIEnv* env, jclass, jbyteArray program, jbyteArray packet,
- jbyteArray data, jint filter_age) {
- uint8_t* program_raw = (uint8_t*)env->GetByteArrayElements(program, nullptr);
- uint8_t* packet_raw = (uint8_t*)env->GetByteArrayElements(packet, nullptr);
- uint8_t* data_raw = (uint8_t*)(data ? env->GetByteArrayElements(data, nullptr) : nullptr);
- uint32_t program_len = env->GetArrayLength(program);
- uint32_t packet_len = env->GetArrayLength(packet);
- uint32_t data_len = data ? env->GetArrayLength(data) : 0;
-
- // Merge program and data into a single buffer.
- uint8_t* program_and_data = (uint8_t*)malloc(program_len + data_len);
- memcpy(program_and_data, program_raw, program_len);
- memcpy(program_and_data + program_len, data_raw, data_len);
+ JNIEnv* env, jclass, jbyteArray jprogram, jbyteArray jpacket,
+ jbyteArray jdata, jint filter_age) {
+
+ ScopedByteArrayRO packet(env, jpacket);
+ uint32_t packet_len = (uint32_t)packet.size();
+ uint32_t program_len = env->GetArrayLength(jprogram);
+ uint32_t data_len = jdata ? env->GetArrayLength(jdata) : 0;
+ std::vector<uint8_t> buf(program_len + data_len, 0);
+
+ env->GetByteArrayRegion(jprogram, 0, program_len, reinterpret_cast<jbyte*>(buf.data()));
+ if (jdata) {
+ // Merge program and data into a single buffer.
+ env->GetByteArrayRegion(jdata, 0, data_len,
+ reinterpret_cast<jbyte*>(buf.data() + program_len));
+ }
jint result =
- accept_packet(program_and_data, program_len, program_len + data_len,
- packet_raw, packet_len, filter_age);
- if (data) {
- memcpy(data_raw, program_and_data + program_len, data_len);
- env->ReleaseByteArrayElements(data, (jbyte*)data_raw, 0 /* copy back */);
- }
- free(program_and_data);
- env->ReleaseByteArrayElements(packet, (jbyte*)packet_raw, JNI_ABORT);
- env->ReleaseByteArrayElements(program, (jbyte*)program_raw, JNI_ABORT);
+ accept_packet(buf.data(), program_len, program_len + data_len,
+ reinterpret_cast<const uint8_t*>(packet.get()), packet_len, filter_age);
+
+ if (jdata) {
+ env->SetByteArrayRegion(jdata, 0, data_len,
+ reinterpret_cast<jbyte*>(buf.data() + program_len));
+ }
+
return result;
}
@@ -118,8 +121,7 @@ static jboolean com_android_server_ApfTest_compareBpfApf(JNIEnv* env, jclass, js
jstring jpcap_filename, jbyteArray japf_program) {
ScopedUtfChars filter(env, jfilter);
ScopedUtfChars pcap_filename(env, jpcap_filename);
- uint8_t* apf_program = (uint8_t*)env->GetByteArrayElements(japf_program, NULL);
- uint32_t apf_program_len = env->GetArrayLength(japf_program);
+ ScopedByteArrayRO apf_program(env, japf_program);
// Open pcap file for BPF filtering
ScopedFILE bpf_fp(fopen(pcap_filename.c_str(), "rb"));
@@ -161,14 +163,15 @@ static jboolean com_android_server_ApfTest_compareBpfApf(JNIEnv* env, jclass, js
do {
apf_packet = pcap_next(apf_pcap.get(), &apf_header);
} while (apf_packet != NULL && !accept_packet(
- apf_program, apf_program_len, 0 /* data_len */,
+ reinterpret_cast<uint8_t*>(const_cast<int8_t*>(apf_program.get())),
+ apf_program.size(), 0 /* data_len */,
apf_packet, apf_header.len, 0 /* filter_age */));
// Make sure both filters matched the same packet.
if (apf_packet == NULL && bpf_packet == NULL)
- break;
+ break;
if (apf_packet == NULL || bpf_packet == NULL)
- return false;
+ return false;
if (apf_header.len != bpf_header.len ||
apf_header.ts.tv_sec != bpf_header.ts.tv_sec ||
apf_header.ts.tv_usec != bpf_header.ts.tv_usec ||
@@ -178,6 +181,48 @@ static jboolean com_android_server_ApfTest_compareBpfApf(JNIEnv* env, jclass, js
return true;
}
+static jboolean com_android_server_ApfTest_dropsAllPackets(JNIEnv* env, jclass, jbyteArray jprogram,
+ jbyteArray jdata, jstring jpcap_filename) {
+ ScopedUtfChars pcap_filename(env, jpcap_filename);
+ ScopedByteArrayRO apf_program(env, jprogram);
+ uint32_t apf_program_len = (uint32_t)apf_program.size();
+ uint32_t data_len = env->GetArrayLength(jdata);
+ pcap_pkthdr apf_header;
+ const uint8_t* apf_packet;
+ char pcap_error[PCAP_ERRBUF_SIZE];
+ std::vector<uint8_t> buf(apf_program_len + data_len, 0);
+
+ // Merge program and data into a single buffer.
+ env->GetByteArrayRegion(jprogram, 0, apf_program_len, reinterpret_cast<jbyte*>(buf.data()));
+ env->GetByteArrayRegion(jdata, 0, data_len,
+ reinterpret_cast<jbyte*>(buf.data() + apf_program_len));
+
+ // Open pcap file
+ ScopedFILE apf_fp(fopen(pcap_filename.c_str(), "rb"));
+ ScopedPcap apf_pcap(pcap_fopen_offline(apf_fp.get(), pcap_error));
+
+ if (apf_pcap.get() == NULL) {
+ throwException(env, "pcap_fopen_offline failed: " + std::string(pcap_error));
+ return false;
+ }
+
+ while ((apf_packet = pcap_next(apf_pcap.get(), &apf_header)) != NULL) {
+ int result = accept_packet(buf.data(), apf_program_len,
+ apf_program_len + data_len, apf_packet, apf_header.len, 0);
+
+ // Return false once packet passes the filter
+ if (result) {
+ env->SetByteArrayRegion(jdata, 0, data_len,
+ reinterpret_cast<jbyte*>(buf.data() + apf_program_len));
+ return false;
+ }
+ }
+
+ env->SetByteArrayRegion(jdata, 0, data_len,
+ reinterpret_cast<jbyte*>(buf.data() + apf_program_len));
+ return true;
+}
+
extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
JNIEnv *env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
@@ -192,6 +237,8 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
(void*)com_android_server_ApfTest_compileToBpf },
{ "compareBpfApf", "(Ljava/lang/String;Ljava/lang/String;[B)Z",
(void*)com_android_server_ApfTest_compareBpfApf },
+ { "dropsAllPackets", "([B[BLjava/lang/String;)Z",
+ (void*)com_android_server_ApfTest_dropsAllPackets },
};
jniRegisterNativeMethods(env, "android/net/apf/ApfTest",
diff --git a/tests/net/res/raw/apfPcap.pcap b/tests/net/res/raw/apfPcap.pcap
new file mode 100644
index 000000000000..6f69c4add0f8
--- /dev/null
+++ b/tests/net/res/raw/apfPcap.pcap
Binary files differ