Merge "Update ripple according to UX feedback."
diff --git a/apct-tests/perftests/multiuser/Android.mk b/apct-tests/perftests/multiuser/Android.mk
index e3f7775..2db0dd6 100644
--- a/apct-tests/perftests/multiuser/Android.mk
+++ b/apct-tests/perftests/multiuser/Android.mk
@@ -20,7 +20,8 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_STATIC_JAVA_LIBRARIES := \
- android-support-test
+ android-support-test \
+ ub-uiautomator
LOCAL_PACKAGE_NAME := MultiUserPerfTests
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java
index c7bebf3..629e6f4 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java
@@ -17,13 +17,16 @@
import android.os.Bundle;
import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.uiautomator.UiDevice;
+import java.io.IOException;
import java.util.ArrayList;
// Based on //platform/frameworks/base/apct-tests/perftests/utils/BenchmarkState.java
public class BenchmarkRunner {
- private static long COOL_OFF_PERIOD_MS = 2000;
+ private static final long COOL_OFF_PERIOD_MS = 1000;
private static final int NUM_ITERATIONS = 4;
@@ -70,9 +73,13 @@
}
private void prepareForNextRun() {
- // TODO: Once http://b/63115387 is fixed, look into using "am wait-for-broadcast-idle"
- // command instead of waiting for a fixed amount of time.
SystemClock.sleep(COOL_OFF_PERIOD_MS);
+ try {
+ UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+ .executeShellCommand("am wait-for-broadcast-idle");
+ } catch (IOException e) {
+ throw new IllegalStateException("Cannot execute shell command", e);
+ }
mStartTimeNs = System.nanoTime();
mPausedDurationNs = 0;
}
diff --git a/api/current.txt b/api/current.txt
index f0aa1d3..f865d14 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -37137,6 +37137,8 @@
method public android.service.autofill.Dataset.Builder setId(java.lang.String);
method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue);
method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, android.widget.RemoteViews);
+ method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, java.util.regex.Pattern);
+ method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, java.util.regex.Pattern, android.widget.RemoteViews);
}
public final class FillCallback {
@@ -37204,8 +37206,10 @@
}
public static class ImageTransformation.Builder {
- ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int);
- method public android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int);
+ ctor public deprecated ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int);
+ ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int, java.lang.CharSequence);
+ method public deprecated android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int);
+ method public android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int, java.lang.CharSequence);
method public android.service.autofill.ImageTransformation build();
}
@@ -37223,6 +37227,9 @@
field public static final android.os.Parcelable.Creator<android.service.autofill.RegexValidator> CREATOR;
}
+ public abstract interface Sanitizer {
+ }
+
public final class SaveCallback {
method public void onFailure(java.lang.CharSequence);
method public void onSuccess();
@@ -37246,6 +37253,7 @@
public static final class SaveInfo.Builder {
ctor public SaveInfo.Builder(int, android.view.autofill.AutofillId[]);
ctor public SaveInfo.Builder(int);
+ method public android.service.autofill.SaveInfo.Builder addSanitizer(android.service.autofill.Sanitizer, android.view.autofill.AutofillId...);
method public android.service.autofill.SaveInfo build();
method public android.service.autofill.SaveInfo.Builder setCustomDescription(android.service.autofill.CustomDescription);
method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence);
@@ -37264,6 +37272,13 @@
field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR;
}
+ public final class TextValueSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer {
+ ctor public TextValueSanitizer(java.util.regex.Pattern, java.lang.String);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.TextValueSanitizer> CREATOR;
+ }
+
public abstract interface Transformation {
}
@@ -45964,8 +45979,8 @@
method public boolean hasTransientState();
method public boolean hasWindowFocus();
method public static android.view.View inflate(android.content.Context, int, android.view.ViewGroup);
- method public void invalidate(android.graphics.Rect);
- method public void invalidate(int, int, int, int);
+ method public deprecated void invalidate(android.graphics.Rect);
+ method public deprecated void invalidate(int, int, int, int);
method public void invalidate();
method public void invalidateDrawable(android.graphics.drawable.Drawable);
method public void invalidateOutline();
diff --git a/api/system-current.txt b/api/system-current.txt
index 4e68265..a8b41be 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6314,6 +6314,7 @@
}
public class VrManager {
+ method public void setAndBindVrCompositor(android.content.ComponentName);
method public void setPersistentVrModeEnabled(boolean);
}
@@ -40232,6 +40233,8 @@
method public android.service.autofill.Dataset.Builder setId(java.lang.String);
method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue);
method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, android.widget.RemoteViews);
+ method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, java.util.regex.Pattern);
+ method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, java.util.regex.Pattern, android.widget.RemoteViews);
}
public final class FillCallback {
@@ -40299,8 +40302,10 @@
}
public static class ImageTransformation.Builder {
- ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int);
- method public android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int);
+ ctor public deprecated ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int);
+ ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int, java.lang.CharSequence);
+ method public deprecated android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int);
+ method public android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int, java.lang.CharSequence);
method public android.service.autofill.ImageTransformation build();
}
@@ -40318,6 +40323,9 @@
field public static final android.os.Parcelable.Creator<android.service.autofill.RegexValidator> CREATOR;
}
+ public abstract interface Sanitizer {
+ }
+
public final class SaveCallback {
method public void onFailure(java.lang.CharSequence);
method public void onSuccess();
@@ -40341,6 +40349,7 @@
public static final class SaveInfo.Builder {
ctor public SaveInfo.Builder(int, android.view.autofill.AutofillId[]);
ctor public SaveInfo.Builder(int);
+ method public android.service.autofill.SaveInfo.Builder addSanitizer(android.service.autofill.Sanitizer, android.view.autofill.AutofillId...);
method public android.service.autofill.SaveInfo build();
method public android.service.autofill.SaveInfo.Builder setCustomDescription(android.service.autofill.CustomDescription);
method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence);
@@ -40359,6 +40368,13 @@
field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR;
}
+ public final class TextValueSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer {
+ ctor public TextValueSanitizer(java.util.regex.Pattern, java.lang.String);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.TextValueSanitizer> CREATOR;
+ }
+
public abstract interface Transformation {
}
@@ -49661,8 +49677,8 @@
method public boolean hasTransientState();
method public boolean hasWindowFocus();
method public static android.view.View inflate(android.content.Context, int, android.view.ViewGroup);
- method public void invalidate(android.graphics.Rect);
- method public void invalidate(int, int, int, int);
+ method public deprecated void invalidate(android.graphics.Rect);
+ method public deprecated void invalidate(int, int, int, int);
method public void invalidate();
method public void invalidateDrawable(android.graphics.drawable.Drawable);
method public void invalidateOutline();
diff --git a/api/test-current.txt b/api/test-current.txt
index 435f3b4..38b15b4 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -37426,6 +37426,8 @@
method public android.service.autofill.Dataset.Builder setId(java.lang.String);
method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue);
method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, android.widget.RemoteViews);
+ method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, java.util.regex.Pattern);
+ method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, java.util.regex.Pattern, android.widget.RemoteViews);
}
public final class FillCallback {
@@ -37494,11 +37496,17 @@
}
public static class ImageTransformation.Builder {
- ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int);
- method public android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int);
+ ctor public deprecated ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int);
+ ctor public ImageTransformation.Builder(android.view.autofill.AutofillId, java.util.regex.Pattern, int, java.lang.CharSequence);
+ method public deprecated android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int);
+ method public android.service.autofill.ImageTransformation.Builder addOption(java.util.regex.Pattern, int, java.lang.CharSequence);
method public android.service.autofill.ImageTransformation build();
}
+ public abstract class InternalSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer {
+ ctor public InternalSanitizer();
+ }
+
public final class LuhnChecksumValidator implements android.os.Parcelable android.service.autofill.Validator {
ctor public LuhnChecksumValidator(android.view.autofill.AutofillId...);
method public int describeContents();
@@ -37515,6 +37523,9 @@
field public static final android.os.Parcelable.Creator<android.service.autofill.RegexValidator> CREATOR;
}
+ public abstract interface Sanitizer {
+ }
+
public final class SaveCallback {
method public void onFailure(java.lang.CharSequence);
method public void onSuccess();
@@ -37538,6 +37549,7 @@
public static final class SaveInfo.Builder {
ctor public SaveInfo.Builder(int, android.view.autofill.AutofillId[]);
ctor public SaveInfo.Builder(int);
+ method public android.service.autofill.SaveInfo.Builder addSanitizer(android.service.autofill.Sanitizer, android.view.autofill.AutofillId...);
method public android.service.autofill.SaveInfo build();
method public android.service.autofill.SaveInfo.Builder setCustomDescription(android.service.autofill.CustomDescription);
method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence);
@@ -37556,6 +37568,14 @@
field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR;
}
+ public final class TextValueSanitizer extends android.service.autofill.InternalSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer {
+ ctor public TextValueSanitizer(java.util.regex.Pattern, java.lang.String);
+ method public int describeContents();
+ method public android.view.autofill.AutofillValue sanitize(android.view.autofill.AutofillValue);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.TextValueSanitizer> CREATOR;
+ }
+
public abstract interface Transformation {
}
@@ -46504,8 +46524,8 @@
method public boolean hasTransientState();
method public boolean hasWindowFocus();
method public static android.view.View inflate(android.content.Context, int, android.view.ViewGroup);
- method public void invalidate(android.graphics.Rect);
- method public void invalidate(int, int, int, int);
+ method public deprecated void invalidate(android.graphics.Rect);
+ method public deprecated void invalidate(int, int, int, int);
method public void invalidate();
method public void invalidateDrawable(android.graphics.drawable.Drawable);
method public void invalidateOutline();
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 64b9ae8..47063f0 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -15,8 +15,11 @@
*/
package android.app;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.NotificationManager.Importance;
+import android.content.ContentResolver;
+import android.content.Context;
import android.content.Intent;
import android.media.AudioAttributes;
import android.net.Uri;
@@ -27,6 +30,8 @@
import android.text.TextUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.util.Preconditions;
+
import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParser;
@@ -569,14 +574,35 @@
/**
* @hide
*/
+ public void populateFromXmlForRestore(XmlPullParser parser, Context context) {
+ populateFromXml(parser, true, context);
+ }
+
+ /**
+ * @hide
+ */
@SystemApi
public void populateFromXml(XmlPullParser parser) {
+ populateFromXml(parser, false, null);
+ }
+
+ /**
+ * If {@param forRestore} is true, {@param Context} MUST be non-null.
+ */
+ private void populateFromXml(XmlPullParser parser, boolean forRestore,
+ @Nullable Context context) {
+ Preconditions.checkArgument(!forRestore || context != null,
+ "forRestore is true but got null context");
+
// Name, id, and importance are set in the constructor.
setDescription(parser.getAttributeValue(null, ATT_DESC));
setBypassDnd(Notification.PRIORITY_DEFAULT
!= safeInt(parser, ATT_PRIORITY, Notification.PRIORITY_DEFAULT));
setLockscreenVisibility(safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY));
- setSound(safeUri(parser, ATT_SOUND), safeAudioAttributes(parser));
+
+ Uri sound = safeUri(parser, ATT_SOUND);
+ setSound(forRestore ? restoreSoundUri(context, sound) : sound, safeAudioAttributes(parser));
+
enableLights(safeBool(parser, ATT_LIGHTS, false));
setLightColor(safeInt(parser, ATT_LIGHT_COLOR, DEFAULT_LIGHT_COLOR));
setVibrationPattern(safeLongArray(parser, ATT_VIBRATION, null));
@@ -588,11 +614,62 @@
setBlockableSystem(safeBool(parser, ATT_BLOCKABLE_SYSTEM, false));
}
+ @Nullable
+ private Uri restoreSoundUri(Context context, @Nullable Uri uri) {
+ if (uri == null) {
+ return null;
+ }
+ ContentResolver contentResolver = context.getContentResolver();
+ // There are backups out there with uncanonical uris (because we fixed this after
+ // shipping). If uncanonical uris are given to MediaProvider.uncanonicalize it won't
+ // verify the uri against device storage and we'll possibly end up with a broken uri.
+ // We then canonicalize the uri to uncanonicalize it back, which means we properly check
+ // the uri and in the case of not having the resource we end up with the default - better
+ // than broken. As a side effect we'll canonicalize already canonicalized uris, this is fine
+ // according to the docs because canonicalize method has to handle canonical uris as well.
+ Uri canonicalizedUri = contentResolver.canonicalize(uri);
+ if (canonicalizedUri == null) {
+ // We got a null because the uri in the backup does not exist here, so we return default
+ return Settings.System.DEFAULT_NOTIFICATION_URI;
+ }
+ return contentResolver.uncanonicalize(canonicalizedUri);
+ }
+
/**
* @hide
*/
@SystemApi
public void writeXml(XmlSerializer out) throws IOException {
+ writeXml(out, false, null);
+ }
+
+ /**
+ * @hide
+ */
+ public void writeXmlForBackup(XmlSerializer out, Context context) throws IOException {
+ writeXml(out, true, context);
+ }
+
+ private Uri getSoundForBackup(Context context) {
+ Uri sound = getSound();
+ if (sound == null) {
+ return null;
+ }
+ Uri canonicalSound = context.getContentResolver().canonicalize(sound);
+ if (canonicalSound == null) {
+ // The content provider does not support canonical uris so we backup the default
+ return Settings.System.DEFAULT_NOTIFICATION_URI;
+ }
+ return canonicalSound;
+ }
+
+ /**
+ * If {@param forBackup} is true, {@param Context} MUST be non-null.
+ */
+ private void writeXml(XmlSerializer out, boolean forBackup, @Nullable Context context)
+ throws IOException {
+ Preconditions.checkArgument(!forBackup || context != null,
+ "forBackup is true but got null context");
out.startTag(null, TAG_CHANNEL);
out.attribute(null, ATT_ID, getId());
if (getName() != null) {
@@ -613,8 +690,9 @@
out.attribute(null, ATT_VISIBILITY,
Integer.toString(getLockscreenVisibility()));
}
- if (getSound() != null) {
- out.attribute(null, ATT_SOUND, getSound().toString());
+ Uri sound = forBackup ? getSoundForBackup(context) : getSound();
+ if (sound != null) {
+ out.attribute(null, ATT_SOUND, sound.toString());
}
if (getAudioAttributes() != null) {
out.attribute(null, ATT_USAGE, Integer.toString(getAudioAttributes().getUsage()));
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 80144bd..8987bc0 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -72,13 +72,16 @@
*/
public static final int DISABLE2_QUICK_SETTINGS = 1;
public static final int DISABLE2_SYSTEM_ICONS = 1 << 1;
+ public static final int DISABLE2_NOTIFICATION_SHADE = 1 << 2;
public static final int DISABLE2_NONE = 0x00000000;
- public static final int DISABLE2_MASK = DISABLE2_QUICK_SETTINGS | DISABLE2_SYSTEM_ICONS;
+ public static final int DISABLE2_MASK = DISABLE2_QUICK_SETTINGS | DISABLE2_SYSTEM_ICONS
+ | DISABLE2_NOTIFICATION_SHADE;
@IntDef(flag = true,
- value = {DISABLE2_NONE, DISABLE2_MASK, DISABLE2_QUICK_SETTINGS, DISABLE2_SYSTEM_ICONS})
+ value = {DISABLE2_NONE, DISABLE2_MASK, DISABLE2_QUICK_SETTINGS, DISABLE2_SYSTEM_ICONS,
+ DISABLE2_NOTIFICATION_SHADE})
@Retention(RetentionPolicy.SOURCE)
public @interface Disable2Flags {}
diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java
index 5786238..5c6ffa3 100644
--- a/core/java/android/app/VrManager.java
+++ b/core/java/android/app/VrManager.java
@@ -4,6 +4,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.content.ComponentName;
import android.content.Context;
import android.os.Handler;
import android.os.RemoteException;
@@ -181,4 +182,20 @@
e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Set the component name of the compositor service to bind.
+ *
+ * @param componentName ComponentName of a Service in the application's compositor process to
+ * bind to, or null to clear the current binding.
+ */
+ @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS)
+ public void setAndBindVrCompositor(ComponentName componentName) {
+ try {
+ mService.setAndBindCompositor(
+ (componentName == null) ? null : componentName.flattenToString());
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 9ccc552..02e70f5 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -47,6 +47,8 @@
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.slice.Slice;
+import android.slice.SliceProvider;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
@@ -178,6 +180,8 @@
public static final Intent ACTION_SYNC_CONN_STATUS_CHANGED =
new Intent("com.android.sync.SYNC_CONN_STATUS_CHANGED");
+ /** @hide */
+ public static final String SCHEME_SLICE = "slice";
public static final String SCHEME_CONTENT = "content";
public static final String SCHEME_ANDROID_RESOURCE = "android.resource";
public static final String SCHEME_FILE = "file";
@@ -1718,6 +1722,36 @@
}
/**
+ * Turns a slice Uri into slice content.
+ *
+ * @param uri The URI to a slice provider
+ * @return The Slice provided by the app or null if none is given.
+ * @see Slice
+ * @hide
+ */
+ public final @Nullable Slice bindSlice(@NonNull Uri uri) {
+ Preconditions.checkNotNull(uri, "uri");
+ IContentProvider provider = acquireProvider(uri);
+ if (provider == null) {
+ throw new IllegalArgumentException("Unknown URI " + uri);
+ }
+ try {
+ Bundle extras = new Bundle();
+ extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
+ final Bundle res = provider.call(mPackageName, SliceProvider.METHOD_SLICE, null,
+ extras);
+ Bundle.setDefusable(res, true);
+ return res.getParcelable(SliceProvider.EXTRA_SLICE);
+ } catch (RemoteException e) {
+ // Arbitrary and not worth documenting, as Activity
+ // Manager will kill this process shortly anyway.
+ return null;
+ } finally {
+ releaseProvider(provider);
+ }
+ }
+
+ /**
* Returns the content provider for the given content URI.
*
* @param uri The URI to a content provider
@@ -1725,7 +1759,7 @@
* @hide
*/
public final IContentProvider acquireProvider(Uri uri) {
- if (!SCHEME_CONTENT.equals(uri.getScheme())) {
+ if (!SCHEME_CONTENT.equals(uri.getScheme()) && !SCHEME_SLICE.equals(uri.getScheme())) {
return null;
}
final String auth = uri.getAuthority();
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 4c981cd..be7f921 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -16,6 +16,9 @@
package android.content.pm;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager.ApplicationInfoFlags;
@@ -25,6 +28,8 @@
import android.os.Bundle;
import android.util.SparseArray;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.List;
/**
@@ -33,6 +38,20 @@
* @hide Only for use within the system server.
*/
public abstract class PackageManagerInternal {
+ public static final int PACKAGE_SYSTEM = 0;
+ public static final int PACKAGE_SETUP_WIZARD = 1;
+ public static final int PACKAGE_INSTALLER = 2;
+ public static final int PACKAGE_VERIFIER = 3;
+ public static final int PACKAGE_BROWSER = 4;
+ @IntDef(value = {
+ PACKAGE_SYSTEM,
+ PACKAGE_SETUP_WIZARD,
+ PACKAGE_INSTALLER,
+ PACKAGE_VERIFIER,
+ PACKAGE_BROWSER,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface KnownPackage {}
/**
* Provider for package names.
@@ -172,6 +191,13 @@
@ResolveInfoFlags int flags, int filterCallingUid, int userId);
/**
+ * Retrieve all services that can be performed for the given intent.
+ * @see PackageManager#queryIntentServices(Intent, int)
+ */
+ public abstract List<ResolveInfo> queryIntentServices(
+ Intent intent, int flags, int callingUid, int userId);
+
+ /**
* Interface to {@link com.android.server.pm.PackageManagerService#getHomeActivitiesAsUser}.
*/
public abstract ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
@@ -343,14 +369,19 @@
* Resolves an activity intent, allowing instant apps to be resolved.
*/
public abstract ResolveInfo resolveIntent(Intent intent, String resolvedType,
- int flags, int userId);
+ int flags, int userId, boolean resolveForStart);
/**
* Resolves a service intent, allowing instant apps to be resolved.
*/
- public abstract ResolveInfo resolveService(Intent intent, String resolvedType,
+ public abstract ResolveInfo resolveService(Intent intent, String resolvedType,
int flags, int userId, int callingUid);
+ /**
+ * Resolves a content provider intent.
+ */
+ public abstract ProviderInfo resolveContentProvider(String name, int flags, int userId);
+
/**
* Track the creator of a new isolated uid.
* @param isolatedUid The newly created isolated uid.
@@ -383,4 +414,59 @@
* Updates a package last used time.
*/
public abstract void notifyPackageUse(String packageName, int reason);
+
+ /**
+ * Returns a package object for the given package name.
+ */
+ public abstract @Nullable PackageParser.Package getPackage(@NonNull String packageName);
+
+ /**
+ * Returns a package object for the disabled system package name.
+ */
+ public abstract @Nullable PackageParser.Package getDisabledPackage(@NonNull String packageName);
+
+ /**
+ * Returns whether or not the component is the resolver activity.
+ */
+ public abstract boolean isResolveActivityComponent(@NonNull ComponentInfo component);
+
+ /**
+ * Returns the package name for a known package.
+ */
+ public abstract @Nullable String getKnownPackageName(
+ @KnownPackage int knownPackage, int userId);
+
+ /**
+ * Returns whether the package is an instant app.
+ */
+ public abstract boolean isInstantApp(String packageName, int userId);
+
+ /**
+ * Returns whether the package is an instant app.
+ */
+ public abstract @Nullable String getInstantAppPackageName(int uid);
+
+ /**
+ * Returns whether or not access to the application should be filtered.
+ * <p>
+ * Access may be limited based upon whether the calling or target applications
+ * are instant applications.
+ *
+ * @see #canAccessInstantApps(int)
+ */
+ public abstract boolean filterAppAccess(
+ @Nullable PackageParser.Package pkg, int callingUid, int userId);
+
+ /*
+ * NOTE: The following methods are temporary until permissions are extracted from
+ * the package manager into a component specifically for handling permissions.
+ */
+ /** Returns the flags for the given permission. */
+ public abstract @Nullable int getPermissionFlagsTEMP(@NonNull String permName,
+ @NonNull String packageName, int userId);
+ /** Updates the flags for the given permission. */
+ public abstract void updatePermissionFlagsTEMP(@NonNull String permName,
+ @NonNull String packageName, int flagMask, int flagValues, int userId);
+ /** temporary until mPermissionTrees is moved to PermissionManager */
+ public abstract Object enforcePermissionTreeTEMP(@NonNull String permName, int callingUid);
}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 6fbacaf..ae4f05a 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -278,6 +278,15 @@
*/
public static final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 1 << 7;
+ /**
+ * Virtual display flag: Indicates that the contents will be destroyed once
+ * the display is removed.
+ *
+ * @see #createVirtualDisplay
+ * @hide
+ */
+ public static final int VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL = 1 << 8;
+
/** @hide */
public DisplayManager(Context context) {
mContext = context;
diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java
index ceccc07..632b7fc 100644
--- a/core/java/android/net/IpSecConfig.java
+++ b/core/java/android/net/IpSecConfig.java
@@ -34,7 +34,7 @@
// Preventing this from being null simplifies Java->Native binder
private String mRemoteAddress = "";
- // The underlying network interface that represents the "gateway" Network
+ // The underlying Network that represents the "gateway" Network
// for outbound packets. It may also be used to select packets.
private Network mNetwork;
@@ -273,6 +273,7 @@
};
@VisibleForTesting
+ /** Equals method used for testing */
public static boolean equals(IpSecConfig lhs, IpSecConfig rhs) {
if (lhs == null || rhs == null) return (lhs == rhs);
return (lhs.mMode == rhs.mMode
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index 529cf1a..e15a2c6 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -409,8 +409,6 @@
public IpSecTransform buildTransportModeTransform(InetAddress remoteAddress)
throws IpSecManager.ResourceUnavailableException,
IpSecManager.SpiUnavailableException, IOException {
- //FIXME: argument validation here
- //throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation");
mConfig.setMode(MODE_TRANSPORT);
mConfig.setRemoteAddress(remoteAddress.getHostAddress());
return new IpSecTransform(mContext, mConfig).activate();
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 66b6b47..bf0a264 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -78,17 +78,17 @@
* A constant indicating a sensor timer.
*/
public static final int SENSOR = 3;
-
+
/**
* A constant indicating a a wifi running timer
*/
public static final int WIFI_RUNNING = 4;
-
+
/**
* A constant indicating a full wifi lock timer
*/
public static final int FULL_WIFI_LOCK = 5;
-
+
/**
* A constant indicating a wifi scan
*/
@@ -217,8 +217,10 @@
* - Package wakeup alarms are now on screen-off timebase
* New in version 26:
* - Resource power manager (rpm) states [but screenOffRpm is disabled from working properly]
+ * New in version 27:
+ * - Always On Display (screen doze mode) time and power
*/
- static final String CHECKIN_VERSION = "26";
+ static final String CHECKIN_VERSION = "27";
/**
* Old version, we hit 9 and ran out of room, need to remove.
@@ -1381,12 +1383,12 @@
public static final int STATE_PHONE_SCANNING_FLAG = 1<<21;
public static final int STATE_SCREEN_ON_FLAG = 1<<20; // consider moving to states2
public static final int STATE_BATTERY_PLUGGED_FLAG = 1<<19; // consider moving to states2
- // empty slot
+ public static final int STATE_SCREEN_DOZE_FLAG = 1 << 18;
// empty slot
public static final int STATE_WIFI_MULTICAST_ON_FLAG = 1<<16;
public static final int MOST_INTERESTING_STATES =
- STATE_BATTERY_PLUGGED_FLAG | STATE_SCREEN_ON_FLAG;
+ STATE_BATTERY_PLUGGED_FLAG | STATE_SCREEN_ON_FLAG | STATE_SCREEN_DOZE_FLAG;
public static final int SETTLE_TO_ZERO_STATES = 0xffff0000 & ~MOST_INTERESTING_STATES;
@@ -1414,8 +1416,8 @@
public static final int STATE2_BLUETOOTH_SCAN_FLAG = 1 << 20;
public static final int MOST_INTERESTING_STATES2 =
- STATE2_POWER_SAVE_FLAG | STATE2_WIFI_ON_FLAG | STATE2_DEVICE_IDLE_MASK
- | STATE2_CHARGING_FLAG | STATE2_PHONE_IN_CALL_FLAG | STATE2_BLUETOOTH_ON_FLAG;
+ STATE2_POWER_SAVE_FLAG | STATE2_WIFI_ON_FLAG | STATE2_DEVICE_IDLE_MASK
+ | STATE2_CHARGING_FLAG | STATE2_PHONE_IN_CALL_FLAG | STATE2_BLUETOOTH_ON_FLAG;
public static final int SETTLE_TO_ZERO_STATES2 = 0xffff0000 & ~MOST_INTERESTING_STATES2;
@@ -1863,6 +1865,21 @@
*/
public abstract int getScreenOnCount(int which);
+ /**
+ * Returns the time in microseconds that the screen has been dozing while the device was
+ * running on battery.
+ *
+ * {@hide}
+ */
+ public abstract long getScreenDozeTime(long elapsedRealtimeUs, int which);
+
+ /**
+ * Returns the number of times the screen was turned dozing.
+ *
+ * {@hide}
+ */
+ public abstract int getScreenDozeCount(int which);
+
public abstract long getInteractiveTime(long elapsedRealtimeUs, int which);
public static final int SCREEN_BRIGHTNESS_DARK = 0;
@@ -2116,8 +2133,7 @@
"group", "compl", "dorm", "uninit"
};
- public static final BitDescription[] HISTORY_STATE_DESCRIPTIONS
- = new BitDescription[] {
+ public static final BitDescription[] HISTORY_STATE_DESCRIPTIONS = new BitDescription[] {
new BitDescription(HistoryItem.STATE_CPU_RUNNING_FLAG, "running", "r"),
new BitDescription(HistoryItem.STATE_WAKE_LOCK_FLAG, "wake_lock", "w"),
new BitDescription(HistoryItem.STATE_SENSOR_ON_FLAG, "sensor", "s"),
@@ -2131,6 +2147,7 @@
new BitDescription(HistoryItem.STATE_AUDIO_ON_FLAG, "audio", "a"),
new BitDescription(HistoryItem.STATE_SCREEN_ON_FLAG, "screen", "S"),
new BitDescription(HistoryItem.STATE_BATTERY_PLUGGED_FLAG, "plugged", "BP"),
+ new BitDescription(HistoryItem.STATE_SCREEN_DOZE_FLAG, "screen_doze", "Sd"),
new BitDescription(HistoryItem.STATE_DATA_CONNECTION_MASK,
HistoryItem.STATE_DATA_CONNECTION_SHIFT, "data_conn", "Pcn",
DATA_CONNECTION_NAMES, DATA_CONNECTION_NAMES),
@@ -2467,6 +2484,18 @@
public abstract int getDischargeAmountScreenOffSinceCharge();
/**
+ * Get the amount the battery has discharged while the screen was doze,
+ * since the last time power was unplugged.
+ */
+ public abstract int getDischargeAmountScreenDoze();
+
+ /**
+ * Get the amount the battery has discharged while the screen was doze,
+ * since the last time the device was charged.
+ */
+ public abstract int getDischargeAmountScreenDozeSinceCharge();
+
+ /**
* Returns the total, last, or current battery uptime in microseconds.
*
* @param curTime the elapsed realtime in microseconds.
@@ -2483,7 +2512,7 @@
public abstract long computeBatteryRealtime(long curTime, int which);
/**
- * Returns the total, last, or current battery screen off uptime in microseconds.
+ * Returns the total, last, or current battery screen off/doze uptime in microseconds.
*
* @param curTime the elapsed realtime in microseconds.
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
@@ -2491,7 +2520,7 @@
public abstract long computeBatteryScreenOffUptime(long curTime, int which);
/**
- * Returns the total, last, or current battery screen off realtime in microseconds.
+ * Returns the total, last, or current battery screen off/doze realtime in microseconds.
*
* @param curTime the current elapsed realtime in microseconds.
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
@@ -2590,18 +2619,24 @@
};
/**
- * Return the counter keeping track of the amount of battery discharge while the screen was off,
- * measured in micro-Ampere-hours. This will be non-zero only if the device's battery has
- * a coulomb counter.
- */
- public abstract LongCounter getDischargeScreenOffCoulombCounter();
-
- /**
- * Return the counter keeping track of the amount of battery discharge measured in
+ * Return the amount of battery discharge while the screen was off, measured in
* micro-Ampere-hours. This will be non-zero only if the device's battery has
* a coulomb counter.
*/
- public abstract LongCounter getDischargeCoulombCounter();
+ public abstract long getMahDischargeScreenOff(int which);
+
+ /**
+ * Return the amount of battery discharge while the screen was in doze mode, measured in
+ * micro-Ampere-hours. This will be non-zero only if the device's battery has
+ * a coulomb counter.
+ */
+ public abstract long getMahDischargeScreenDoze(int which);
+
+ /**
+ * Return the amount of battery discharge measured in micro-Ampere-hours. This will be
+ * non-zero only if the device's battery has a coulomb counter.
+ */
+ public abstract long getMahDischarge(int which);
/**
* Returns the estimated real battery capacity, which may be less than the capacity
@@ -3112,6 +3147,7 @@
final long totalRealtime = computeRealtime(rawRealtime, which);
final long totalUptime = computeUptime(rawUptime, which);
final long screenOnTime = getScreenOnTime(rawRealtime, which);
+ final long screenDozeTime = getScreenDozeTime(rawRealtime, which);
final long interactiveTime = getInteractiveTime(rawRealtime, which);
final long powerSaveModeEnabledTime = getPowerSaveModeEnabledTime(rawRealtime, which);
final long deviceIdleModeLightTime = getDeviceIdleModeTime(DEVICE_IDLE_MODE_LIGHT,
@@ -3124,9 +3160,9 @@
rawRealtime, which);
final int connChanges = getNumConnectivityChange(which);
final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
- final long dischargeCount = getDischargeCoulombCounter().getCountLocked(which);
- final long dischargeScreenOffCount = getDischargeScreenOffCoulombCounter()
- .getCountLocked(which);
+ final long dischargeCount = getMahDischarge(which);
+ final long dischargeScreenOffCount = getMahDischargeScreenOff(which);
+ final long dischargeScreenDozeCount = getMahDischargeScreenDoze(which);
final StringBuilder sb = new StringBuilder(128);
@@ -3143,7 +3179,8 @@
getStartClockTime(),
whichBatteryScreenOffRealtime / 1000, whichBatteryScreenOffUptime / 1000,
getEstimatedBatteryCapacity(),
- getMinLearnedBatteryCapacity(), getMaxLearnedBatteryCapacity());
+ getMinLearnedBatteryCapacity(), getMaxLearnedBatteryCapacity(),
+ screenDozeTime / 1000);
// Calculate wakelock times across all uids.
@@ -3295,13 +3332,15 @@
getDischargeStartLevel()-getDischargeCurrentLevel(),
getDischargeStartLevel()-getDischargeCurrentLevel(),
getDischargeAmountScreenOn(), getDischargeAmountScreenOff(),
- dischargeCount / 1000, dischargeScreenOffCount / 1000);
+ dischargeCount / 1000, dischargeScreenOffCount / 1000,
+ getDischargeAmountScreenDoze(), dischargeScreenDozeCount / 1000);
} else {
dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA,
getLowDischargeAmountSinceCharge(), getHighDischargeAmountSinceCharge(),
getDischargeAmountScreenOnSinceCharge(),
getDischargeAmountScreenOffSinceCharge(),
- dischargeCount / 1000, dischargeScreenOffCount / 1000);
+ dischargeCount / 1000, dischargeScreenOffCount / 1000,
+ getDischargeAmountScreenDozeSinceCharge(), dischargeScreenDozeCount / 1000);
}
if (reqUid < 0) {
@@ -3831,6 +3870,7 @@
which);
final long batteryTimeRemaining = computeBatteryTimeRemaining(rawRealtime);
final long chargeTimeRemaining = computeChargeTimeRemaining(rawRealtime);
+ final long screenDozeTime = getScreenDozeTime(rawRealtime, which);
final StringBuilder sb = new StringBuilder(128);
@@ -3868,25 +3908,35 @@
sb.setLength(0);
sb.append(prefix);
- sb.append(" Time on battery: ");
- formatTimeMs(sb, whichBatteryRealtime / 1000); sb.append("(");
- sb.append(formatRatioLocked(whichBatteryRealtime, totalRealtime));
- sb.append(") realtime, ");
- formatTimeMs(sb, whichBatteryUptime / 1000);
- sb.append("("); sb.append(formatRatioLocked(whichBatteryUptime, totalRealtime));
- sb.append(") uptime");
+ sb.append(" Time on battery: ");
+ formatTimeMs(sb, whichBatteryRealtime / 1000); sb.append("(");
+ sb.append(formatRatioLocked(whichBatteryRealtime, totalRealtime));
+ sb.append(") realtime, ");
+ formatTimeMs(sb, whichBatteryUptime / 1000);
+ sb.append("("); sb.append(formatRatioLocked(whichBatteryUptime, whichBatteryRealtime));
+ sb.append(") uptime");
pw.println(sb.toString());
+
sb.setLength(0);
sb.append(prefix);
- sb.append(" Time on battery screen off: ");
- formatTimeMs(sb, whichBatteryScreenOffRealtime / 1000); sb.append("(");
- sb.append(formatRatioLocked(whichBatteryScreenOffRealtime, totalRealtime));
- sb.append(") realtime, ");
- formatTimeMs(sb, whichBatteryScreenOffUptime / 1000);
- sb.append("(");
- sb.append(formatRatioLocked(whichBatteryScreenOffUptime, totalRealtime));
- sb.append(") uptime");
+ sb.append(" Time on battery screen off: ");
+ formatTimeMs(sb, whichBatteryScreenOffRealtime / 1000); sb.append("(");
+ sb.append(formatRatioLocked(whichBatteryScreenOffRealtime, whichBatteryRealtime));
+ sb.append(") realtime, ");
+ formatTimeMs(sb, whichBatteryScreenOffUptime / 1000);
+ sb.append("(");
+ sb.append(formatRatioLocked(whichBatteryScreenOffUptime, whichBatteryRealtime));
+ sb.append(") uptime");
pw.println(sb.toString());
+
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Time on battery screen doze: ");
+ formatTimeMs(sb, screenDozeTime / 1000); sb.append("(");
+ sb.append(formatRatioLocked(screenDozeTime, whichBatteryRealtime));
+ sb.append(")");
+ pw.println(sb.toString());
+
sb.setLength(0);
sb.append(prefix);
sb.append(" Total run time: ");
@@ -3910,8 +3960,7 @@
pw.println(sb.toString());
}
- final LongCounter dischargeCounter = getDischargeCoulombCounter();
- final long dischargeCount = dischargeCounter.getCountLocked(which);
+ final long dischargeCount = getMahDischarge(which);
if (dischargeCount >= 0) {
sb.setLength(0);
sb.append(prefix);
@@ -3921,8 +3970,7 @@
pw.println(sb.toString());
}
- final LongCounter dischargeScreenOffCounter = getDischargeScreenOffCoulombCounter();
- final long dischargeScreenOffCount = dischargeScreenOffCounter.getCountLocked(which);
+ final long dischargeScreenOffCount = getMahDischargeScreenOff(which);
if (dischargeScreenOffCount >= 0) {
sb.setLength(0);
sb.append(prefix);
@@ -3932,7 +3980,18 @@
pw.println(sb.toString());
}
- final long dischargeScreenOnCount = dischargeCount - dischargeScreenOffCount;
+ final long dischargeScreenDozeCount = getMahDischargeScreenDoze(which);
+ if (dischargeScreenDozeCount >= 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Screen doze discharge: ");
+ sb.append(BatteryStatsHelper.makemAh(dischargeScreenDozeCount / 1000.0));
+ sb.append(" mAh");
+ pw.println(sb.toString());
+ }
+
+ final long dischargeScreenOnCount =
+ dischargeCount - dischargeScreenOffCount - dischargeScreenDozeCount;
if (dischargeScreenOnCount >= 0) {
sb.setLength(0);
sb.append(prefix);
@@ -4340,20 +4399,24 @@
pw.println(getDischargeCurrentLevel());
}
pw.print(prefix); pw.print(" Amount discharged while screen on: ");
- pw.println(getDischargeAmountScreenOn());
+ pw.println(getDischargeAmountScreenOn());
pw.print(prefix); pw.print(" Amount discharged while screen off: ");
- pw.println(getDischargeAmountScreenOff());
+ pw.println(getDischargeAmountScreenOff());
+ pw.print(prefix); pw.print(" Amount discharged while screen doze: ");
+ pw.println(getDischargeAmountScreenDoze());
pw.println(" ");
} else {
pw.print(prefix); pw.println(" Device battery use since last full charge");
pw.print(prefix); pw.print(" Amount discharged (lower bound): ");
- pw.println(getLowDischargeAmountSinceCharge());
+ pw.println(getLowDischargeAmountSinceCharge());
pw.print(prefix); pw.print(" Amount discharged (upper bound): ");
- pw.println(getHighDischargeAmountSinceCharge());
+ pw.println(getHighDischargeAmountSinceCharge());
pw.print(prefix); pw.print(" Amount discharged while screen on: ");
- pw.println(getDischargeAmountScreenOnSinceCharge());
+ pw.println(getDischargeAmountScreenOnSinceCharge());
pw.print(prefix); pw.print(" Amount discharged while screen off: ");
- pw.println(getDischargeAmountScreenOffSinceCharge());
+ pw.println(getDischargeAmountScreenOffSinceCharge());
+ pw.print(prefix); pw.print(" Amount discharged while screen doze: ");
+ pw.println(getDischargeAmountScreenDozeSinceCharge());
pw.println();
}
@@ -5426,7 +5489,7 @@
}
}
}
-
+
public void prepareForDumpLocked() {
}
@@ -6248,7 +6311,7 @@
pw.println();
}
}
-
+
@SuppressWarnings("unused")
public void dumpCheckinLocked(Context context, PrintWriter pw,
List<ApplicationInfo> apps, int flags, long histStart) {
diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl
index cc2af21..8271701 100644
--- a/core/java/android/os/IDeviceIdleController.aidl
+++ b/core/java/android/os/IDeviceIdleController.aidl
@@ -23,6 +23,11 @@
interface IDeviceIdleController {
void addPowerSaveWhitelistApp(String name);
void removePowerSaveWhitelistApp(String name);
+ /* Removes an app from the system whitelist. Calling restoreSystemPowerWhitelistApp will add
+ the app back into the system whitelist */
+ void removeSystemPowerWhitelistApp(String name);
+ void restoreSystemPowerWhitelistApp(String name);
+ String[] getRemovedSystemPowerWhitelistApps();
String[] getSystemPowerWhitelistExceptIdle();
String[] getSystemPowerWhitelist();
String[] getUserPowerWhitelist();
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index 17f00c2..9369eeb 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -154,11 +154,21 @@
public abstract boolean isUserUnlocked(int userId);
/**
- * Return whether the given user is running
+ * Returns whether the given user is running
*/
public abstract boolean isUserRunning(int userId);
/**
+ * Returns whether the given user is initialized
+ */
+ public abstract boolean isUserInitialized(int userId);
+
+ /**
+ * Returns whether the given user exists
+ */
+ public abstract boolean exists(int userId);
+
+ /**
* Set user's running state
*/
public abstract void setUserState(int userId, int userState);
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 1521e7e..2e59f6c 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -187,7 +187,7 @@
* protect a dataset that contains sensitive information by requiring dataset authentication
* (see {@link Dataset.Builder#setAuthentication(android.content.IntentSender)}), and to include
* info about the "primary" field of the partition in the custom presentation for "secondary"
- * fields — that would prevent a malicious app from getting the "primary" fields without the
+ * fields—that would prevent a malicious app from getting the "primary" fields without the
* user realizing they're being released (for example, a malicious app could have fields for a
* credit card number, verification code, and expiration date crafted in a way that just the latter
* is visible; by explicitly indicating the expiration date is related to a given credit card
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index 2a9a39f..ef9598a 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -29,32 +29,77 @@
import com.android.internal.util.Preconditions;
+import java.io.Serializable;
import java.util.ArrayList;
+import java.util.regex.Pattern;
/**
- * A dataset object represents a group of key/value pairs used to autofill parts of a screen.
+ * A dataset object represents a group of fields (key / value pairs) used to autofill parts of a
+ * screen.
*
- * <p>In its simplest form, a dataset contains one or more key / value pairs (comprised of
- * {@link AutofillId} and {@link AutofillValue} respectively); and one or more
- * {@link RemoteViews presentation} for these pairs (a pair could have its own
- * {@link RemoteViews presentation}, or use the default {@link RemoteViews presentation} associated
- * with the whole dataset). When an autofill service returns datasets in a {@link FillResponse}
+ * <a name="BasicUsage"></a>
+ * <h3>Basic usage</h3>
+ *
+ * <p>In its simplest form, a dataset contains one or more fields (comprised of
+ * an {@link AutofillId id}, a {@link AutofillValue value}, and an optional filter
+ * {@link Pattern regex}); and one or more {@link RemoteViews presentations} for these fields
+ * (each field could have its own {@link RemoteViews presentation}, or use the default
+ * {@link RemoteViews presentation} associated with the whole dataset).
+ *
+ * <p>When an autofill service returns datasets in a {@link FillResponse}
* and the screen input is focused in a view that is present in at least one of these datasets,
- * the Android System displays a UI affordance containing the {@link RemoteViews presentation} of
+ * the Android System displays a UI containing the {@link RemoteViews presentation} of
* all datasets pairs that have that view's {@link AutofillId}. Then, when the user selects a
- * dataset from the affordance, all views in that dataset are autofilled.
+ * dataset from the UI, all views in that dataset are autofilled.
*
- * <p>In a more sophisticated form, the dataset value can be protected until the user authenticates
- * the dataset - see {@link Dataset.Builder#setAuthentication(IntentSender)}.
+ * <a name="Authentication"></a>
+ * <h3>Dataset authentication</h3>
*
- * @see android.service.autofill.AutofillService for more information and examples about the
- * role of datasets in the autofill workflow.
+ * <p>In a more sophisticated form, the dataset values can be protected until the user authenticates
+ * the dataset—in that case, when a dataset is selected by the user, the Android System
+ * launches an intent set by the service to "unlock" the dataset.
+ *
+ * <p>For example, when a data set contains credit card information (such as number,
+ * expiration date, and verification code), you could provide a dataset presentation saying
+ * "Tap to authenticate". Then when the user taps that option, you would launch an activity asking
+ * the user to enter the credit card code, and if the user enters a valid code, you could then
+ * "unlock" the dataset.
+ *
+ * <p>You can also use authenticated datasets to offer an interactive UI for the user. For example,
+ * if the activity being autofilled is an account creation screen, you could use an authenticated
+ * dataset to automatically generate a random password for the user.
+ *
+ * <p>See {@link Dataset.Builder#setAuthentication(IntentSender)} for more details about the dataset
+ * authentication mechanism.
+ *
+ * <a name="Filtering"></a>
+ * <h3>Filtering</h3>
+ * <p>The autofill UI automatically changes which values are shown based on value of the view
+ * anchoring it, following the rules below:
+ * <ol>
+ * <li>If the view's {@link android.view.View#getAutofillValue() autofill value} is not
+ * {@link AutofillValue#isText() text} or is empty, all datasets are shown.
+ * <li>Datasets that have a filter regex (set through
+ * {@link Dataset.Builder#setValue(AutofillId, AutofillValue, Pattern)} or
+ * {@link Dataset.Builder#setValue(AutofillId, AutofillValue, Pattern, RemoteViews)}) and whose
+ * regex matches the view's text value converted to lower case are shown.
+ * <li>Datasets that do not require authentication, have a field value that is
+ * {@link AutofillValue#isText() text} and whose {@link AutofillValue#getTextValue() value} starts
+ * with the lower case value of the view's text are shown.
+ * <li>All other datasets are hidden.
+ * </ol>
+ *
+ * <a name="MoreInfo"></a>
+ * <h3>More information</h3>
+ * <p>See {@link android.service.autofill.AutofillService} for more information and examples about
+ * the role of datasets in the autofill workflow.
*/
public final class Dataset implements Parcelable {
private final ArrayList<AutofillId> mFieldIds;
private final ArrayList<AutofillValue> mFieldValues;
private final ArrayList<RemoteViews> mFieldPresentations;
+ private final ArrayList<Pattern> mFieldFilters;
private final RemoteViews mPresentation;
private final IntentSender mAuthentication;
@Nullable String mId;
@@ -63,6 +108,7 @@
mFieldIds = builder.mFieldIds;
mFieldValues = builder.mFieldValues;
mFieldPresentations = builder.mFieldPresentations;
+ mFieldFilters = builder.mFieldFilters;
mPresentation = builder.mPresentation;
mAuthentication = builder.mAuthentication;
mId = builder.mId;
@@ -85,6 +131,12 @@
}
/** @hide */
+ @Nullable
+ public Pattern getFilter(int index) {
+ return mFieldFilters.get(index);
+ }
+
+ /** @hide */
public @Nullable IntentSender getAuthentication() {
return mAuthentication;
}
@@ -103,6 +155,8 @@
.append(", fieldValues=").append(mFieldValues)
.append(", fieldPresentations=")
.append(mFieldPresentations == null ? 0 : mFieldPresentations.size())
+ .append(", fieldFilters=")
+ .append(mFieldFilters == null ? 0 : mFieldFilters.size())
.append(", hasPresentation=").append(mPresentation != null)
.append(", hasAuthentication=").append(mAuthentication != null)
.append(']').toString();
@@ -127,6 +181,7 @@
private ArrayList<AutofillId> mFieldIds;
private ArrayList<AutofillValue> mFieldValues;
private ArrayList<RemoteViews> mFieldPresentations;
+ private ArrayList<Pattern> mFieldFilters;
private RemoteViews mPresentation;
private IntentSender mAuthentication;
private boolean mDestroyed;
@@ -182,12 +237,12 @@
* credit card information without the CVV for the data set in the {@link FillResponse
* response} then the returned data set should contain the CVV entry.
*
- * <p><b>NOTE:</b> Do not make the provided pending intent
+ * <p><b>Note:</b> Do not make the provided pending intent
* immutable by using {@link android.app.PendingIntent#FLAG_IMMUTABLE} as the
* platform needs to fill in the authentication arguments.
*
* @param authentication Intent to an activity with your authentication flow.
- * @return This builder.
+ * @return this builder.
*
* @see android.app.PendingIntent
*/
@@ -214,11 +269,10 @@
*
* @param id id for this dataset or {@code null} to unset.
*
- * @return This builder.
+ * @return this builder.
*/
public @NonNull Builder setId(@Nullable String id) {
throwIfDestroyed();
-
mId = id;
return this;
}
@@ -230,17 +284,16 @@
* android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
* @param value value to be autofilled. Pass {@code null} if you do not have the value
* but the target view is a logical part of the dataset. For example, if
- * the dataset needs an authentication and you have no access to the value.
- * @return This builder.
+ * the dataset needs authentication and you have no access to the value.
+ * @return this builder.
* @throws IllegalStateException if the builder was constructed without a
* {@link RemoteViews presentation}.
*/
public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value) {
throwIfDestroyed();
- if (mPresentation == null) {
- throw new IllegalStateException("Dataset presentation not set on constructor");
- }
- setValueAndPresentation(id, value, null);
+ Preconditions.checkState(mPresentation != null,
+ "Dataset presentation not set on constructor");
+ setLifeTheUniverseAndEverything(id, value, null, null);
return this;
}
@@ -250,23 +303,81 @@
*
* @param id id returned by {@link
* android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
- * @param value value to be auto filled. Pass {@code null} if you do not have the value
+ * @param value the value to be autofilled. Pass {@code null} if you do not have the value
* but the target view is a logical part of the dataset. For example, if
- * the dataset needs an authentication and you have no access to the value.
- * Filtering matches any user typed string to {@code null} values.
- * @param presentation The presentation used to visualize this field.
- * @return This builder.
+ * the dataset needs authentication and you have no access to the value.
+ * @param presentation the presentation used to visualize this field.
+ * @return this builder.
+ *
*/
public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value,
@NonNull RemoteViews presentation) {
throwIfDestroyed();
Preconditions.checkNotNull(presentation, "presentation cannot be null");
- setValueAndPresentation(id, value, presentation);
+ setLifeTheUniverseAndEverything(id, value, presentation, null);
return this;
}
- private void setValueAndPresentation(AutofillId id, AutofillValue value,
- RemoteViews presentation) {
+ /**
+ * Sets the value of a field using an <a href="#Filtering">explicit filter</a>.
+ *
+ * <p>This method is typically used when the dataset is not authenticated and the field
+ * value is not {@link AutofillValue#isText() text} but the service still wants to allow
+ * the user to filter it out.
+ *
+ * @param id id returned by {@link
+ * android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
+ * @param value the value to be autofilled. Pass {@code null} if you do not have the value
+ * but the target view is a logical part of the dataset. For example, if
+ * the dataset needs authentication and you have no access to the value.
+ * @param filter regex used to determine if the dataset should be shown in the autofill UI.
+ *
+ * @return this builder.
+ * @throws IllegalStateException if the builder was constructed without a
+ * {@link RemoteViews presentation}.
+ */
+ public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value,
+ @NonNull Pattern filter) {
+ throwIfDestroyed();
+ Preconditions.checkNotNull(filter, "filter cannot be null");
+ Preconditions.checkState(mPresentation != null,
+ "Dataset presentation not set on constructor");
+ setLifeTheUniverseAndEverything(id, value, null, filter);
+ return this;
+ }
+
+ /**
+ * Sets the value of a field, using a custom {@link RemoteViews presentation} to
+ * visualize it and a <a href="#Filtering">explicit filter</a>.
+ *
+ * <p>Typically used to allow filtering on
+ * {@link Dataset.Builder#setAuthentication(IntentSender) authenticated datasets}. For
+ * example, if the dataset represents a credit card number and the service does not want to
+ * show the "Tap to authenticate" message until the user tapped 4 digits, in which case
+ * the filter would be {@code Pattern.compile("\\d.{4,}")}.
+ *
+ * @param id id returned by {@link
+ * android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
+ * @param value the value to be autofilled. Pass {@code null} if you do not have the value
+ * but the target view is a logical part of the dataset. For example, if
+ * the dataset needs authentication and you have no access to the value.
+ * @param presentation the presentation used to visualize this field.
+ * @param filter regex used to determine if the dataset should be shown in the autofill UI.
+ *
+ * @return this builder.
+ */
+ public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value,
+ @NonNull Pattern filter, @NonNull RemoteViews presentation) {
+ throwIfDestroyed();
+ Preconditions.checkNotNull(filter, "filter cannot be null");
+ Preconditions.checkNotNull(presentation, "presentation cannot be null");
+ setLifeTheUniverseAndEverything(id, value, presentation, filter);
+ return this;
+ }
+
+ private void setLifeTheUniverseAndEverything(@NonNull AutofillId id,
+ @Nullable AutofillValue value, @Nullable RemoteViews presentation,
+ @Nullable Pattern filter) {
Preconditions.checkNotNull(id, "id cannot be null");
if (mFieldIds != null) {
final int existingIdx = mFieldIds.indexOf(id);
@@ -279,10 +390,12 @@
mFieldIds = new ArrayList<>();
mFieldValues = new ArrayList<>();
mFieldPresentations = new ArrayList<>();
+ mFieldFilters = new ArrayList<>();
}
mFieldIds.add(id);
mFieldValues.add(value);
mFieldPresentations.add(presentation);
+ mFieldFilters.add(filter);
}
/**
@@ -290,8 +403,9 @@
*
* <p>You should not interact with this builder once this method is called.
*
- * <p>It is required that you specify at least one field before calling this method. It's
- * also mandatory to provide a presentation view to visualize the data set in the UI.
+ * @throws IllegalStateException if no field was set (through
+ * {@link #setValue(AutofillId, AutofillValue)} or
+ * {@link #setValue(AutofillId, AutofillValue, RemoteViews)}).
*
* @return The built dataset.
*/
@@ -299,7 +413,7 @@
throwIfDestroyed();
mDestroyed = true;
if (mFieldIds == null) {
- throw new IllegalArgumentException("at least one value must be set");
+ throw new IllegalStateException("at least one value must be set");
}
return new Dataset(this);
}
@@ -326,6 +440,7 @@
parcel.writeTypedList(mFieldIds, flags);
parcel.writeTypedList(mFieldValues, flags);
parcel.writeParcelableList(mFieldPresentations, flags);
+ parcel.writeSerializable(mFieldFilters);
parcel.writeParcelable(mAuthentication, flags);
parcel.writeString(mId);
}
@@ -345,6 +460,9 @@
parcel.createTypedArrayList(AutofillValue.CREATOR);
final ArrayList<RemoteViews> presentations = new ArrayList<>();
parcel.readParcelableList(presentations, null);
+ @SuppressWarnings("unchecked")
+ final ArrayList<Serializable> filters =
+ (ArrayList<Serializable>) parcel.readSerializable();
final int idCount = (ids != null) ? ids.size() : 0;
final int valueCount = (values != null) ? values.size() : 0;
for (int i = 0; i < idCount; i++) {
@@ -352,7 +470,8 @@
final AutofillValue value = (valueCount > i) ? values.get(i) : null;
final RemoteViews fieldPresentation = presentations.isEmpty() ? null
: presentations.get(i);
- builder.setValueAndPresentation(id, value, fieldPresentation);
+ final Pattern filter = (Pattern) filters.get(i);
+ builder.setLifeTheUniverseAndEverything(id, value, fieldPresentation, filter);
}
builder.setAuthentication(parcel.readParcelable(null));
builder.setId(parcel.readString());
diff --git a/core/java/android/service/autofill/ImageTransformation.java b/core/java/android/service/autofill/ImageTransformation.java
index 2151f74..4afda24 100644
--- a/core/java/android/service/autofill/ImageTransformation.java
+++ b/core/java/android/service/autofill/ImageTransformation.java
@@ -20,11 +20,12 @@
import android.annotation.DrawableRes;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import android.util.Log;
-import android.util.Pair;
import android.view.autofill.AutofillId;
import android.widget.ImageView;
import android.widget.RemoteViews;
@@ -43,9 +44,9 @@
*
* <pre class="prettyprint">
* new ImageTransformation.Builder(ccNumberId, Pattern.compile("^4815.*$"),
- * R.drawable.ic_credit_card_logo1)
- * .addOption(Pattern.compile("^1623.*$"), R.drawable.ic_credit_card_logo2)
- * .addOption(Pattern.compile("^42.*$"), R.drawable.ic_credit_card_logo3)
+ * R.drawable.ic_credit_card_logo1, "Brand 1")
+ * .addOption(Pattern.compile("^1623.*$"), R.drawable.ic_credit_card_logo2, "Brand 2")
+ * .addOption(Pattern.compile("^42.*$"), R.drawable.ic_credit_card_logo3, "Brand 3")
* .build();
* </pre>
*
@@ -59,7 +60,7 @@
private static final String TAG = "ImageTransformation";
private final AutofillId mId;
- private final ArrayList<Pair<Pattern, Integer>> mOptions;
+ private final ArrayList<Option> mOptions;
private ImageTransformation(Builder builder) {
mId = builder.mId;
@@ -82,17 +83,21 @@
}
for (int i = 0; i < size; i++) {
- final Pair<Pattern, Integer> option = mOptions.get(i);
+ final Option option = mOptions.get(i);
try {
- if (option.first.matcher(value).matches()) {
+ if (option.pattern.matcher(value).matches()) {
Log.d(TAG, "Found match at " + i + ": " + option);
- parentTemplate.setImageViewResource(childViewId, option.second);
+ parentTemplate.setImageViewResource(childViewId, option.resId);
+ if (option.contentDescription != null) {
+ parentTemplate.setContentDescription(childViewId,
+ option.contentDescription);
+ }
return;
}
} catch (Exception e) {
// Do not log full exception to avoid PII leaking
- Log.w(TAG, "Error matching regex #" + i + "(" + option.first.pattern() + ") on id "
- + option.second + ": " + e.getClass());
+ Log.w(TAG, "Error matching regex #" + i + "(" + option.pattern + ") on id "
+ + option.resId + ": " + e.getClass());
throw e;
}
@@ -105,25 +110,44 @@
*/
public static class Builder {
private final AutofillId mId;
- private final ArrayList<Pair<Pattern, Integer>> mOptions = new ArrayList<>();
+ private final ArrayList<Option> mOptions = new ArrayList<>();
private boolean mDestroyed;
/**
- * Create a new builder for a autofill id and add a first option.
+ * Creates a new builder for a autofill id and add a first option.
*
* @param id id of the screen field that will be used to evaluate whether the image should
* be used.
* @param regex regular expression defining what should be matched to use this image.
* @param resId resource id of the image (in the autofill service's package). The
* {@link RemoteViews presentation} must contain a {@link ImageView} child with that id.
+ *
+ * @deprecated use
+ * {@link #ImageTransformation.Builder(AutofillId, Pattern, int, CharSequence)} instead.
*/
+ @Deprecated
public Builder(@NonNull AutofillId id, @NonNull Pattern regex, @DrawableRes int resId) {
mId = Preconditions.checkNotNull(id);
-
addOption(regex, resId);
}
/**
+ * Creates a new builder for a autofill id and add a first option.
+ *
+ * @param id id of the screen field that will be used to evaluate whether the image should
+ * be used.
+ * @param regex regular expression defining what should be matched to use this image.
+ * @param resId resource id of the image (in the autofill service's package). The
+ * {@link RemoteViews presentation} must contain a {@link ImageView} child with that id.
+ * @param contentDescription content description to be applied in the child view.
+ */
+ public Builder(@NonNull AutofillId id, @NonNull Pattern regex, @DrawableRes int resId,
+ @NonNull CharSequence contentDescription) {
+ mId = Preconditions.checkNotNull(id);
+ addOption(regex, resId, contentDescription);
+ }
+
+ /**
* Adds an option to replace the child view with a different image when the regex matches.
*
* @param regex regular expression defining what should be matched to use this image.
@@ -131,17 +155,43 @@
* {@link RemoteViews presentation} must contain a {@link ImageView} child with that id.
*
* @return this build
+ *
+ * @deprecated use {@link #addOption(Pattern, int, CharSequence)} instead.
*/
+ @Deprecated
public Builder addOption(@NonNull Pattern regex, @DrawableRes int resId) {
+ addOptionInternal(regex, resId, null);
+ return this;
+ }
+
+ /**
+ * Adds an option to replace the child view with a different image and content description
+ * when the regex matches.
+ *
+ * @param regex regular expression defining what should be matched to use this image.
+ * @param resId resource id of the image (in the autofill service's package). The
+ * {@link RemoteViews presentation} must contain a {@link ImageView} child with that id.
+ * @param contentDescription content description to be applied in the child view.
+ *
+ * @return this build
+ */
+ public Builder addOption(@NonNull Pattern regex, @DrawableRes int resId,
+ @NonNull CharSequence contentDescription) {
+ addOptionInternal(regex, resId, Preconditions.checkNotNull(contentDescription));
+ return this;
+ }
+
+ private void addOptionInternal(@NonNull Pattern regex, @DrawableRes int resId,
+ @Nullable CharSequence contentDescription) {
throwIfDestroyed();
Preconditions.checkNotNull(regex);
Preconditions.checkArgument(resId != 0);
- mOptions.add(new Pair<>(regex, resId));
- return this;
+ mOptions.add(new Option(regex, resId, contentDescription));
}
+
/**
* Creates a new {@link ImageTransformation} instance.
*/
@@ -178,15 +228,18 @@
parcel.writeParcelable(mId, flags);
final int size = mOptions.size();
- final Pattern[] regexs = new Pattern[size];
+ final Pattern[] patterns = new Pattern[size];
final int[] resIds = new int[size];
+ final CharSequence[] contentDescriptions = new String[size];
for (int i = 0; i < size; i++) {
- Pair<Pattern, Integer> regex = mOptions.get(i);
- regexs[i] = regex.first;
- resIds[i] = regex.second;
+ final Option option = mOptions.get(i);
+ patterns[i] = option.pattern;
+ resIds[i] = option.resId;
+ contentDescriptions[i] = option.contentDescription;
}
- parcel.writeSerializable(regexs);
+ parcel.writeSerializable(patterns);
parcel.writeIntArray(resIds);
+ parcel.writeCharSequenceArray(contentDescriptions);
}
public static final Parcelable.Creator<ImageTransformation> CREATOR =
@@ -197,15 +250,22 @@
final Pattern[] regexs = (Pattern[]) parcel.readSerializable();
final int[] resIds = parcel.createIntArray();
+ final CharSequence[] contentDescriptions = parcel.readCharSequenceArray();
// Always go through the builder to ensure the data ingested by the system obeys the
// contract of the builder to avoid attacks using specially crafted parcels.
- final ImageTransformation.Builder builder = new ImageTransformation.Builder(id,
- regexs[0], resIds[0]);
+ final CharSequence contentDescription = contentDescriptions[0];
+ final ImageTransformation.Builder builder = (contentDescription != null)
+ ? new ImageTransformation.Builder(id, regexs[0], resIds[0], contentDescription)
+ : new ImageTransformation.Builder(id, regexs[0], resIds[0]);
final int size = regexs.length;
for (int i = 1; i < size; i++) {
- builder.addOption(regexs[i], resIds[i]);
+ if (contentDescriptions[i] != null) {
+ builder.addOption(regexs[i], resIds[i], contentDescriptions[i]);
+ } else {
+ builder.addOption(regexs[i], resIds[i]);
+ }
}
return builder.build();
@@ -216,4 +276,16 @@
return new ImageTransformation[size];
}
};
+
+ private static final class Option {
+ public final Pattern pattern;
+ public final int resId;
+ public final CharSequence contentDescription;
+
+ Option(Pattern pattern, int resId, CharSequence contentDescription) {
+ this.pattern = pattern;
+ this.resId = resId;
+ this.contentDescription = TextUtils.trimNoCopySpans(contentDescription);
+ }
+ }
}
diff --git a/core/java/android/service/autofill/InternalSanitizer.java b/core/java/android/service/autofill/InternalSanitizer.java
new file mode 100644
index 0000000..95d2f66
--- /dev/null
+++ b/core/java/android/service/autofill/InternalSanitizer.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 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.service.autofill;
+
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+import android.os.Parcelable;
+import android.view.autofill.AutofillValue;
+
+/**
+ * Superclass of all sanitizers the system understands. As this is not public all public subclasses
+ * have to implement {@link Sanitizer} again.
+ *
+ * @hide
+ */
+@TestApi
+public abstract class InternalSanitizer implements Sanitizer, Parcelable {
+
+ /**
+ * Sanitizes an {@link AutofillValue}.
+ *
+ * @hide
+ */
+ public abstract AutofillValue sanitize(@NonNull AutofillValue value);
+}
diff --git a/core/java/android/service/autofill/Sanitizer.java b/core/java/android/service/autofill/Sanitizer.java
new file mode 100644
index 0000000..38757ac
--- /dev/null
+++ b/core/java/android/service/autofill/Sanitizer.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 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.service.autofill;
+
+/**
+ * Helper class used to sanitize user input before using it in a save request.
+ *
+ * <p>Typically used to avoid displaying the save UI for values that are autofilled but reformatted
+ * by the app—for example, if the autofill service sends a credit card number
+ * value as "004815162342108" and the app automatically changes it to "0048 1516 2342 108".
+ */
+public interface Sanitizer {
+}
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index e0a0730..1b9240c 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -25,6 +25,8 @@
import android.content.IntentSender;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.DebugUtils;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
@@ -232,6 +234,8 @@
private final int mFlags;
private final CustomDescription mCustomDescription;
private final InternalValidator mValidator;
+ private final InternalSanitizer[] mSanitizerKeys;
+ private final AutofillId[][] mSanitizerValues;
private SaveInfo(Builder builder) {
mType = builder.mType;
@@ -243,6 +247,18 @@
mFlags = builder.mFlags;
mCustomDescription = builder.mCustomDescription;
mValidator = builder.mValidator;
+ if (builder.mSanitizers == null) {
+ mSanitizerKeys = null;
+ mSanitizerValues = null;
+ } else {
+ final int size = builder.mSanitizers.size();
+ mSanitizerKeys = new InternalSanitizer[size];
+ mSanitizerValues = new AutofillId[size][];
+ for (int i = 0; i < size; i++) {
+ mSanitizerKeys[i] = builder.mSanitizers.keyAt(i);
+ mSanitizerValues[i] = builder.mSanitizers.valueAt(i);
+ }
+ }
}
/** @hide */
@@ -292,6 +308,18 @@
return mValidator;
}
+ /** @hide */
+ @Nullable
+ public InternalSanitizer[] getSanitizerKeys() {
+ return mSanitizerKeys;
+ }
+
+ /** @hide */
+ @Nullable
+ public AutofillId[][] getSanitizerValues() {
+ return mSanitizerValues;
+ }
+
/**
* A builder for {@link SaveInfo} objects.
*/
@@ -307,6 +335,9 @@
private int mFlags;
private CustomDescription mCustomDescription;
private InternalValidator mValidator;
+ private ArrayMap<InternalSanitizer, AutofillId[]> mSanitizers;
+ // Set used to validate against duplicate ids.
+ private ArraySet<AutofillId> mSanitizerIds;
/**
* Creates a new builder.
@@ -530,6 +561,61 @@
}
/**
+ * Adds a sanitizer for one or more field.
+ *
+ * <p>When a sanitizer is set for a field, the {@link AutofillValue} is sent to the
+ * sanitizer before a save request is <a href="#TriggeringSaveRequest">triggered</a>.
+ *
+ * <p>Typically used to avoid displaying the save UI for values that are autofilled but
+ * reformattedby the app. For example, to remove spaces between every 4 digits of a
+ * credit card number:
+ *
+ * <pre class="prettyprint">
+ * builder.addSanitizer(
+ * new TextValueSanitizer(Pattern.compile("^(\\d{4}\s?\\d{4}\s?\\d{4}\s?\\d{4})$"),
+ * "$1$2$3$4"), ccNumberId);
+ * </pre>
+ *
+ * <p>The same sanitizer can be reused to sanitize multiple fields. For example, to trim
+ * both the username and password fields:
+ *
+ * <pre class="prettyprint">
+ * builder.addSanitizer(
+ * new TextValueSanitizer(Pattern.compile("^\\s*(.*)\\s*$"), "$1"),
+ * usernameId, passwordId);
+ * </pre>
+ *
+ * @param sanitizer an implementation provided by the Android System.
+ * @param ids id of fields whose value will be sanitized.
+ * @return this builder.
+ *
+ * @throws IllegalArgumentException if a sanitizer for any of the {@code ids} has already
+ * been added or if {@code ids} is empty.
+ */
+ public @NonNull Builder addSanitizer(@NonNull Sanitizer sanitizer,
+ @NonNull AutofillId... ids) {
+ throwIfDestroyed();
+ Preconditions.checkArgument(!ArrayUtils.isEmpty(ids), "ids cannot be empty or null");
+ Preconditions.checkArgument((sanitizer instanceof InternalSanitizer),
+ "not provided by Android System: " + sanitizer);
+
+ if (mSanitizers == null) {
+ mSanitizers = new ArrayMap<>();
+ mSanitizerIds = new ArraySet<>(ids.length);
+ }
+
+ // Check for duplicates first.
+ for (AutofillId id : ids) {
+ Preconditions.checkArgument(!mSanitizerIds.contains(id), "already added %s", id);
+ mSanitizerIds.add(id);
+ }
+
+ mSanitizers.put((InternalSanitizer) sanitizer, ids);
+
+ return this;
+ }
+
+ /**
* Builds a new {@link SaveInfo} instance.
*
* @throws IllegalStateException if no
@@ -569,6 +655,10 @@
.append(", mFlags=").append(mFlags)
.append(", mCustomDescription=").append(mCustomDescription)
.append(", validation=").append(mValidator)
+ .append(", sanitizerKeys=")
+ .append(mSanitizerKeys == null ? "N/A:" : mSanitizerKeys.length)
+ .append(", sanitizerValues=")
+ .append(mSanitizerValues == null ? "N/A:" : mSanitizerValues.length)
.append("]").toString();
}
@@ -591,6 +681,12 @@
parcel.writeCharSequence(mDescription);
parcel.writeParcelable(mCustomDescription, flags);
parcel.writeParcelable(mValidator, flags);
+ parcel.writeParcelableArray(mSanitizerKeys, flags);
+ if (mSanitizerKeys != null) {
+ for (int i = 0; i < mSanitizerValues.length; i++) {
+ parcel.writeParcelableArray(mSanitizerValues[i], flags);
+ }
+ }
parcel.writeInt(mFlags);
}
@@ -621,6 +717,16 @@
if (validator != null) {
builder.setValidator(validator);
}
+ final InternalSanitizer[] sanitizers =
+ parcel.readParcelableArray(null, InternalSanitizer.class);
+ if (sanitizers != null) {
+ final int size = sanitizers.length;
+ for (int i = 0; i < size; i++) {
+ final AutofillId[] autofillIds =
+ parcel.readParcelableArray(null, AutofillId.class);
+ builder.addSanitizer(sanitizers[i], autofillIds);
+ }
+ }
builder.setFlags(parcel.readInt());
return builder.build();
}
diff --git a/core/java/android/service/autofill/TextValueSanitizer.java b/core/java/android/service/autofill/TextValueSanitizer.java
new file mode 100644
index 0000000..12e85b1
--- /dev/null
+++ b/core/java/android/service/autofill/TextValueSanitizer.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2017 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.service.autofill;
+
+import static android.view.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Slog;
+import android.view.autofill.AutofillValue;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Sanitizes a text {@link AutofillValue} using a regular expression (regex) substitution.
+ *
+ * <p>For example, to remove spaces from groups of 4-digits in a credit card:
+ *
+ * <pre class="prettyprint">
+ * new TextValueSanitizer(Pattern.compile("^(\\d{4}\s?\\d{4}\s?\\d{4}\s?\\d{4})$"), "$1$2$3$4")
+ * </pre>
+ */
+public final class TextValueSanitizer extends InternalSanitizer implements
+ Sanitizer, Parcelable {
+ private static final String TAG = "TextValueSanitizer";
+
+ private final Pattern mRegex;
+ private final String mSubst;
+
+ /**
+ * Default constructor.
+ *
+ * @param regex regular expression with groups (delimited by {@code (} and {@code (}) that
+ * are used to substitute parts of the {@link AutofillValue#getTextValue() text value}.
+ * @param subst the string that substitutes the matched regex, using {@code $} for
+ * group substitution ({@code $1} for 1st group match, {@code $2} for 2nd, etc).
+ */
+ public TextValueSanitizer(@NonNull Pattern regex, @NonNull String subst) {
+ mRegex = Preconditions.checkNotNull(regex);
+ mSubst = Preconditions.checkNotNull(subst);
+ }
+
+ /** @hide */
+ @Override
+ @TestApi
+ public AutofillValue sanitize(@NonNull AutofillValue value) {
+ if (value == null) {
+ Slog.w(TAG, "sanitize() called with null value");
+ return null;
+ }
+ if (!value.isText()) return value;
+
+ final CharSequence text = value.getTextValue();
+
+ try {
+ final Matcher matcher = mRegex.matcher(text);
+ if (!matcher.matches()) return value;
+
+ final CharSequence sanitized = matcher.replaceAll(mSubst);
+ return AutofillValue.forText(sanitized);
+ } catch (Exception e) {
+ Slog.w(TAG, "Exception evaluating " + mRegex + "/" + mSubst + ": " + e);
+ return value;
+ }
+ }
+
+ /////////////////////////////////////
+ // Object "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public String toString() {
+ if (!sDebug) return super.toString();
+
+ return "TextValueSanitizer: [regex=" + mRegex + ", subst=" + mSubst + "]";
+ }
+
+ /////////////////////////////////////
+ // Parcelable "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeSerializable(mRegex);
+ parcel.writeString(mSubst);
+ }
+
+ public static final Parcelable.Creator<TextValueSanitizer> CREATOR =
+ new Parcelable.Creator<TextValueSanitizer>() {
+ @Override
+ public TextValueSanitizer createFromParcel(Parcel parcel) {
+ return new TextValueSanitizer((Pattern) parcel.readSerializable(), parcel.readString());
+ }
+
+ @Override
+ public TextValueSanitizer[] newArray(int size) {
+ return new TextValueSanitizer[size];
+ }
+ };
+}
diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl
index c38fab1..fef9223 100644
--- a/core/java/android/service/vr/IVrManager.aidl
+++ b/core/java/android/service/vr/IVrManager.aidl
@@ -93,5 +93,13 @@
* currently, else return the display id of the virtual display
*/
int getVr2dDisplayId();
+
+ /**
+ * Set the component name of the compositor service to bind.
+ *
+ * @param componentName flattened string representing a ComponentName of a Service in the
+ * application's compositor process to bind to, or null to clear the current binding.
+ */
+ void setAndBindCompositor(in String componentName);
}
diff --git a/core/java/android/slice/Slice.java b/core/java/android/slice/Slice.java
new file mode 100644
index 0000000..bb810e6
--- /dev/null
+++ b/core/java/android/slice/Slice.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2017 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.slice;
+
+import static android.slice.SliceItem.TYPE_ACTION;
+import static android.slice.SliceItem.TYPE_COLOR;
+import static android.slice.SliceItem.TYPE_IMAGE;
+import static android.slice.SliceItem.TYPE_REMOTE_INPUT;
+import static android.slice.SliceItem.TYPE_REMOTE_VIEW;
+import static android.slice.SliceItem.TYPE_SLICE;
+import static android.slice.SliceItem.TYPE_TEXT;
+import static android.slice.SliceItem.TYPE_TIMESTAMP;
+
+import android.annotation.NonNull;
+import android.annotation.StringDef;
+import android.app.PendingIntent;
+import android.app.RemoteInput;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.widget.RemoteViews;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * A slice is a piece of app content and actions that can be surfaced outside of the app.
+ *
+ * <p>They are constructed using {@link Builder} in a tree structure
+ * that provides the OS some information about how the content should be displayed.
+ * @hide
+ */
+public final class Slice implements Parcelable {
+
+ /**
+ * @hide
+ */
+ @StringDef({HINT_TITLE, HINT_LIST, HINT_LIST_ITEM, HINT_LARGE, HINT_ACTIONS, HINT_SELECTED,
+ HINT_SOURCE, HINT_MESSAGE, HINT_HORIZONTAL, HINT_NO_TINT})
+ public @interface SliceHint{ }
+
+ /**
+ * Hint that this content is a title of other content in the slice.
+ */
+ public static final String HINT_TITLE = "title";
+ /**
+ * Hint that all sub-items/sub-slices within this content should be considered
+ * to have {@link #HINT_LIST_ITEM}.
+ */
+ public static final String HINT_LIST = "list";
+ /**
+ * Hint that this item is part of a list and should be formatted as if is part
+ * of a list.
+ */
+ public static final String HINT_LIST_ITEM = "list_item";
+ /**
+ * Hint that this content is important and should be larger when displayed if
+ * possible.
+ */
+ public static final String HINT_LARGE = "large";
+ /**
+ * Hint that this slice contains a number of actions that can be grouped together
+ * in a sort of controls area of the UI.
+ */
+ public static final String HINT_ACTIONS = "actions";
+ /**
+ * Hint indicating that this item (and its sub-items) are the current selection.
+ */
+ public static final String HINT_SELECTED = "selected";
+ /**
+ * Hint to indicate that this is a message as part of a communication
+ * sequence in this slice.
+ */
+ public static final String HINT_MESSAGE = "message";
+ /**
+ * Hint to tag the source (i.e. sender) of a {@link #HINT_MESSAGE}.
+ */
+ public static final String HINT_SOURCE = "source";
+ /**
+ * Hint that list items within this slice or subslice would appear better
+ * if organized horizontally.
+ */
+ public static final String HINT_HORIZONTAL = "horizontal";
+ /**
+ * Hint to indicate that this content should not be tinted.
+ */
+ public static final String HINT_NO_TINT = "no_tint";
+
+ // These two are coming over from prototyping, but we probably don't want in
+ // public API, at least not right now.
+ /**
+ * @hide
+ */
+ public static final String HINT_ALT = "alt";
+ /**
+ * @hide
+ */
+ public static final String HINT_PARTIAL = "partial";
+
+ private final SliceItem[] mItems;
+ private final @SliceHint String[] mHints;
+ private Uri mUri;
+
+ /**
+ * @hide
+ */
+ public Slice(ArrayList<SliceItem> items, @SliceHint String[] hints, Uri uri) {
+ mHints = hints;
+ mItems = items.toArray(new SliceItem[items.size()]);
+ mUri = uri;
+ }
+
+ protected Slice(Parcel in) {
+ mHints = in.readStringArray();
+ int n = in.readInt();
+ mItems = new SliceItem[n];
+ for (int i = 0; i < n; i++) {
+ mItems[i] = SliceItem.CREATOR.createFromParcel(in);
+ }
+ mUri = Uri.CREATOR.createFromParcel(in);
+ }
+
+ /**
+ * @return The Uri that this slice represents.
+ */
+ public Uri getUri() {
+ return mUri;
+ }
+
+ /**
+ * @return All child {@link SliceItem}s that this Slice contains.
+ */
+ public SliceItem[] getItems() {
+ return mItems;
+ }
+
+ /**
+ * @return All hints associated with this Slice.
+ */
+ public @SliceHint String[] getHints() {
+ return mHints;
+ }
+
+ /**
+ * @hide
+ */
+ public SliceItem getPrimaryIcon() {
+ for (SliceItem item : getItems()) {
+ if (item.getType() == TYPE_IMAGE) {
+ return item;
+ }
+ if (!(item.getType() == TYPE_SLICE && item.hasHint(Slice.HINT_LIST))
+ && !item.hasHint(Slice.HINT_ACTIONS)
+ && !item.hasHint(Slice.HINT_LIST_ITEM)
+ && (item.getType() != TYPE_ACTION)) {
+ SliceItem icon = SliceQuery.find(item, TYPE_IMAGE);
+ if (icon != null) return icon;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStringArray(mHints);
+ dest.writeInt(mItems.length);
+ for (int i = 0; i < mItems.length; i++) {
+ mItems[i].writeToParcel(dest, flags);
+ }
+ mUri.writeToParcel(dest, 0);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * A Builder used to construct {@link Slice}s
+ */
+ public static class Builder {
+
+ private final Uri mUri;
+ private ArrayList<SliceItem> mItems = new ArrayList<>();
+ private @SliceHint ArrayList<String> mHints = new ArrayList<>();
+
+ /**
+ * Create a builder which will construct a {@link Slice} for the Given Uri.
+ * @param uri Uri to tag for this slice.
+ */
+ public Builder(@NonNull Uri uri) {
+ mUri = uri;
+ }
+
+ /**
+ * Create a builder for a {@link Slice} that is a sub-slice of the slice
+ * being constructed by the provided builder.
+ * @param parent The builder constructing the parent slice
+ */
+ public Builder(@NonNull Slice.Builder parent) {
+ mUri = parent.mUri.buildUpon().appendPath("_gen")
+ .appendPath(String.valueOf(mItems.size())).build();
+ }
+
+ /**
+ * Add hints to the Slice being constructed
+ */
+ public Builder addHints(@SliceHint String... hints) {
+ mHints.addAll(Arrays.asList(hints));
+ return this;
+ }
+
+ /**
+ * Add a sub-slice to the slice being constructed
+ */
+ public Builder addSubSlice(@NonNull Slice slice) {
+ mItems.add(new SliceItem(slice, TYPE_SLICE, slice.getHints()));
+ return this;
+ }
+
+ /**
+ * Add an action to the slice being constructed
+ */
+ public Slice.Builder addAction(@NonNull PendingIntent action, @NonNull Slice s) {
+ mItems.add(new SliceItem(action, s, TYPE_ACTION, new String[0]));
+ return this;
+ }
+
+ /**
+ * Add text to the slice being constructed
+ */
+ public Builder addText(CharSequence text, @SliceHint String... hints) {
+ mItems.add(new SliceItem(text, TYPE_TEXT, hints));
+ return this;
+ }
+
+ /**
+ * Add an image to the slice being constructed
+ */
+ public Builder addIcon(Icon icon, @SliceHint String... hints) {
+ mItems.add(new SliceItem(icon, TYPE_IMAGE, hints));
+ return this;
+ }
+
+ /**
+ * @hide This isn't final
+ */
+ public Builder addRemoteView(RemoteViews remoteView, @SliceHint String... hints) {
+ mItems.add(new SliceItem(remoteView, TYPE_REMOTE_VIEW, hints));
+ return this;
+ }
+
+ /**
+ * Add remote input to the slice being constructed
+ */
+ public Slice.Builder addRemoteInput(RemoteInput remoteInput, @SliceHint String... hints) {
+ mItems.add(new SliceItem(remoteInput, TYPE_REMOTE_INPUT, hints));
+ return this;
+ }
+
+ /**
+ * Add a color to the slice being constructed
+ */
+ public Builder addColor(int color, @SliceHint String... hints) {
+ mItems.add(new SliceItem(color, TYPE_COLOR, hints));
+ return this;
+ }
+
+ /**
+ * Add a timestamp to the slice being constructed
+ */
+ public Slice.Builder addTimestamp(long time, @SliceHint String... hints) {
+ mItems.add(new SliceItem(time, TYPE_TIMESTAMP, hints));
+ return this;
+ }
+
+ /**
+ * Construct the slice.
+ */
+ public Slice build() {
+ return new Slice(mItems, mHints.toArray(new String[mHints.size()]), mUri);
+ }
+ }
+
+ public static final Creator<Slice> CREATOR = new Creator<Slice>() {
+ @Override
+ public Slice createFromParcel(Parcel in) {
+ return new Slice(in);
+ }
+
+ @Override
+ public Slice[] newArray(int size) {
+ return new Slice[size];
+ }
+ };
+}
diff --git a/core/java/android/slice/SliceItem.java b/core/java/android/slice/SliceItem.java
new file mode 100644
index 0000000..16f7dc6
--- /dev/null
+++ b/core/java/android/slice/SliceItem.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2017 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.slice;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.app.PendingIntent;
+import android.app.RemoteInput;
+import android.graphics.drawable.Icon;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.slice.Slice.SliceHint;
+import android.text.TextUtils;
+import android.util.Pair;
+import android.widget.RemoteViews;
+
+import com.android.internal.util.ArrayUtils;
+
+
+/**
+ * A SliceItem is a single unit in the tree structure of a {@link Slice}.
+ *
+ * A SliceItem a piece of content and some hints about what that content
+ * means or how it should be displayed. The types of content can be:
+ * <li>{@link #TYPE_SLICE}</li>
+ * <li>{@link #TYPE_TEXT}</li>
+ * <li>{@link #TYPE_IMAGE}</li>
+ * <li>{@link #TYPE_ACTION}</li>
+ * <li>{@link #TYPE_COLOR}</li>
+ * <li>{@link #TYPE_TIMESTAMP}</li>
+ * <li>{@link #TYPE_REMOTE_INPUT}</li>
+ *
+ * The hints that a {@link SliceItem} are a set of strings which annotate
+ * the content. The hints that are guaranteed to be understood by the system
+ * are defined on {@link Slice}.
+ * @hide
+ */
+public final class SliceItem implements Parcelable {
+
+ /**
+ * @hide
+ */
+ @IntDef({TYPE_SLICE, TYPE_TEXT, TYPE_IMAGE, TYPE_ACTION, TYPE_COLOR,
+ TYPE_TIMESTAMP, TYPE_REMOTE_INPUT})
+ public @interface SliceType {}
+
+ /**
+ * A {@link SliceItem} that contains a {@link Slice}
+ */
+ public static final int TYPE_SLICE = 1;
+ /**
+ * A {@link SliceItem} that contains a {@link CharSequence}
+ */
+ public static final int TYPE_TEXT = 2;
+ /**
+ * A {@link SliceItem} that contains an {@link Icon}
+ */
+ public static final int TYPE_IMAGE = 3;
+ /**
+ * A {@link SliceItem} that contains a {@link PendingIntent}
+ *
+ * Note: Actions contain 2 pieces of data, In addition to the pending intent, the
+ * item contains a {@link Slice} that the action applies to.
+ */
+ public static final int TYPE_ACTION = 4;
+ /**
+ * @hide This isn't final
+ */
+ public static final int TYPE_REMOTE_VIEW = 5;
+ /**
+ * A {@link SliceItem} that contains a Color int.
+ */
+ public static final int TYPE_COLOR = 6;
+ /**
+ * A {@link SliceItem} that contains a timestamp.
+ */
+ public static final int TYPE_TIMESTAMP = 8;
+ /**
+ * A {@link SliceItem} that contains a {@link RemoteInput}.
+ */
+ public static final int TYPE_REMOTE_INPUT = 9;
+
+ /**
+ * @hide
+ */
+ protected @SliceHint String[] mHints;
+ private final int mType;
+ private final Object mObj;
+
+ /**
+ * @hide
+ */
+ public SliceItem(Object obj, @SliceType int type, @SliceHint String[] hints) {
+ mHints = hints;
+ mType = type;
+ mObj = obj;
+ }
+
+ /**
+ * @hide
+ */
+ public SliceItem(PendingIntent intent, Slice slice, int type, @SliceHint String[] hints) {
+ this(new Pair<>(intent, slice), type, hints);
+ }
+
+ /**
+ * Gets all hints associated with this SliceItem.
+ * @return Array of hints.
+ */
+ public @NonNull @SliceHint String[] getHints() {
+ return mHints;
+ }
+
+ /**
+ * @hide
+ */
+ public void addHint(@SliceHint String hint) {
+ mHints = ArrayUtils.appendElement(String.class, mHints, hint);
+ }
+
+ public @SliceType int getType() {
+ return mType;
+ }
+
+ /**
+ * @return The text held by this {@link #TYPE_TEXT} SliceItem
+ */
+ public CharSequence getText() {
+ return (CharSequence) mObj;
+ }
+
+ /**
+ * @return The icon held by this {@link #TYPE_IMAGE} SliceItem
+ */
+ public Icon getIcon() {
+ return (Icon) mObj;
+ }
+
+ /**
+ * @return The pending intent held by this {@link #TYPE_ACTION} SliceItem
+ */
+ public PendingIntent getAction() {
+ return ((Pair<PendingIntent, Slice>) mObj).first;
+ }
+
+ /**
+ * @hide This isn't final
+ */
+ public RemoteViews getRemoteView() {
+ return (RemoteViews) mObj;
+ }
+
+ /**
+ * @return The remote input held by this {@link #TYPE_REMOTE_INPUT} SliceItem
+ */
+ public RemoteInput getRemoteInput() {
+ return (RemoteInput) mObj;
+ }
+
+ /**
+ * @return The color held by this {@link #TYPE_COLOR} SliceItem
+ */
+ public int getColor() {
+ return (Integer) mObj;
+ }
+
+ /**
+ * @return The slice held by this {@link #TYPE_ACTION} or {@link #TYPE_SLICE} SliceItem
+ */
+ public Slice getSlice() {
+ if (getType() == TYPE_ACTION) {
+ return ((Pair<PendingIntent, Slice>) mObj).second;
+ }
+ return (Slice) mObj;
+ }
+
+ /**
+ * @return The timestamp held by this {@link #TYPE_TIMESTAMP} SliceItem
+ */
+ public long getTimestamp() {
+ return (Long) mObj;
+ }
+
+ /**
+ * @param hint The hint to check for
+ * @return true if this item contains the given hint
+ */
+ public boolean hasHint(@SliceHint String hint) {
+ return ArrayUtils.contains(mHints, hint);
+ }
+
+ /**
+ * @hide
+ */
+ public SliceItem(Parcel in) {
+ mHints = in.readStringArray();
+ mType = in.readInt();
+ mObj = readObj(mType, in);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStringArray(mHints);
+ dest.writeInt(mType);
+ writeObj(dest, flags, mObj, mType);
+ }
+
+ /**
+ * @hide
+ */
+ public boolean hasHints(@SliceHint String[] hints) {
+ if (hints == null) return true;
+ for (String hint : hints) {
+ if (!ArrayUtils.contains(mHints, hint)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @hide
+ */
+ public boolean hasAnyHints(@SliceHint String[] hints) {
+ if (hints == null) return true;
+ for (String hint : hints) {
+ if (ArrayUtils.contains(mHints, hint)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void writeObj(Parcel dest, int flags, Object obj, int type) {
+ switch (type) {
+ case TYPE_SLICE:
+ case TYPE_REMOTE_VIEW:
+ case TYPE_IMAGE:
+ case TYPE_REMOTE_INPUT:
+ ((Parcelable) obj).writeToParcel(dest, flags);
+ break;
+ case TYPE_ACTION:
+ ((Pair<PendingIntent, Slice>) obj).first.writeToParcel(dest, flags);
+ ((Pair<PendingIntent, Slice>) obj).second.writeToParcel(dest, flags);
+ break;
+ case TYPE_TEXT:
+ TextUtils.writeToParcel((CharSequence) mObj, dest, flags);
+ break;
+ case TYPE_COLOR:
+ dest.writeInt((Integer) mObj);
+ break;
+ case TYPE_TIMESTAMP:
+ dest.writeLong((Long) mObj);
+ break;
+ }
+ }
+
+ private static Object readObj(int type, Parcel in) {
+ switch (type) {
+ case TYPE_SLICE:
+ return Slice.CREATOR.createFromParcel(in);
+ case TYPE_TEXT:
+ return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ case TYPE_IMAGE:
+ return Icon.CREATOR.createFromParcel(in);
+ case TYPE_ACTION:
+ return new Pair<PendingIntent, Slice>(
+ PendingIntent.CREATOR.createFromParcel(in),
+ Slice.CREATOR.createFromParcel(in));
+ case TYPE_REMOTE_VIEW:
+ return RemoteViews.CREATOR.createFromParcel(in);
+ case TYPE_COLOR:
+ return in.readInt();
+ case TYPE_TIMESTAMP:
+ return in.readLong();
+ case TYPE_REMOTE_INPUT:
+ return RemoteInput.CREATOR.createFromParcel(in);
+ }
+ throw new RuntimeException("Unsupported type " + type);
+ }
+
+ public static final Creator<SliceItem> CREATOR = new Creator<SliceItem>() {
+ @Override
+ public SliceItem createFromParcel(Parcel in) {
+ return new SliceItem(in);
+ }
+
+ @Override
+ public SliceItem[] newArray(int size) {
+ return new SliceItem[size];
+ }
+ };
+}
diff --git a/core/java/android/slice/SliceProvider.java b/core/java/android/slice/SliceProvider.java
new file mode 100644
index 0000000..4e21371
--- /dev/null
+++ b/core/java/android/slice/SliceProvider.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2017 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.slice;
+
+import android.Manifest.permission;
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * A SliceProvider allows app to provide content to be displayed in system
+ * spaces. This content is templated and can contain actions, and the behavior
+ * of how it is surfaced is specific to the system surface.
+ *
+ * <p>Slices are not currently live content. They are bound once and shown to the
+ * user. If the content changes due to a callback from user interaction, then
+ * {@link ContentResolver#notifyChange(Uri, ContentObserver)}
+ * should be used to notify the system.</p>
+ *
+ * <p>The provider needs to be declared in the manifest to provide the authority
+ * for the app. The authority for most slices is expected to match the package
+ * of the application.</p>
+ * <pre class="prettyprint">
+ * {@literal
+ * <provider
+ * android:name="com.android.mypkg.MySliceProvider"
+ * android:authorities="com.android.mypkg" />}
+ * </pre>
+ *
+ * @see Slice
+ * @hide
+ */
+public abstract class SliceProvider extends ContentProvider {
+
+ private static final String TAG = "SliceProvider";
+ /**
+ * @hide
+ */
+ public static final String EXTRA_BIND_URI = "slice_uri";
+ /**
+ * @hide
+ */
+ public static final String METHOD_SLICE = "bind_slice";
+ /**
+ * @hide
+ */
+ public static final String EXTRA_SLICE = "slice";
+
+ private static final boolean DEBUG = false;
+
+ /**
+ * Implemented to create a slice. Will be called on the main thread.
+ * @see {@link Slice}.
+ */
+ public abstract Slice onBindSlice(Uri sliceUri);
+
+ @Override
+ public final int update(Uri uri, ContentValues values, String selection,
+ String[] selectionArgs) {
+ if (DEBUG) Log.d(TAG, "update " + uri);
+ return 0;
+ }
+
+ @Override
+ public final int delete(Uri uri, String selection, String[] selectionArgs) {
+ if (DEBUG) Log.d(TAG, "delete " + uri);
+ return 0;
+ }
+
+ @Override
+ public final Cursor query(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ if (DEBUG) Log.d(TAG, "query " + uri);
+ return null;
+ }
+
+ @Override
+ public final Cursor query(Uri uri, String[] projection, String selection, String[]
+ selectionArgs, String sortOrder, CancellationSignal cancellationSignal) {
+ if (DEBUG) Log.d(TAG, "query " + uri);
+ return null;
+ }
+
+ @Override
+ public final Cursor query(Uri uri, String[] projection, Bundle queryArgs,
+ CancellationSignal cancellationSignal) {
+ if (DEBUG) Log.d(TAG, "query " + uri);
+ return null;
+ }
+
+ @Override
+ public final Uri insert(Uri uri, ContentValues values) {
+ if (DEBUG) Log.d(TAG, "insert " + uri);
+ return null;
+ }
+
+ @Override
+ public final String getType(Uri uri) {
+ if (DEBUG) Log.d(TAG, "getType " + uri);
+ return null;
+ }
+
+ @Override
+ public final Bundle call(String method, String arg, Bundle extras) {
+ if (method.equals(METHOD_SLICE)) {
+ getContext().enforceCallingPermission(permission.BIND_SLICE,
+ "Slice binding requires the permission BIND_SLICE");
+ Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+
+ Slice s = handleBindSlice(uri);
+ Bundle b = new Bundle();
+ b.putParcelable(EXTRA_SLICE, s);
+ return b;
+ }
+ return super.call(method, arg, extras);
+ }
+
+ private Slice handleBindSlice(Uri sliceUri) {
+ Slice[] output = new Slice[1];
+ CountDownLatch latch = new CountDownLatch(1);
+ Handler mainHandler = new Handler(Looper.getMainLooper());
+ mainHandler.post(() -> {
+ output[0] = onBindSlice(sliceUri);
+ latch.countDown();
+ });
+ try {
+ latch.await();
+ return output[0];
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/core/java/android/slice/SliceQuery.java b/core/java/android/slice/SliceQuery.java
new file mode 100644
index 0000000..edac0cc
--- /dev/null
+++ b/core/java/android/slice/SliceQuery.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2017 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.slice;
+
+import static android.slice.SliceItem.TYPE_ACTION;
+import static android.slice.SliceItem.TYPE_SLICE;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.Spliterators;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+/**
+ * A bunch of utilities for searching the contents of a slice.
+ * @hide
+ */
+public class SliceQuery {
+ private static final String TAG = "SliceQuery";
+
+ /**
+ * @hide
+ */
+ public static SliceItem findNotContaining(SliceItem container, List<SliceItem> list) {
+ SliceItem ret = null;
+ while (ret == null && list.size() != 0) {
+ SliceItem remove = list.remove(0);
+ if (!contains(container, remove)) {
+ ret = remove;
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * @hide
+ */
+ private static boolean contains(SliceItem container, SliceItem item) {
+ if (container == null || item == null) return false;
+ return stream(container).filter(s -> (s == item)).findAny().isPresent();
+ }
+
+ /**
+ * @hide
+ */
+ public static List<SliceItem> findAll(SliceItem s, int type, String hints, String nonHints) {
+ return findAll(s, type, new String[]{ hints }, new String[]{ nonHints });
+ }
+
+ /**
+ * @hide
+ */
+ public static List<SliceItem> findAll(SliceItem s, int type, String[] hints,
+ String[] nonHints) {
+ return stream(s).filter(item -> (type == -1 || item.getType() == type)
+ && (item.hasHints(hints) && !item.hasAnyHints(nonHints)))
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * @hide
+ */
+ public static SliceItem find(Slice s, int type, String hints, String nonHints) {
+ return find(s, type, new String[]{ hints }, new String[]{ nonHints });
+ }
+
+ /**
+ * @hide
+ */
+ public static SliceItem find(SliceItem s, int type) {
+ return find(s, type, (String[]) null, null);
+ }
+
+ /**
+ * @hide
+ */
+ public static SliceItem find(SliceItem s, int type, String hints, String nonHints) {
+ return find(s, type, new String[]{ hints }, new String[]{ nonHints });
+ }
+
+ /**
+ * @hide
+ */
+ public static SliceItem find(Slice s, int type, String[] hints, String[] nonHints) {
+ return find(new SliceItem(s, TYPE_SLICE, s.getHints()), type, hints, nonHints);
+ }
+
+ /**
+ * @hide
+ */
+ public static SliceItem find(SliceItem s, int type, String[] hints, String[] nonHints) {
+ return stream(s).filter(item -> (item.getType() == type || type == -1)
+ && (item.hasHints(hints) && !item.hasAnyHints(nonHints))).findFirst().orElse(null);
+ }
+
+ /**
+ * @hide
+ */
+ public static Stream<SliceItem> stream(SliceItem slice) {
+ Queue<SliceItem> items = new LinkedList();
+ items.add(slice);
+ Iterator<SliceItem> iterator = new Iterator<SliceItem>() {
+ @Override
+ public boolean hasNext() {
+ return items.size() != 0;
+ }
+
+ @Override
+ public SliceItem next() {
+ SliceItem item = items.poll();
+ if (item.getType() == TYPE_SLICE || item.getType() == TYPE_ACTION) {
+ items.addAll(Arrays.asList(item.getSlice().getItems()));
+ }
+ return item;
+ }
+ };
+ return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
+ }
+}
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index 16f2d7d..2c9f871 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -103,7 +103,7 @@
* <tr>
* <td>ACTION_DRAG_ENDED</td>
* <td style="text-align: center;"> </td>
- * <td style="text-align: center;"> </td>
+ * <td style="text-align: center;">X</td>
* <td style="text-align: center;"> </td>
* <td style="text-align: center;"> </td>
* <td style="text-align: center;"> </td>
@@ -112,6 +112,7 @@
* </table>
* <p>
* The {@link android.view.DragEvent#getAction()},
+ * {@link android.view.DragEvent#getLocalState()}
* {@link android.view.DragEvent#describeContents()},
* {@link android.view.DragEvent#writeToParcel(Parcel,int)}, and
* {@link android.view.DragEvent#toString()} methods always return valid data.
@@ -397,7 +398,7 @@
* operation. In all other activities this method will return null
* </p>
* <p>
- * This method returns valid data for all event actions except for {@link #ACTION_DRAG_ENDED}.
+ * This method returns valid data for all event actions.
* </p>
* @return The local state object sent to the system by startDragAndDrop().
*/
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3f710a8..b6be296 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -15529,7 +15529,13 @@
* {@code dirty}.
*
* @param dirty the rectangle representing the bounds of the dirty region
+ *
+ * @deprecated The switch to hardware accelerated rendering in API 14 reduced
+ * the importance of the dirty rectangle. In API 21 the given rectangle is
+ * ignored entirely in favor of an internally-calculated area instead.
+ * Because of this, clients are encouraged to just call {@link #invalidate()}.
*/
+ @Deprecated
public void invalidate(Rect dirty) {
final int scrollX = mScrollX;
final int scrollY = mScrollY;
@@ -15550,7 +15556,13 @@
* @param t the top position of the dirty region
* @param r the right position of the dirty region
* @param b the bottom position of the dirty region
+ *
+ * @deprecated The switch to hardware accelerated rendering in API 14 reduced
+ * the importance of the dirty rectangle. In API 21 the given rectangle is
+ * ignored entirely in favor of an internally-calculated area instead.
+ * Because of this, clients are encouraged to just call {@link #invalidate()}.
*/
+ @Deprecated
public void invalidate(int l, int t, int r, int b) {
final int scrollX = mScrollX;
final int scrollY = mScrollY;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index a346863..71106ad 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -512,7 +512,7 @@
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
if (!sCompatibilityDone) {
- sAlwaysAssignFocus = true;
+ sAlwaysAssignFocus = mTargetSdkVersion < Build.VERSION_CODES.P;
sCompatibilityDone = true;
}
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 4773cda..95cb454 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -454,13 +454,13 @@
// waiting on relro creation.
if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro");
- WebViewLibraryLoader.createRelroFile(false /* is64Bit */, nativeLibraryPaths);
+ WebViewLibraryLoader.createRelroFile(false /* is64Bit */, nativeLibraryPaths[0]);
numRelros++;
}
if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro");
- WebViewLibraryLoader.createRelroFile(true /* is64Bit */, nativeLibraryPaths);
+ WebViewLibraryLoader.createRelroFile(true /* is64Bit */, nativeLibraryPaths[1]);
numRelros++;
}
return numRelros;
diff --git a/core/java/android/webkit/WebViewLibraryLoader.java b/core/java/android/webkit/WebViewLibraryLoader.java
index 21316e7..fa1a390 100644
--- a/core/java/android/webkit/WebViewLibraryLoader.java
+++ b/core/java/android/webkit/WebViewLibraryLoader.java
@@ -62,20 +62,18 @@
boolean result = false;
boolean is64Bit = VMRuntime.getRuntime().is64Bit();
try {
- if (args.length != 2 || args[0] == null || args[1] == null) {
+ if (args.length != 1 || args[0] == null) {
Log.e(LOGTAG, "Invalid RelroFileCreator args: " + Arrays.toString(args));
return;
}
- Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), "
- + " 32-bit lib: " + args[0] + ", 64-bit lib: " + args[1]);
+ Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), lib: " + args[0]);
if (!sAddressSpaceReserved) {
Log.e(LOGTAG, "can't create relro file; address space not reserved");
return;
}
- result = nativeCreateRelroFile(args[0] /* path32 */,
- args[1] /* path64 */,
- CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
- CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
+ result = nativeCreateRelroFile(args[0] /* path */,
+ is64Bit ? CHROMIUM_WEBVIEW_NATIVE_RELRO_64 :
+ CHROMIUM_WEBVIEW_NATIVE_RELRO_32);
if (result && DEBUG) Log.v(LOGTAG, "created relro file");
} finally {
// We must do our best to always notify the update service, even if something fails.
@@ -96,7 +94,7 @@
/**
* Create a single relro file by invoking an isolated process that to do the actual work.
*/
- static void createRelroFile(final boolean is64Bit, String[] nativeLibraryPaths) {
+ static void createRelroFile(final boolean is64Bit, String nativeLibraryPath) {
final String abi =
is64Bit ? Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
@@ -114,13 +112,12 @@
};
try {
- if (nativeLibraryPaths == null
- || nativeLibraryPaths[0] == null || nativeLibraryPaths[1] == null) {
+ if (nativeLibraryPath == null) {
throw new IllegalArgumentException(
"Native library paths to the WebView RelRo process must not be null!");
}
int pid = LocalServices.getService(ActivityManagerInternal.class).startIsolatedProcess(
- RelroFileCreator.class.getName(), nativeLibraryPaths,
+ RelroFileCreator.class.getName(), new String[] { nativeLibraryPath },
"WebViewLoader-" + abi, abi, Process.SHARED_RELRO_UID, crashHandler);
if (pid <= 0) throw new Exception("Failed to start the relro file creator process");
} catch (Throwable t) {
@@ -217,8 +214,9 @@
final String libraryFileName =
WebViewFactory.getWebViewLibrary(packageInfo.applicationInfo);
- int result = nativeLoadWithRelroFile(libraryFileName, CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
- CHROMIUM_WEBVIEW_NATIVE_RELRO_64, clazzLoader);
+ String relroPath = VMRuntime.getRuntime().is64Bit() ? CHROMIUM_WEBVIEW_NATIVE_RELRO_64 :
+ CHROMIUM_WEBVIEW_NATIVE_RELRO_32;
+ int result = nativeLoadWithRelroFile(libraryFileName, relroPath, clazzLoader);
if (result != WebViewFactory.LIBLOAD_SUCCESS) {
Log.w(LOGTAG, "failed to load with relro file, proceeding without");
} else if (DEBUG) {
@@ -313,8 +311,6 @@
}
static native boolean nativeReserveAddressSpace(long addressSpaceToReserve);
- static native boolean nativeCreateRelroFile(String lib32, String lib64,
- String relro32, String relro64);
- static native int nativeLoadWithRelroFile(String lib, String relro32, String relro64,
- ClassLoader clazzLoader);
+ static native boolean nativeCreateRelroFile(String lib, String relro);
+ static native int nativeLoadWithRelroFile(String lib, String relro, ClassLoader clazzLoader);
}
diff --git a/core/java/com/android/internal/alsa/AlsaDevicesParser.java b/core/java/com/android/internal/alsa/AlsaDevicesParser.java
index 7cdd897..6e3d596 100644
--- a/core/java/com/android/internal/alsa/AlsaDevicesParser.java
+++ b/core/java/com/android/internal/alsa/AlsaDevicesParser.java
@@ -258,7 +258,7 @@
return line.charAt(kIndex_CardDeviceField) == '[';
}
- public void scan() {
+ public boolean scan() {
mDeviceRecords.clear();
File devicesFile = new File(kDevicesFilePath);
@@ -274,11 +274,13 @@
}
}
reader.close();
+ return true;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
+ return false;
}
//
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 0bd2981..36fd991 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -119,7 +119,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 166 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 167 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS;
@@ -341,8 +341,8 @@
protected final TimeBase mOnBatteryTimeBase = new TimeBase();
// These are the objects that will want to do something when the device
- // is unplugged from power *and* the screen is off.
- final TimeBase mOnBatteryScreenOffTimeBase = new TimeBase();
+ // is unplugged from power *and* the screen is off or doze.
+ protected final TimeBase mOnBatteryScreenOffTimeBase = new TimeBase();
// Set to true when we want to distribute CPU across wakelocks for the next
// CPU update, even if we aren't currently running wake locks.
@@ -436,8 +436,12 @@
public boolean mRecordAllHistory;
boolean mNoAutoReset;
- int mScreenState = Display.STATE_UNKNOWN;
- StopwatchTimer mScreenOnTimer;
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ protected int mScreenState = Display.STATE_UNKNOWN;
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ protected StopwatchTimer mScreenOnTimer;
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ protected StopwatchTimer mScreenDozeTimer;
int mScreenBrightnessBin = -1;
final StopwatchTimer[] mScreenBrightnessTimer = new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS];
@@ -583,12 +587,16 @@
int mHighDischargeAmountSinceCharge;
int mDischargeScreenOnUnplugLevel;
int mDischargeScreenOffUnplugLevel;
+ int mDischargeScreenDozeUnplugLevel;
int mDischargeAmountScreenOn;
int mDischargeAmountScreenOnSinceCharge;
int mDischargeAmountScreenOff;
int mDischargeAmountScreenOffSinceCharge;
+ int mDischargeAmountScreenDoze;
+ int mDischargeAmountScreenDozeSinceCharge;
private LongSamplingCounter mDischargeScreenOffCounter;
+ private LongSamplingCounter mDischargeScreenDozeCounter;
private LongSamplingCounter mDischargeCounter;
static final int MAX_LEVEL_STEPS = 200;
@@ -673,13 +681,18 @@
}
@Override
- public LongCounter getDischargeScreenOffCoulombCounter() {
- return mDischargeScreenOffCounter;
+ public long getMahDischarge(int which) {
+ return mDischargeCounter.getCountLocked(which);
}
@Override
- public LongCounter getDischargeCoulombCounter() {
- return mDischargeCounter;
+ public long getMahDischargeScreenOff(int which) {
+ return mDischargeScreenOffCounter.getCountLocked(which);
+ }
+
+ @Override
+ public long getMahDischargeScreenDoze(int which) {
+ return mDischargeScreenDozeCounter.getCountLocked(which);
}
@Override
@@ -3573,8 +3586,9 @@
mActiveHistoryStates2 = 0xffffffff;
}
- public void updateTimeBasesLocked(boolean unplugged, boolean screenOff, long uptime,
+ public void updateTimeBasesLocked(boolean unplugged, int screenState, long uptime,
long realtime) {
+ final boolean screenOff = isScreenOff(screenState) || isScreenDoze(screenState);
final boolean updateOnBatteryTimeBase = unplugged != mOnBatteryTimeBase.isRunning();
final boolean updateOnBatteryScreenOffTimeBase =
(unplugged && screenOff) != mOnBatteryScreenOffTimeBase.isRunning();
@@ -3591,20 +3605,22 @@
updateRpmStatsLocked(); // if either OnBattery or OnBatteryScreenOff timebase changes.
}
if (DEBUG_ENERGY_CPU) {
- Slog.d(TAG, "Updating cpu time because screen is now " + (screenOff ? "off" : "on")
+ Slog.d(TAG, "Updating cpu time because screen is now "
+ + Display.stateToString(screenState)
+ " and battery is " + (unplugged ? "on" : "off"));
}
updateCpuTimeLocked();
mOnBatteryTimeBase.setRunning(unplugged, uptime, realtime);
- mOnBatteryScreenOffTimeBase.setRunning(unplugged && screenOff, uptime, realtime);
- for (int i = mUidStats.size() - 1; i >= 0; --i) {
- final Uid u = mUidStats.valueAt(i);
- if (updateOnBatteryTimeBase) {
- u.updateOnBatteryBgTimeBase(uptime, realtime);
+ if (updateOnBatteryTimeBase) {
+ for (int i = mUidStats.size() - 1; i >= 0; --i) {
+ mUidStats.valueAt(i).updateOnBatteryBgTimeBase(uptime, realtime);
}
- if (updateOnBatteryScreenOffTimeBase) {
- u.updateOnBatteryScreenOffBgTimeBase(uptime, realtime);
+ }
+ if (updateOnBatteryScreenOffTimeBase) {
+ mOnBatteryScreenOffTimeBase.setRunning(unplugged && screenOff, uptime, realtime);
+ for (int i = mUidStats.size() - 1; i >= 0; --i) {
+ mUidStats.valueAt(i).updateOnBatteryScreenOffBgTimeBase(uptime, realtime);
}
}
}
@@ -3864,8 +3880,10 @@
}
public void setPretendScreenOff(boolean pretendScreenOff) {
- mPretendScreenOff = pretendScreenOff;
- noteScreenStateLocked(pretendScreenOff ? Display.STATE_OFF : Display.STATE_ON);
+ if (mPretendScreenOff != pretendScreenOff) {
+ mPretendScreenOff = pretendScreenOff;
+ noteScreenStateLocked(pretendScreenOff ? Display.STATE_OFF : Display.STATE_ON);
+ }
}
private String mInitialAcquireWakeName;
@@ -4195,54 +4213,58 @@
}
}
- if (state == Display.STATE_ON) {
- // Screen turning on.
- final long elapsedRealtime = mClocks.elapsedRealtime();
- final long uptime = mClocks.uptimeMillis();
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
+
+ boolean updateHistory = false;
+ if (isScreenDoze(state)) {
+ mHistoryCur.states |= HistoryItem.STATE_SCREEN_DOZE_FLAG;
+ mScreenDozeTimer.startRunningLocked(elapsedRealtime);
+ updateHistory = true;
+ } else if (isScreenDoze(oldState)) {
+ mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_DOZE_FLAG;
+ mScreenDozeTimer.stopRunningLocked(elapsedRealtime);
+ updateHistory = true;
+ }
+ if (isScreenOn(state)) {
mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(elapsedRealtime, uptime);
mScreenOnTimer.startRunningLocked(elapsedRealtime);
if (mScreenBrightnessBin >= 0) {
mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(elapsedRealtime);
}
-
- updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), false,
- mClocks.uptimeMillis() * 1000, elapsedRealtime * 1000);
-
- // Fake a wake lock, so we consider the device waked as long
- // as the screen is on.
- noteStartWakeLocked(-1, -1, "screen", null, WAKE_TYPE_PARTIAL, false,
- elapsedRealtime, uptime);
-
- // Update discharge amounts.
- if (mOnBatteryInternal) {
- updateDischargeScreenLevelsLocked(false, true);
- }
- } else if (oldState == Display.STATE_ON) {
- // Screen turning off or dozing.
- final long elapsedRealtime = mClocks.elapsedRealtime();
- final long uptime = mClocks.uptimeMillis();
+ updateHistory = true;
+ } else if (isScreenOn(oldState)) {
mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(elapsedRealtime, uptime);
mScreenOnTimer.stopRunningLocked(elapsedRealtime);
if (mScreenBrightnessBin >= 0) {
mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(elapsedRealtime);
}
-
+ updateHistory = true;
+ }
+ if (updateHistory) {
+ if (DEBUG_HISTORY) Slog.v(TAG, "Screen state to: "
+ + Display.stateToString(state));
+ addHistoryRecordLocked(elapsedRealtime, uptime);
+ }
+ if (isScreenOn(state)) {
+ updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), state,
+ mClocks.uptimeMillis() * 1000, elapsedRealtime * 1000);
+ // Fake a wake lock, so we consider the device waked as long as the screen is on.
+ noteStartWakeLocked(-1, -1, "screen", null, WAKE_TYPE_PARTIAL, false,
+ elapsedRealtime, uptime);
+ } else if (isScreenOn(oldState)) {
noteStopWakeLocked(-1, -1, "screen", "screen", WAKE_TYPE_PARTIAL,
elapsedRealtime, uptime);
-
- updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), true,
+ updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), state,
mClocks.uptimeMillis() * 1000, elapsedRealtime * 1000);
-
- // Update discharge amounts.
- if (mOnBatteryInternal) {
- updateDischargeScreenLevelsLocked(true, false);
- }
+ }
+ // Update discharge amounts.
+ if (mOnBatteryInternal) {
+ updateDischargeScreenLevelsLocked(oldState, state);
}
}
}
@@ -5391,6 +5413,14 @@
return mScreenOnTimer.getCountLocked(which);
}
+ @Override public long getScreenDozeTime(long elapsedRealtimeUs, int which) {
+ return mScreenDozeTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
+ }
+
+ @Override public int getScreenDozeCount(int which) {
+ return mScreenDozeTimer.getCountLocked(which);
+ }
+
@Override public long getScreenBrightnessTime(int brightnessBin,
long elapsedRealtimeUs, int which) {
return mScreenBrightnessTimer[brightnessBin].getTotalTimeLocked(
@@ -8829,6 +8859,7 @@
mHandler = new MyHandler(handler.getLooper());
mStartCount++;
mScreenOnTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
+ mScreenDozeTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i] = new StopwatchTimer(mClocks, null, -100-i, null,
mOnBatteryTimeBase);
@@ -8887,6 +8918,7 @@
mCameraOnTimer = new StopwatchTimer(mClocks, null, -13, null, mOnBatteryTimeBase);
mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
mDischargeScreenOffCounter = new LongSamplingCounter(mOnBatteryScreenOffTimeBase);
+ mDischargeScreenDozeCounter = new LongSamplingCounter(mOnBatteryTimeBase);
mDischargeCounter = new LongSamplingCounter(mOnBatteryTimeBase);
mOnBattery = mOnBatteryInternal = false;
long uptime = mClocks.uptimeMillis() * 1000;
@@ -9430,8 +9462,16 @@
return mCharging;
}
- public boolean isScreenOn() {
- return mScreenState == Display.STATE_ON;
+ public boolean isScreenOn(int state) {
+ return state == Display.STATE_ON;
+ }
+
+ public boolean isScreenOff(int state) {
+ return state == Display.STATE_OFF;
+ }
+
+ public boolean isScreenDoze(int state) {
+ return state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND;
}
void initTimes(long uptime, long realtime) {
@@ -9451,9 +9491,12 @@
mDischargeAmountScreenOnSinceCharge = 0;
mDischargeAmountScreenOff = 0;
mDischargeAmountScreenOffSinceCharge = 0;
+ mDischargeAmountScreenDoze = 0;
+ mDischargeAmountScreenDozeSinceCharge = 0;
mDischargeStepTracker.init();
mChargeStepTracker.init();
mDischargeScreenOffCounter.reset(false);
+ mDischargeScreenDozeCounter.reset(false);
mDischargeCounter.reset(false);
}
@@ -9471,15 +9514,22 @@
mOnBatteryTimeBase.reset(uptime, realtime);
mOnBatteryScreenOffTimeBase.reset(uptime, realtime);
if ((mHistoryCur.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) == 0) {
- if (mScreenState == Display.STATE_ON) {
+ if (isScreenOn(mScreenState)) {
mDischargeScreenOnUnplugLevel = mHistoryCur.batteryLevel;
+ mDischargeScreenDozeUnplugLevel = 0;
+ mDischargeScreenOffUnplugLevel = 0;
+ } else if (isScreenDoze(mScreenState)) {
+ mDischargeScreenOnUnplugLevel = 0;
+ mDischargeScreenDozeUnplugLevel = mHistoryCur.batteryLevel;
mDischargeScreenOffUnplugLevel = 0;
} else {
mDischargeScreenOnUnplugLevel = 0;
+ mDischargeScreenDozeUnplugLevel = 0;
mDischargeScreenOffUnplugLevel = mHistoryCur.batteryLevel;
}
mDischargeAmountScreenOn = 0;
mDischargeAmountScreenOff = 0;
+ mDischargeAmountScreenDoze = 0;
}
initActiveHistoryEventsLocked(mSecRealtime, mSecUptime);
}
@@ -9490,6 +9540,7 @@
mStartCount = 0;
initTimes(uptimeMillis * 1000, elapsedRealtimeMillis * 1000);
mScreenOnTimer.reset(false);
+ mScreenDozeTimer.reset(false);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].reset(false);
}
@@ -9626,33 +9677,52 @@
}
}
- void updateDischargeScreenLevelsLocked(boolean oldScreenOn, boolean newScreenOn) {
- if (oldScreenOn) {
+ void updateDischargeScreenLevelsLocked(int oldState, int newState) {
+ updateOldDischargeScreenLevelLocked(oldState);
+ updateNewDischargeScreenLevelLocked(newState);
+ }
+
+ private void updateOldDischargeScreenLevelLocked(int state) {
+ if (isScreenOn(state)) {
int diff = mDischargeScreenOnUnplugLevel - mDischargeCurrentLevel;
if (diff > 0) {
mDischargeAmountScreenOn += diff;
mDischargeAmountScreenOnSinceCharge += diff;
}
- } else {
+ } else if (isScreenDoze(state)) {
+ int diff = mDischargeScreenDozeUnplugLevel - mDischargeCurrentLevel;
+ if (diff > 0) {
+ mDischargeAmountScreenDoze += diff;
+ mDischargeAmountScreenDozeSinceCharge += diff;
+ }
+ } else if (isScreenOff(state)){
int diff = mDischargeScreenOffUnplugLevel - mDischargeCurrentLevel;
if (diff > 0) {
mDischargeAmountScreenOff += diff;
mDischargeAmountScreenOffSinceCharge += diff;
}
}
- if (newScreenOn) {
+ }
+
+ private void updateNewDischargeScreenLevelLocked(int state) {
+ if (isScreenOn(state)) {
mDischargeScreenOnUnplugLevel = mDischargeCurrentLevel;
mDischargeScreenOffUnplugLevel = 0;
- } else {
+ mDischargeScreenDozeUnplugLevel = 0;
+ } else if (isScreenDoze(state)){
mDischargeScreenOnUnplugLevel = 0;
+ mDischargeScreenDozeUnplugLevel = mDischargeCurrentLevel;
+ mDischargeScreenOffUnplugLevel = 0;
+ } else if (isScreenOff(state)) {
+ mDischargeScreenOnUnplugLevel = 0;
+ mDischargeScreenDozeUnplugLevel = 0;
mDischargeScreenOffUnplugLevel = mDischargeCurrentLevel;
}
}
public void pullPendingStateUpdatesLocked() {
if (mOnBatteryInternal) {
- final boolean screenOn = mScreenState == Display.STATE_ON;
- updateDischargeScreenLevelsLocked(screenOn, screenOn);
+ updateDischargeScreenLevelsLocked(mScreenState, mScreenState);
}
}
@@ -10785,8 +10855,8 @@
return false;
}
- void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime, final boolean onBattery,
- final int oldStatus, final int level, final int chargeUAh) {
+ protected void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime,
+ final boolean onBattery, final int oldStatus, final int level, final int chargeUAh) {
boolean doWrite = false;
Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE);
m.arg1 = onBattery ? 1 : 0;
@@ -10794,7 +10864,7 @@
final long uptime = mSecUptime * 1000;
final long realtime = mSecRealtime * 1000;
- final boolean screenOn = mScreenState == Display.STATE_ON;
+ final int screenState = mScreenState;
if (onBattery) {
// We will reset our status if we are unplugging after the
// battery was last full, or the level is at 100, or
@@ -10870,16 +10940,23 @@
}
addHistoryRecordLocked(mSecRealtime, mSecUptime);
mDischargeCurrentLevel = mDischargeUnplugLevel = level;
- if (screenOn) {
+ if (isScreenOn(screenState)) {
mDischargeScreenOnUnplugLevel = level;
+ mDischargeScreenDozeUnplugLevel = 0;
+ mDischargeScreenOffUnplugLevel = 0;
+ } else if (isScreenDoze(screenState)) {
+ mDischargeScreenOnUnplugLevel = 0;
+ mDischargeScreenDozeUnplugLevel = level;
mDischargeScreenOffUnplugLevel = 0;
} else {
mDischargeScreenOnUnplugLevel = 0;
+ mDischargeScreenDozeUnplugLevel = 0;
mDischargeScreenOffUnplugLevel = level;
}
mDischargeAmountScreenOn = 0;
+ mDischargeAmountScreenDoze = 0;
mDischargeAmountScreenOff = 0;
- updateTimeBasesLocked(true, !screenOn, uptime, realtime);
+ updateTimeBasesLocked(true, screenState, uptime, realtime);
} else {
mLastChargingStateLevel = level;
mOnBattery = mOnBatteryInternal = false;
@@ -10894,8 +10971,8 @@
mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
}
- updateDischargeScreenLevelsLocked(screenOn, screenOn);
- updateTimeBasesLocked(false, !screenOn, uptime, realtime);
+ updateDischargeScreenLevelsLocked(screenState, screenState);
+ updateTimeBasesLocked(false, screenState, uptime, realtime);
mChargeStepTracker.init();
mLastChargeStepLevel = level;
mMaxChargeStepLevel = level;
@@ -11012,6 +11089,9 @@
final long chargeDiff = mHistoryCur.batteryChargeUAh - chargeUAh;
mDischargeCounter.addCountLocked(chargeDiff);
mDischargeScreenOffCounter.addCountLocked(chargeDiff);
+ if (isScreenDoze(mScreenState)) {
+ mDischargeScreenDozeCounter.addCountLocked(chargeDiff);
+ }
}
mHistoryCur.batteryChargeUAh = chargeUAh;
setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level, chargeUAh);
@@ -11054,6 +11134,9 @@
final long chargeDiff = mHistoryCur.batteryChargeUAh - chargeUAh;
mDischargeCounter.addCountLocked(chargeDiff);
mDischargeScreenOffCounter.addCountLocked(chargeDiff);
+ if (isScreenDoze(mScreenState)) {
+ mDischargeScreenDozeCounter.addCountLocked(chargeDiff);
+ }
}
mHistoryCur.batteryChargeUAh = chargeUAh;
changed = true;
@@ -11362,10 +11445,11 @@
return dischargeAmount;
}
+ @Override
public int getDischargeAmountScreenOn() {
synchronized(this) {
int val = mDischargeAmountScreenOn;
- if (mOnBattery && mScreenState == Display.STATE_ON
+ if (mOnBattery && isScreenOn(mScreenState)
&& mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
}
@@ -11373,10 +11457,11 @@
}
}
+ @Override
public int getDischargeAmountScreenOnSinceCharge() {
synchronized(this) {
int val = mDischargeAmountScreenOnSinceCharge;
- if (mOnBattery && mScreenState == Display.STATE_ON
+ if (mOnBattery && isScreenOn(mScreenState)
&& mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
}
@@ -11384,23 +11469,51 @@
}
}
+ @Override
public int getDischargeAmountScreenOff() {
synchronized(this) {
int val = mDischargeAmountScreenOff;
- if (mOnBattery && mScreenState != Display.STATE_ON
+ if (mOnBattery && isScreenOff(mScreenState)
&& mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
}
+ // For backward compatibility, doze discharge is counted into screen off.
+ return val + getDischargeAmountScreenDoze();
+ }
+ }
+
+ @Override
+ public int getDischargeAmountScreenOffSinceCharge() {
+ synchronized(this) {
+ int val = mDischargeAmountScreenOffSinceCharge;
+ if (mOnBattery && isScreenOff(mScreenState)
+ && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
+ val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
+ }
+ // For backward compatibility, doze discharge is counted into screen off.
+ return val + getDischargeAmountScreenDozeSinceCharge();
+ }
+ }
+
+ @Override
+ public int getDischargeAmountScreenDoze() {
+ synchronized(this) {
+ int val = mDischargeAmountScreenDoze;
+ if (mOnBattery && isScreenDoze(mScreenState)
+ && mDischargeCurrentLevel < mDischargeScreenDozeUnplugLevel) {
+ val += mDischargeScreenDozeUnplugLevel-mDischargeCurrentLevel;
+ }
return val;
}
}
- public int getDischargeAmountScreenOffSinceCharge() {
+ @Override
+ public int getDischargeAmountScreenDozeSinceCharge() {
synchronized(this) {
- int val = mDischargeAmountScreenOffSinceCharge;
- if (mOnBattery && mScreenState != Display.STATE_ON
- && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
- val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
+ int val = mDischargeAmountScreenDozeSinceCharge;
+ if (mOnBattery && isScreenDoze(mScreenState)
+ && mDischargeCurrentLevel < mDischargeScreenDozeUnplugLevel) {
+ val += mDischargeScreenDozeUnplugLevel-mDischargeCurrentLevel;
}
return val;
}
@@ -11759,12 +11872,14 @@
mHighDischargeAmountSinceCharge = in.readInt();
mDischargeAmountScreenOnSinceCharge = in.readInt();
mDischargeAmountScreenOffSinceCharge = in.readInt();
+ mDischargeAmountScreenDozeSinceCharge = in.readInt();
mDischargeStepTracker.readFromParcel(in);
mChargeStepTracker.readFromParcel(in);
mDailyDischargeStepTracker.readFromParcel(in);
mDailyChargeStepTracker.readFromParcel(in);
mDischargeCounter.readSummaryFromParcelLocked(in);
mDischargeScreenOffCounter.readSummaryFromParcelLocked(in);
+ mDischargeScreenDozeCounter.readSummaryFromParcelLocked(in);
int NPKG = in.readInt();
if (NPKG > 0) {
mDailyPackageChanges = new ArrayList<>(NPKG);
@@ -11787,6 +11902,7 @@
mScreenState = Display.STATE_UNKNOWN;
mScreenOnTimer.readSummaryFromParcelLocked(in);
+ mScreenDozeTimer.readSummaryFromParcelLocked(in);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].readSummaryFromParcelLocked(in);
}
@@ -12180,12 +12296,14 @@
out.writeInt(getHighDischargeAmountSinceCharge());
out.writeInt(getDischargeAmountScreenOnSinceCharge());
out.writeInt(getDischargeAmountScreenOffSinceCharge());
+ out.writeInt(getDischargeAmountScreenDozeSinceCharge());
mDischargeStepTracker.writeToParcel(out);
mChargeStepTracker.writeToParcel(out);
mDailyDischargeStepTracker.writeToParcel(out);
mDailyChargeStepTracker.writeToParcel(out);
mDischargeCounter.writeSummaryFromParcelLocked(out);
mDischargeScreenOffCounter.writeSummaryFromParcelLocked(out);
+ mDischargeScreenDozeCounter.writeSummaryFromParcelLocked(out);
if (mDailyPackageChanges != null) {
final int NPKG = mDailyPackageChanges.size();
out.writeInt(NPKG);
@@ -12203,6 +12321,7 @@
out.writeLong(mNextMaxDailyDeadline);
mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mScreenDozeTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
}
@@ -12635,6 +12754,7 @@
mScreenState = Display.STATE_UNKNOWN;
mScreenOnTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase, in);
+ mScreenDozeTimer = new StopwatchTimer(mClocks, null, -1, null, mOnBatteryTimeBase, in);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i] = new StopwatchTimer(mClocks, null, -100-i, null,
mOnBatteryTimeBase, in);
@@ -12728,10 +12848,13 @@
mDischargeAmountScreenOnSinceCharge = in.readInt();
mDischargeAmountScreenOff = in.readInt();
mDischargeAmountScreenOffSinceCharge = in.readInt();
+ mDischargeAmountScreenDoze = in.readInt();
+ mDischargeAmountScreenDozeSinceCharge = in.readInt();
mDischargeStepTracker.readFromParcel(in);
mChargeStepTracker.readFromParcel(in);
mDischargeCounter = new LongSamplingCounter(mOnBatteryTimeBase, in);
- mDischargeScreenOffCounter = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ mDischargeScreenOffCounter = new LongSamplingCounter(mOnBatteryScreenOffTimeBase, in);
+ mDischargeScreenDozeCounter = new LongSamplingCounter(mOnBatteryTimeBase, in);
mLastWriteTime = in.readLong();
mRpmStats.clear();
@@ -12848,6 +12971,7 @@
mOnBatteryScreenOffTimeBase.writeToParcel(out, uSecUptime, uSecRealtime);
mScreenOnTimer.writeToParcel(out, uSecRealtime);
+ mScreenDozeTimer.writeToParcel(out, uSecRealtime);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].writeToParcel(out, uSecRealtime);
}
@@ -12910,10 +13034,13 @@
out.writeInt(mDischargeAmountScreenOnSinceCharge);
out.writeInt(mDischargeAmountScreenOff);
out.writeInt(mDischargeAmountScreenOffSinceCharge);
+ out.writeInt(mDischargeAmountScreenDoze);
+ out.writeInt(mDischargeAmountScreenDozeSinceCharge);
mDischargeStepTracker.writeToParcel(out);
mChargeStepTracker.writeToParcel(out);
mDischargeCounter.writeToParcel(out);
mDischargeScreenOffCounter.writeToParcel(out);
+ mDischargeScreenDozeCounter.writeToParcel(out);
out.writeLong(mLastWriteTime);
out.writeInt(mRpmStats.size());
@@ -13020,8 +13147,10 @@
pw.println("mOnBatteryScreenOffTimeBase:");
mOnBatteryScreenOffTimeBase.dump(pw, " ");
Printer pr = new PrintWriterPrinter(pw);
- pr.println("*** Screen timer:");
+ pr.println("*** Screen on timer:");
mScreenOnTimer.logState(pr, " ");
+ pr.println("*** Screen doze timer:");
+ mScreenDozeTimer.logState(pr, " ");
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
pr.println("*** Screen brightness #" + i + ":");
mScreenBrightnessTimer[i].logState(pr, " ");
diff --git a/core/java/com/android/internal/util/BitUtils.java b/core/java/com/android/internal/util/BitUtils.java
index 28f12eb..ba80aea 100644
--- a/core/java/com/android/internal/util/BitUtils.java
+++ b/core/java/com/android/internal/util/BitUtils.java
@@ -93,6 +93,10 @@
return s & 0xffff;
}
+ public static int uint16(byte hi, byte lo) {
+ return ((hi & 0xff) << 8) | (lo & 0xff);
+ }
+
public static long uint32(int i) {
return i & 0xffffffffL;
}
diff --git a/core/java/com/android/internal/widget/LinearLayoutManager.java b/core/java/com/android/internal/widget/LinearLayoutManager.java
index d82c746..0000a74 100644
--- a/core/java/com/android/internal/widget/LinearLayoutManager.java
+++ b/core/java/com/android/internal/widget/LinearLayoutManager.java
@@ -168,10 +168,6 @@
/**
* Constructor used when layout manager is set in XML by RecyclerView attribute
* "layoutManager". Defaults to vertical orientation.
- *
- * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_android_orientation
- * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_reverseLayout
- * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_stackFromEnd
*/
public LinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 18f3177..09e37e1 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -40,6 +40,7 @@
#include "android_view_InputChannel.h"
#include "android_view_KeyEvent.h"
+#include "android-base/stringprintf.h"
#include "nativebridge/native_bridge.h"
#include "nativeloader/native_loader.h"
@@ -265,6 +266,8 @@
// ------------------------------------------------------------------------
+static thread_local std::string g_error_msg;
+
static jlong
loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName,
jobject messageQueue, jstring internalDataDir, jstring obbDir,
@@ -277,7 +280,6 @@
ScopedUtfChars pathStr(env, path);
std::unique_ptr<NativeCode> code;
bool needs_native_bridge = false;
- std::string error_msg;
void* handle = OpenNativeLibrary(env,
sdkVersion,
@@ -285,12 +287,12 @@
classLoader,
libraryPath,
&needs_native_bridge,
- &error_msg);
+ &g_error_msg);
if (handle == nullptr) {
ALOGW("NativeActivity LoadNativeLibrary(\"%s\") failed: %s",
pathStr.c_str(),
- error_msg.c_str());
+ g_error_msg.c_str());
return 0;
}
@@ -306,19 +308,22 @@
env->ReleaseStringUTFChars(funcName, funcStr);
if (code->createActivityFunc == NULL) {
- ALOGW("ANativeActivity_onCreate not found");
+ g_error_msg = needs_native_bridge ? NativeBridgeGetError() : dlerror();
+ ALOGW("ANativeActivity_onCreate not found: %s", g_error_msg.c_str());
return 0;
}
code->messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueue);
if (code->messageQueue == NULL) {
- ALOGW("Unable to retrieve native MessageQueue");
+ g_error_msg = "Unable to retrieve native MessageQueue";
+ ALOGW("%s", g_error_msg.c_str());
return 0;
}
int msgpipe[2];
if (pipe(msgpipe)) {
- ALOGW("could not create pipe: %s", strerror(errno));
+ g_error_msg = android::base::StringPrintf("could not create pipe: %s", strerror(errno));
+ ALOGW("%s", g_error_msg.c_str());
return 0;
}
code->mainWorkRead = msgpipe[0];
@@ -334,7 +339,8 @@
code->ANativeActivity::callbacks = &code->callbacks;
if (env->GetJavaVM(&code->vm) < 0) {
- ALOGW("NativeActivity GetJavaVM failed");
+ g_error_msg = "NativeActivity GetJavaVM failed";
+ ALOGW("%s", g_error_msg.c_str());
return 0;
}
code->env = env;
@@ -381,7 +387,9 @@
}
static jstring getDlError_native(JNIEnv* env, jobject clazz) {
- return env->NewStringUTF(dlerror());
+ jstring result = env->NewStringUTF(g_error_msg.c_str());
+ g_error_msg.clear();
+ return result;
}
static void
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a9fda8e..6a9afbc 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3106,6 +3106,13 @@
<permission android:name="android.permission.BIND_APPWIDGET"
android:protectionLevel="signature|privileged" />
+ <!-- Allows an application to bind app's slices and get their
+ content. This content will be surfaced to the
+ user and not to leave the device.
+ <p>Not for use by third-party applications. @hide -->
+ <permission android:name="android.permission.BIND_SLICE"
+ android:protectionLevel="signature|privileged|development" />
+
<!-- @SystemApi Private permission, to restrict who can bring up a dialog to add a new
keyguard widget
@hide -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6bf5c63..dcb56a2 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3092,4 +3092,8 @@
booted. -->
<integer name="config_stableDeviceDisplayWidth">-1</integer>
<integer name="config_stableDeviceDisplayHeight">-1</integer>
+
+ <!-- Decide whether to display 'No service' on status bar instead of 'Emergency calls only'
+ when SIM is unready. -->
+ <bool name="config_display_no_service_when_sim_unready">false</bool>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a5dbe26..cc74f17 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3099,4 +3099,5 @@
<java-symbol type="integer" name="config_stableDeviceDisplayWidth" />
<java-symbol type="integer" name="config_stableDeviceDisplayHeight" />
+ <java-symbol type="bool" name="config_display_no_service_when_sim_unready" />
</resources>
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java
index eff6ad9..c611a01 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBackgroundStatsTest.java
@@ -22,6 +22,7 @@
import android.os.WorkSource;
import android.support.test.filters.SmallTest;
import android.util.ArrayMap;
+import android.view.Display;
import junit.framework.TestCase;
@@ -44,7 +45,7 @@
// Off-battery, non-existent
clocks.realtime = clocks.uptime = 10;
cur = clocks.realtime * 1000;
- bi.updateTimeBasesLocked(false, false, cur, cur); // off battery
+ bi.updateTimeBasesLocked(false, Display.STATE_ON, cur, cur); // off battery
assertFalse(bgtb.isRunning());
assertEquals(0, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED));
@@ -65,7 +66,7 @@
// On-battery, background
clocks.realtime = clocks.uptime = 303;
cur = clocks.realtime * 1000;
- bi.updateTimeBasesLocked(true, false, cur, cur); // on battery
+ bi.updateTimeBasesLocked(true, Display.STATE_ON, cur, cur); // on battery
// still in ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
assertTrue(bgtb.isRunning());
assertEquals(0, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED));
@@ -73,7 +74,7 @@
// On-battery, background - but change screen state
clocks.realtime = clocks.uptime = 409;
cur = clocks.realtime * 1000;
- bi.updateTimeBasesLocked(true, true, cur, cur); // on battery (again)
+ bi.updateTimeBasesLocked(true, Display.STATE_OFF, cur, cur); // on battery (again)
assertTrue(bgtb.isRunning());
assertEquals(106_000, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED));
@@ -87,7 +88,7 @@
// Off-battery, foreground
clocks.realtime = clocks.uptime = 530;
cur = clocks.realtime * 1000;
- bi.updateTimeBasesLocked(false, false, cur, cur); // off battery
+ bi.updateTimeBasesLocked(false, Display.STATE_ON, cur, cur); // off battery
bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
assertFalse(bgtb.isRunning());
assertEquals(227_000, bgtb.computeRealtime(cur, STATS_SINCE_CHARGED));
@@ -112,17 +113,17 @@
// battery=off, screen=off, background=off
cur = (clocks.realtime = clocks.uptime = 100) * 1000;
bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
- bi.updateTimeBasesLocked(false, false, cur, cur);
+ bi.updateTimeBasesLocked(false, Display.STATE_ON, cur, cur);
assertFalse(bgtb.isRunning());
// battery=on, screen=off, background=off
cur = (clocks.realtime = clocks.uptime = 200) * 1000;
- bi.updateTimeBasesLocked(true, false, cur, cur);
+ bi.updateTimeBasesLocked(true, Display.STATE_ON, cur, cur);
assertFalse(bgtb.isRunning());
// battery=on, screen=on, background=off
cur = (clocks.realtime = clocks.uptime = 300) * 1000;
- bi.updateTimeBasesLocked(true, true, cur, cur);
+ bi.updateTimeBasesLocked(true, Display.STATE_OFF, cur, cur);
assertFalse(bgtb.isRunning());
// battery=on, screen=on, background=on
@@ -133,12 +134,12 @@
// battery=on, screen=off, background=on
cur = (clocks.realtime = clocks.uptime = 550) * 1000;
- bi.updateTimeBasesLocked(true, false, cur, cur);
+ bi.updateTimeBasesLocked(true, Display.STATE_ON, cur, cur);
assertFalse(bgtb.isRunning());
// battery=off, screen=off, background=on
cur = (clocks.realtime = clocks.uptime = 660) * 1000;
- bi.updateTimeBasesLocked(false, false, cur, cur);
+ bi.updateTimeBasesLocked(false, Display.STATE_ON, cur, cur);
assertFalse(bgtb.isRunning());
// battery=off, screen=off, background=off
@@ -157,7 +158,7 @@
// On battery
curr = 1000 * (clocks.realtime = clocks.uptime = 100);
- bi.updateTimeBasesLocked(true, false, curr, curr); // on battery
+ bi.updateTimeBasesLocked(true, Display.STATE_ON, curr, curr); // on battery
// App in foreground
bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
@@ -171,7 +172,7 @@
// Off battery
curr = 1000 * (clocks.realtime = clocks.uptime = 305);
- bi.updateTimeBasesLocked(false, false, curr, curr); // off battery
+ bi.updateTimeBasesLocked(false, Display.STATE_ON, curr, curr); // off battery
// Stop timer
curr = 1000 * (clocks.realtime = clocks.uptime = 409);
@@ -200,7 +201,7 @@
// On battery
curr = 1000 * (clocks.realtime = clocks.uptime = 100);
- bi.updateTimeBasesLocked(true, false, curr, curr); // on battery
+ bi.updateTimeBasesLocked(true, Display.STATE_ON, curr, curr); // on battery
// App in foreground
bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
@@ -215,7 +216,7 @@
// Off battery
curr = 1000 * (clocks.realtime = clocks.uptime = 305);
- bi.updateTimeBasesLocked(false, false, curr, curr); // off battery
+ bi.updateTimeBasesLocked(false, Display.STATE_ON, curr, curr); // off battery
// Start timer (unoptimized)
curr = 1000 * (clocks.realtime = clocks.uptime = 1000);
@@ -223,7 +224,7 @@
// On battery
curr = 1000 * (clocks.realtime = clocks.uptime = 2001);
- bi.updateTimeBasesLocked(true, false, curr, curr); // on battery
+ bi.updateTimeBasesLocked(true, Display.STATE_ON, curr, curr); // on battery
// Move to foreground
curr = 1000 * (clocks.realtime = clocks.uptime = 3004);
@@ -270,7 +271,7 @@
// On battery
curr = 1000 * (clocks.realtime = clocks.uptime = 100);
- bi.updateTimeBasesLocked(true, false, curr, curr); // on battery
+ bi.updateTimeBasesLocked(true, Display.STATE_ON, curr, curr); // on battery
// App in foreground
bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
@@ -292,7 +293,7 @@
// Off battery
curr = 1000 * (clocks.realtime = clocks.uptime = 305);
- bi.updateTimeBasesLocked(false, false, curr, curr); // off battery
+ bi.updateTimeBasesLocked(false, Display.STATE_ON, curr, curr); // off battery
// Stop timer
curr = 1000 * (clocks.realtime = clocks.uptime = 409);
@@ -331,7 +332,7 @@
// On battery
curr = 1000 * (clocks.realtime = clocks.uptime = 100);
- bi.updateTimeBasesLocked(true, false, curr, curr); // on battery
+ bi.updateTimeBasesLocked(true, Display.STATE_ON, curr, curr); // on battery
// App in foreground
bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
@@ -353,7 +354,7 @@
// Off battery
curr = 1000 * (clocks.realtime = clocks.uptime = 305);
- bi.updateTimeBasesLocked(false, false, curr, curr); // off battery
+ bi.updateTimeBasesLocked(false, Display.STATE_ON, curr, curr); // off battery
// Stop timer
curr = 1000 * (clocks.realtime = clocks.uptime = 409);
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
index 97b54b1..6ff0ab2 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCpuTimesTest.java
@@ -39,6 +39,7 @@
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.SparseLongArray;
+import android.view.Display;
import com.android.internal.util.ArrayUtils;
@@ -179,7 +180,7 @@
@Test
public void testUpdateClusterSpeedTimes() {
// PRECONDITIONS
- updateTimeBasesLocked(true, false, 0, 0);
+ updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
final long[][] clusterSpeedTimesMs = {{20, 30}, {40, 50, 60}};
initKernelCpuSpeedReaders(clusterSpeedTimesMs.length);
for (int i = 0; i < clusterSpeedTimesMs.length; ++i) {
@@ -224,7 +225,7 @@
@Test
public void testReadKernelUidCpuTimesLocked() {
//PRECONDITIONS
- updateTimeBasesLocked(true, false, 0, 0);
+ updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
final int testUserId = 11;
when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
final int[] testUids = getUids(testUserId, new int[] {
@@ -295,7 +296,7 @@
@Test
public void testReadKernelUidCpuTimesLocked_isolatedUid() {
//PRECONDITIONS
- updateTimeBasesLocked(true, false, 0, 0);
+ updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
final int testUserId = 11;
when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
final int isolatedAppId = FIRST_ISOLATED_UID + 27;
@@ -382,7 +383,7 @@
@Test
public void testReadKernelUidCpuTimesLocked_invalidUid() {
//PRECONDITIONS
- updateTimeBasesLocked(true, false, 0, 0);
+ updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
final int testUserId = 11;
final int invalidUserId = 15;
final int invalidUid = UserHandle.getUid(invalidUserId, FIRST_APPLICATION_UID + 99);
@@ -427,7 +428,7 @@
@Test
public void testReadKernelUidCpuTimesLocked_withPartialTimers() {
//PRECONDITIONS
- updateTimeBasesLocked(true, false, 0, 0);
+ updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
final int testUserId = 11;
when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
final int[] testUids = getUids(testUserId, new int[] {
@@ -509,7 +510,7 @@
@Test
public void testReadKernelUidCpuFreqTimesLocked() {
// PRECONDITIONS
- updateTimeBasesLocked(true, false, 0, 0);
+ updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
final int testUserId = 11;
when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
@@ -550,7 +551,7 @@
// Repeat the test when the screen is off.
// PRECONDITIONS
- updateTimeBasesLocked(true, true, 0, 0);
+ updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
final long[][] deltasMs = {
{3, 12, 55, 100, 32},
{3248327490475l, 232349349845043l, 123, 2398, 0},
@@ -584,7 +585,7 @@
@Test
public void testReadKernelUidCpuFreqTimesLocked_perClusterTimesAvailable() {
// PRECONDITIONS
- updateTimeBasesLocked(true, false, 0, 0);
+ updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
final int testUserId = 11;
when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
@@ -644,7 +645,7 @@
// Repeat the test when the screen is off.
// PRECONDITIONS
- updateTimeBasesLocked(true, true, 0, 0);
+ updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
final long[][] deltasMs = {
{3, 12, 55, 100, 32},
{3248327490475l, 232349349845043l, 123, 2398, 0},
@@ -688,7 +689,7 @@
@Test
public void testReadKernelUidCpuFreqTimesLocked_partialTimers() {
// PRECONDITIONS
- updateTimeBasesLocked(true, false, 0, 0);
+ updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
final int testUserId = 11;
when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
@@ -792,7 +793,7 @@
@Test
public void testReadKernelUidCpuFreqTimesLocked_freqsChanged() {
// PRECONDITIONS
- updateTimeBasesLocked(true, false, 0, 0);
+ updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
final int testUserId = 11;
when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
@@ -833,7 +834,7 @@
// Repeat the test with the freqs from proc file changed.
// PRECONDITIONS
- updateTimeBasesLocked(true, true, 0, 0);
+ updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
final long[][] deltasMs = {
{3, 12, 55, 100, 32, 34984, 27983},
{3248327490475l, 232349349845043l, 123, 2398, 0, 398, 0},
@@ -867,7 +868,7 @@
@Test
public void testReadKernelUidCpuFreqTimesLocked_isolatedUid() {
// PRECONDITIONS
- updateTimeBasesLocked(true, false, 0, 0);
+ updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
final int testUserId = 11;
when(mUserInfoProvider.exists(testUserId)).thenReturn(true);
@@ -961,7 +962,7 @@
@Test
public void testReadKernelUiidCpuFreqTimesLocked_invalidUid() {
// PRECONDITIONS
- updateTimeBasesLocked(true, false, 0, 0);
+ updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
final int testUserId = 11;
final int invalidUserId = 15;
@@ -1008,12 +1009,12 @@
verify(mKernelUidCpuFreqTimeReader).removeUid(invalidUid);
}
- private void updateTimeBasesLocked(boolean unplugged, boolean screenOff,
+ private void updateTimeBasesLocked(boolean unplugged, int screenState,
long upTime, long realTime) {
// Set PowerProfile=null before calling updateTimeBasesLocked to avoid execution of
// BatteryStatsImpl.updateCpuTimeLocked
mBatteryStatsImpl.setPowerProfile(null);
- mBatteryStatsImpl.updateTimeBasesLocked(unplugged, screenOff, upTime, realTime);
+ mBatteryStatsImpl.updateTimeBasesLocked(unplugged, screenState, upTime, realTime);
mBatteryStatsImpl.setPowerProfile(mPowerProfile);
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index 7769e69..461d537 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -19,9 +19,11 @@
import static android.os.BatteryStats.WAKE_TYPE_PARTIAL;
import android.app.ActivityManager;
+import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.WorkSource;
import android.support.test.filters.SmallTest;
+import android.view.Display;
import junit.framework.TestCase;
@@ -50,7 +52,7 @@
@SmallTest
public void testNoteBluetoothScanResultLocked() throws Exception {
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(new MockClocks());
- bi.updateTimeBasesLocked(true, true, 0, 0);
+ bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
bi.noteBluetoothScanResultsFromSourceLocked(WS, 1);
@@ -82,7 +84,7 @@
int pid = 10;
String name = "name";
- bi.updateTimeBasesLocked(true, true, 0, 0);
+ bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
bi.getUidStatsLocked(UID).noteStartWakeLocked(pid, name, WAKE_TYPE_PARTIAL, clocks.realtime);
@@ -124,7 +126,7 @@
stateRuntimeMap.put(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT, 5309);
stateRuntimeMap.put(ActivityManager.PROCESS_STATE_CACHED_EMPTY, 42);
- bi.updateTimeBasesLocked(true, false, 0, 0);
+ bi.updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
for (Map.Entry<Integer, Integer> entry : stateRuntimeMap.entrySet()) {
bi.noteUidProcessStateLocked(UID, entry.getKey());
@@ -189,4 +191,46 @@
expectedRunTimeMs = stateRuntimeMap.get(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
assertEquals(expectedRunTimeMs * 1000, actualRunTimeUs);
}
+
+ /** Test BatteryStatsImpl.updateTimeBasesLocked. */
+ @SmallTest
+ public void testUpdateTimeBasesLocked() throws Exception {
+ final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+
+ bi.updateTimeBasesLocked(false, Display.STATE_OFF, 0, 0);
+ assertFalse(bi.getOnBatteryTimeBase().isRunning());
+ bi.updateTimeBasesLocked(false, Display.STATE_DOZE, 10, 10);
+ assertFalse(bi.getOnBatteryTimeBase().isRunning());
+ bi.updateTimeBasesLocked(false, Display.STATE_ON, 20, 20);
+ assertFalse(bi.getOnBatteryTimeBase().isRunning());
+
+ bi.updateTimeBasesLocked(true, Display.STATE_ON, 30, 30);
+ assertTrue(bi.getOnBatteryTimeBase().isRunning());
+ assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning());
+ bi.updateTimeBasesLocked(true, Display.STATE_DOZE, 40, 40);
+ assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning());
+ bi.updateTimeBasesLocked(true, Display.STATE_OFF, 40, 40);
+ assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning());
+ }
+
+ /** Test BatteryStatsImpl.noteScreenStateLocked. */
+ @SmallTest
+ public void testNoteScreenStateLocked() throws Exception {
+ final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+
+ bi.updateTimeBasesLocked(true, Display.STATE_ON, 0, 0);
+ bi.noteScreenStateLocked(Display.STATE_ON);
+ bi.noteScreenStateLocked(Display.STATE_DOZE);
+ assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning());
+ assertEquals(bi.getScreenState(), Display.STATE_DOZE);
+ bi.noteScreenStateLocked(Display.STATE_ON);
+ assertFalse(bi.getOnBatteryScreenOffTimeBase().isRunning());
+ assertEquals(bi.getScreenState(), Display.STATE_ON);
+ bi.noteScreenStateLocked(Display.STATE_OFF);
+ assertTrue(bi.getOnBatteryScreenOffTimeBase().isRunning());
+ assertEquals(bi.getScreenState(), Display.STATE_OFF);
+ }
+
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
index 0294095..a751f90 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java
@@ -18,6 +18,7 @@
import android.app.ActivityManager;
import android.os.BatteryStats;
import android.support.test.filters.SmallTest;
+import android.view.Display;
import junit.framework.TestCase;
@@ -74,7 +75,7 @@
// Plugged-in (battery=off, sensor=off)
curr = 1000 * (clocks.realtime = clocks.uptime = 100);
- bi.updateTimeBasesLocked(false, false, curr, curr);
+ bi.updateTimeBasesLocked(false, Display.STATE_ON, curr, curr);
// Start sensor (battery=off, sensor=on)
@@ -110,7 +111,7 @@
// Unplugged (battery=on, sensor=off)
curr = 1000 * (clocks.realtime = clocks.uptime = 100);
- bi.updateTimeBasesLocked(true, false, curr, curr);
+ bi.updateTimeBasesLocked(true, Display.STATE_ON, curr, curr);
// Start sensor (battery=on, sensor=on)
curr = 1000 * (clocks.realtime = clocks.uptime = 200);
@@ -145,7 +146,7 @@
// On battery (battery=on, sensor=off)
curr = 1000 * (clocks.realtime = clocks.uptime = 100);
- bi.updateTimeBasesLocked(true, false, curr, curr);
+ bi.updateTimeBasesLocked(true, Display.STATE_ON, curr, curr);
bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
// Start sensor (battery=on, sensor=on)
@@ -154,7 +155,7 @@
// Off battery (battery=off, sensor=on)
curr = 1000 * (clocks.realtime = clocks.uptime = 305);
- bi.updateTimeBasesLocked(false, false, curr, curr);
+ bi.updateTimeBasesLocked(false, Display.STATE_ON, curr, curr);
// Stop sensor while off battery (battery=off, sensor=off)
curr = 1000 * (clocks.realtime = clocks.uptime = 409);
@@ -191,7 +192,7 @@
// Plugged-in (battery=off, sensor=off)
curr = 1000 * (clocks.realtime = clocks.uptime = 100);
- bi.updateTimeBasesLocked(false, false, curr, curr);
+ bi.updateTimeBasesLocked(false, Display.STATE_ON, curr, curr);
// Start sensor (battery=off, sensor=on)
curr = 1000 * (clocks.realtime = clocks.uptime = 200);
@@ -209,7 +210,7 @@
// Unplug (battery=on, sensor=on)
curr = 1000 * (clocks.realtime = clocks.uptime = 305);
- bi.updateTimeBasesLocked(true, false, curr, curr);
+ bi.updateTimeBasesLocked(true, Display.STATE_ON, curr, curr);
//Test situation
curr = 1000 * (clocks.realtime = clocks.uptime = 410);
@@ -243,7 +244,7 @@
long curr = 0; // realtime in us
// Entire test is on-battery
curr = 1000 * (clocks.realtime = clocks.uptime = 1000);
- bi.updateTimeBasesLocked(true, false, curr, curr);
+ bi.updateTimeBasesLocked(true, Display.STATE_ON, curr, curr);
// See below for a diagram of events.
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index 73ee3e5..63d1e5a 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -28,6 +28,10 @@
MockBatteryStatsImpl(Clocks clocks) {
super(clocks);
this.clocks = mClocks;
+ mScreenOnTimer = new BatteryStatsImpl.StopwatchTimer(clocks, null, -1, null,
+ mOnBatteryTimeBase);
+ mScreenDozeTimer = new BatteryStatsImpl.StopwatchTimer(clocks, null, -1, null,
+ mOnBatteryTimeBase);
mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
}
@@ -39,6 +43,14 @@
return mOnBatteryTimeBase;
}
+ public TimeBase getOnBatteryScreenOffTimeBase() {
+ return mOnBatteryScreenOffTimeBase;
+ }
+
+ public int getScreenState() {
+ return mScreenState;
+ }
+
public boolean isOnBattery() {
return mForceOnBattery ? true : super.isOnBattery();
}
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index 5c6078d..3b72a8b 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -72,15 +72,23 @@
textureMatrixInv = textureMatrix;
}
- SkMatrix matrix = SkMatrix::Concat(textureMatrixInv, layerTransform);
+ SkMatrix matrix = SkMatrix::Concat(layerTransform, textureMatrixInv);
SkPaint paint;
paint.setAlpha(layer->getAlpha());
paint.setBlendMode(layer->getMode());
paint.setColorFilter(sk_ref_sp(layer->getColorFilter()));
- // draw image with a shader to avoid save/restore of the matrix
- paint.setShader(layerImage->makeShader(&matrix));
- canvas->drawRect(SkRect::MakeWH(layerWidth, layerHeight), paint);
+
+ const bool nonIdentityMatrix = !matrix.isIdentity();
+ if (nonIdentityMatrix) {
+ canvas->save();
+ canvas->concat(matrix);
+ }
+ canvas->drawImage(layerImage.get(), 0, 0, &paint);
+ // restore the original matrix
+ if (nonIdentityMatrix) {
+ canvas->restore();
+ }
}
return layerImage;
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 1f5edfa..ba41a7b 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -2584,22 +2584,21 @@
ExifAttribute.createUShort(Integer.parseInt(height), mExifByteOrder));
}
- // Note that the rotation angle from MediaMetadataRetriever for heif images
- // are CCW, while rotation in ExifInterface orientations are CW.
String rotation = retriever.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
if (rotation != null) {
int orientation = ExifInterface.ORIENTATION_NORMAL;
+ // all rotation angles in CW
switch (Integer.parseInt(rotation)) {
case 90:
- orientation = ExifInterface.ORIENTATION_ROTATE_270;
+ orientation = ExifInterface.ORIENTATION_ROTATE_90;
break;
case 180:
orientation = ExifInterface.ORIENTATION_ROTATE_180;
break;
case 270:
- orientation = ExifInterface.ORIENTATION_ROTATE_90;
+ orientation = ExifInterface.ORIENTATION_ROTATE_270;
break;
}
diff --git a/native/webview/loader/loader.cpp b/native/webview/loader/loader.cpp
index 376dbb8..adb371d 100644
--- a/native/webview/loader/loader.cpp
+++ b/native/webview/loader/loader.cpp
@@ -143,17 +143,7 @@
return DoReserveAddressSpace(size);
}
-jboolean CreateRelroFile(JNIEnv* env, jclass, jstring lib32, jstring lib64,
- jstring relro32, jstring relro64) {
-#ifdef __LP64__
- jstring lib = lib64;
- jstring relro = relro64;
- (void)lib32; (void)relro32;
-#else
- jstring lib = lib32;
- jstring relro = relro32;
- (void)lib64; (void)relro64;
-#endif
+jboolean CreateRelroFile(JNIEnv* env, jclass, jstring lib, jstring relro) {
jboolean ret = JNI_FALSE;
const char* lib_utf8 = env->GetStringUTFChars(lib, NULL);
if (lib_utf8 != NULL) {
@@ -167,15 +157,8 @@
return ret;
}
-jint LoadWithRelroFile(JNIEnv* env, jclass, jstring lib, jstring relro32,
- jstring relro64, jobject clazzLoader) {
-#ifdef __LP64__
- jstring relro = relro64;
- (void)relro32;
-#else
- jstring relro = relro32;
- (void)relro64;
-#endif
+jint LoadWithRelroFile(JNIEnv* env, jclass, jstring lib, jstring relro,
+ jobject clazzLoader) {
jint ret = LIBLOAD_FAILED_JNI_CALL;
const char* lib_utf8 = env->GetStringUTFChars(lib, NULL);
if (lib_utf8 != NULL) {
@@ -196,10 +179,10 @@
{ "nativeReserveAddressSpace", "(J)Z",
reinterpret_cast<void*>(ReserveAddressSpace) },
{ "nativeCreateRelroFile",
- "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z",
+ "(Ljava/lang/String;Ljava/lang/String;)Z",
reinterpret_cast<void*>(CreateRelroFile) },
{ "nativeLoadWithRelroFile",
- "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)I",
+ "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)I",
reinterpret_cast<void*>(LoadWithRelroFile) },
};
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index 7225ba9..432b406 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -66,7 +66,11 @@
// again when the PUK locked SIM is re-entered.
case ABSENT: {
KeyguardUpdateMonitor.getInstance(getContext()).reportSimUnlocked(mSubId);
- mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ // onSimStateChanged callback can fire when the SIM PIN lock is not currently
+ // active and mCallback is null.
+ if (mCallback != null) {
+ mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ }
break;
}
default:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index 171cf23..7f79008 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -72,7 +72,11 @@
// move into the READY state and the PUK lock keyguard should be removed.
case READY: {
KeyguardUpdateMonitor.getInstance(getContext()).reportSimUnlocked(mSubId);
- mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ // mCallback can be null if onSimStateChanged callback is called when keyguard
+ // isn't active.
+ if (mCallback != null) {
+ mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ }
break;
}
default:
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index f545556..86b7790 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -358,6 +358,9 @@
mScrimViews = new SystemBarScrimViews(this);
getWindow().getAttributes().privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
+ if (Recents.getConfiguration().isLowRamDevice) {
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ }
mLastConfig = new Configuration(Utilities.getAppConfiguration(this));
mFocusTimerDuration = getResources().getInteger(R.integer.recents_auto_advance_duration);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 2cff79d..561fbb2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -796,6 +796,24 @@
}
}
+ /**
+ * This method returns the drawing rect for the view which is different from the regular
+ * drawing rect, since we layout all children at position 0 and usually the translation is
+ * neglected. The standard implementation doesn't account for translation.
+ *
+ * @param outRect The (scrolled) drawing bounds of the view.
+ */
+ @Override
+ public void getDrawingRect(Rect outRect) {
+ super.getDrawingRect(outRect);
+ float translationX = getTranslationX();
+ float translationY = getTranslationY();
+ outRect.left += translationX;
+ outRect.right += translationX;
+ outRect.top += translationY;
+ outRect.bottom += translationY;
+ }
+
public void setIsInShelf(boolean isInShelf) {
mIsInShelf = isInShelf;
}
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 c191618..7b11ace 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -667,7 +667,7 @@
return false;
}
initDownStates(event);
- if (mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
+ if (mBar.panelEnabled() && mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
mIsExpansionFromHeadsUp = true;
MetricsLogger.count(mContext, COUNTER_PANEL_OPEN, 1);
MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_PEEK, 1);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 54b4e35..d3bb17f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -479,7 +479,8 @@
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
// ensure quick settings is disabled until the current user makes it through the setup wizard
- private boolean mUserSetup = false;
+ @VisibleForTesting
+ protected boolean mUserSetup = false;
private final DeviceProvisionedListener mUserSetupObserver = new DeviceProvisionedListener() {
@Override
public void onUserSetupChanged() {
@@ -1978,6 +1979,7 @@
mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned()
&& (mUserSetup || mUserSwitcherController == null
|| !mUserSwitcherController.isSimpleUserSwitcher())
+ && ((mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0)
&& ((mDisabled2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) == 0)
&& !mDozing
&& !ONLY_CORE_APPS);
@@ -2533,6 +2535,8 @@
flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS)) ? '!' : ' ');
flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_SYSTEM_ICONS)) ? 'I' : 'i');
flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_SYSTEM_ICONS)) ? '!' : ' ');
+ flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE)) ? 'N' : 'n');
+ flagdbg.append(0 != ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE)) ? '!' : ' ');
flagdbg.append('>');
Log.d(TAG, flagdbg.toString());
@@ -2559,6 +2563,13 @@
if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) {
updateQsExpansionEnabled();
}
+
+ if ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
+ updateQsExpansionEnabled();
+ if ((state1 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
+ animateCollapsePanels();
+ }
+ }
}
/**
@@ -2915,7 +2926,9 @@
}
boolean panelsEnabled() {
- return (mDisabled1 & StatusBarManager.DISABLE_EXPAND) == 0 && !ONLY_CORE_APPS;
+ return (mDisabled1 & StatusBarManager.DISABLE_EXPAND) == 0
+ && (mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0
+ && !ONLY_CORE_APPS;
}
void makeExpandedVisible(boolean force) {
@@ -4844,6 +4857,10 @@
* @param expandView The view to expand after going to the shade.
*/
public void goToLockedShade(View expandView) {
+ if ((mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
+ return;
+ }
+
int userId = mCurrentUserId;
ExpandableNotificationRow row = null;
if (expandView instanceof ExpandableNotificationRow) {
@@ -5732,6 +5749,11 @@
}
private boolean handleRemoteInput(View view, PendingIntent pendingIntent) {
+ if ((mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
+ // Skip remote input as doing so will expand the notification shade.
+ return true;
+ }
+
Object tag = view.getTag(com.android.internal.R.id.remote_input_tag);
RemoteInput[] inputs = null;
if (tag instanceof RemoteInput[]) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index c0de004..3b401a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -21,9 +21,11 @@
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import com.android.internal.app.NightDisplayController;
+import com.android.systemui.Dependency;
import com.android.systemui.Prefs;
import com.android.systemui.Prefs.Key;
import com.android.systemui.SysuiTestCase;
@@ -45,6 +47,8 @@
@Before
public void setUp() throws Exception {
+ mDependency.injectTestDependency(Dependency.BG_LOOPER,
+ TestableLooper.get(this).getLooper());
Prefs.putBoolean(mContext, Key.QS_NIGHTDISPLAY_ADDED, false);
mQsTileHost = Mockito.mock(QSTileHost.class);
mAutoTileManager = new AutoTileManager(mContext, mQsTileHost);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index ac367d2..899e873 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -34,8 +34,8 @@
import static org.mockito.Mockito.when;
import android.app.Notification;
+import android.app.StatusBarManager;
import android.app.trust.TrustManager;
-import android.content.Context;
import android.hardware.fingerprint.FingerprintManager;
import android.metrics.LogMaker;
import android.os.Binder;
@@ -50,21 +50,17 @@
import android.support.test.filters.SmallTest;
import android.support.test.metricshelper.MetricsAsserts;
import android.testing.AndroidTestingRunner;
-import android.testing.LayoutInflaterBuilder;
import android.testing.TestableLooper;
import android.testing.TestableLooper.MessageHandler;
import android.testing.TestableLooper.RunWithLooper;
import android.util.DisplayMetrics;
-import android.view.View;
import android.view.ViewGroup.LayoutParams;
-import android.widget.FrameLayout;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.logging.testing.FakeMetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.keyguard.KeyguardHostView.OnDismissAction;
-import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.assist.AssistManager;
@@ -76,7 +72,6 @@
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationData.Entry;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.policy.DateView;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -496,6 +491,28 @@
}
@Test
+ public void testDisableExpandStatusBar() {
+ mStatusBar.setBarStateForTest(StatusBarState.SHADE);
+ mStatusBar.setUserSetupForTest(true);
+ when(mStatusBar.isDeviceProvisioned()).thenReturn(true);
+
+ mStatusBar.disable(StatusBarManager.DISABLE_NONE,
+ StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false);
+ verify(mNotificationPanelView).setQsExpansionEnabled(false);
+ mStatusBar.animateExpandNotificationsPanel();
+ verify(mNotificationPanelView, never()).expand(anyBoolean());
+ mStatusBar.animateExpandSettingsPanel(null);
+ verify(mNotificationPanelView, never()).expand(anyBoolean());
+
+ mStatusBar.disable(StatusBarManager.DISABLE_NONE, StatusBarManager.DISABLE2_NONE, false);
+ verify(mNotificationPanelView).setQsExpansionEnabled(true);
+ mStatusBar.animateExpandNotificationsPanel();
+ verify(mNotificationPanelView).expand(anyBoolean());
+ mStatusBar.animateExpandSettingsPanel(null);
+ verify(mNotificationPanelView).expand(anyBoolean());
+ }
+
+ @Test
public void testDump_DoesNotCrash() {
mStatusBar.dump(null, new PrintWriter(new ByteArrayOutputStream()), null);
}
@@ -546,5 +563,9 @@
public void setBarStateForTest(int state) {
mState = state;
}
+
+ public void setUserSetupForTest(boolean userSetup) {
+ mUserSetup = userSetup;
+ }
}
}
\ No newline at end of file
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 11478fe..ed00ffe 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -56,9 +56,11 @@
import android.service.autofill.FillContext;
import android.service.autofill.FillRequest;
import android.service.autofill.FillResponse;
+import android.service.autofill.InternalSanitizer;
import android.service.autofill.InternalValidator;
import android.service.autofill.SaveInfo;
import android.service.autofill.SaveRequest;
+import android.service.autofill.Transformation;
import android.service.autofill.ValueFinder;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -856,6 +858,8 @@
return true;
}
+ final ArrayMap<AutofillId, InternalSanitizer> sanitizers = createSanitizers(saveInfo);
+
// Cache used to make sure changed fields do not belong to a dataset.
final ArrayMap<AutofillId, AutofillValue> currentValues = new ArrayMap<>();
final ArraySet<AutofillId> allIds = new ArraySet<>();
@@ -895,6 +899,7 @@
break;
}
}
+ value = getSanitizedValue(sanitizers, id, value);
currentValues.put(id, value);
final AutofillValue filledValue = viewState.getAutofilledValue();
@@ -1037,6 +1042,48 @@
return true;
}
+ @Nullable
+ private ArrayMap<AutofillId, InternalSanitizer> createSanitizers(@Nullable SaveInfo saveInfo) {
+ if (saveInfo == null) return null;
+
+ final InternalSanitizer[] sanitizerKeys = saveInfo.getSanitizerKeys();
+ if (sanitizerKeys == null) return null;
+
+ final int size = sanitizerKeys.length ;
+ final ArrayMap<AutofillId, InternalSanitizer> sanitizers = new ArrayMap<>(size);
+ if (sDebug) Slog.d(TAG, "Service provided " + size + " sanitizers");
+ final AutofillId[][] sanitizerValues = saveInfo.getSanitizerValues();
+ for (int i = 0; i < size; i++) {
+ final InternalSanitizer sanitizer = sanitizerKeys[i];
+ final AutofillId[] ids = sanitizerValues[i];
+ if (sDebug) {
+ Slog.d(TAG, "sanitizer #" + i + " (" + sanitizer + ") for ids "
+ + Arrays.toString(ids));
+ }
+ for (AutofillId id : ids) {
+ sanitizers.put(id, sanitizer);
+ }
+ }
+ return sanitizers;
+ }
+
+ @NonNull
+ private AutofillValue getSanitizedValue(
+ @Nullable ArrayMap<AutofillId, InternalSanitizer> sanitizers,
+ @NonNull AutofillId id,
+ @NonNull AutofillValue value) {
+ if (sanitizers == null) return value;
+
+ final InternalSanitizer sanitizer = sanitizers.get(id);
+ if (sanitizer == null) {
+ return value;
+ }
+
+ final AutofillValue sanitized = sanitizer.sanitize(value);
+ if (sDebug) Slog.d(TAG, "Value for " + id + "(" + value + ") sanitized to " + sanitized);
+ return sanitized;
+ }
+
/**
* Returns whether the session is currently showing the save UI
*/
@@ -1100,6 +1147,9 @@
return;
}
+ final ArrayMap<AutofillId, InternalSanitizer> sanitizers =
+ createSanitizers(getSaveInfoLocked());
+
final int numContexts = mContexts.size();
for (int contextNum = 0; contextNum < numContexts; contextNum++) {
@@ -1126,7 +1176,9 @@
}
if (sVerbose) Slog.v(TAG, "callSaveLocked(): updating " + id + " to " + value);
- node.updateAutofillValue(value);
+ final AutofillValue sanitizedValue = getSanitizedValue(sanitizers, id, value);
+
+ node.updateAutofillValue(sanitizedValue);
}
// Sanitize structure before it's sent to service.
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 371e74d..bf442dc 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -55,6 +55,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.regex.Pattern;
final class FillUi {
private static final String TAG = "FillUi";
@@ -164,15 +165,18 @@
Slog.e(TAG, "Error inflating remote views", e);
continue;
}
- final AutofillValue value = dataset.getFieldValues().get(index);
+ final Pattern filter = dataset.getFilter(index);
String valueText = null;
- // If the dataset needs auth - don't add its text to allow guessing
- // its content based on how filtering behaves.
- if (value != null && value.isText() && dataset.getAuthentication() == null) {
- valueText = value.getTextValue().toString().toLowerCase();
+ if (filter == null) {
+ final AutofillValue value = dataset.getFieldValues().get(index);
+ // If the dataset needs auth - don't add its text to allow guessing
+ // its content based on how filtering behaves.
+ if (value != null && value.isText() && dataset.getAuthentication() == null) {
+ valueText = value.getTextValue().toString().toLowerCase();
+ }
}
- items.add(new ViewItem(dataset, valueText, view));
+ items.add(new ViewItem(dataset, filter, valueText, view));
}
}
@@ -331,11 +335,17 @@
private final String mValue;
private final Dataset mDataset;
private final View mView;
+ private final Pattern mFilter;
- ViewItem(Dataset dataset, String value, View view) {
+ ViewItem(Dataset dataset, Pattern filter, String value, View view) {
mDataset = dataset;
mValue = value;
mView = view;
+ mFilter = filter;
+ }
+
+ public Pattern getFilter() {
+ return mFilter;
}
public View getView() {
@@ -349,12 +359,6 @@
public String getValue() {
return mValue;
}
-
- @Override
- public String toString() {
- // Used for filtering in the adapter
- return mValue;
- }
}
private final class AutofillWindowPresenter extends IAutofillWindowPresenter.Stub {
@@ -516,10 +520,16 @@
for (int i = 0; i < itemCount; i++) {
final ViewItem item = mAllItems.get(i);
final String value = item.getValue();
- // No value, i.e. null, matches any filter
- if ((value == null && item.mDataset.getAuthentication() == null)
- || (value != null
- && value.toLowerCase().startsWith(constraintLowerCase))) {
+ final Pattern filter = item.getFilter();
+ final boolean matches;
+ if (filter != null) {
+ matches = filter.matcher(constraintLowerCase).matches();
+ } else {
+ matches = (value == null)
+ ? (item.mDataset.getAuthentication() == null)
+ : value.toLowerCase().startsWith(constraintLowerCase);
+ }
+ if (matches) {
filteredItems.add(item);
}
}
diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
index 14a008e..fe4902f 100644
--- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
@@ -653,7 +653,7 @@
// Persistently track the need to do a full init
private static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
- private ArraySet<String> mPendingInits = new ArraySet<>(); // transport names
+ private final ArraySet<String> mPendingInits = new ArraySet<>(); // transport names
// Round-robin queue for scheduling full backup passes
private static final int SCHEDULE_FILE_VERSION = 1; // current version of the schedule file
diff --git a/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java b/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java
index a6897d0..1df0bf0 100644
--- a/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java
+++ b/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java
@@ -23,6 +23,7 @@
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.util.ArraySet;
import android.util.Slog;
import com.android.server.backup.RefactoredBackupManagerService;
@@ -38,19 +39,22 @@
public void onReceive(Context context, Intent intent) {
if (RUN_INITIALIZE_ACTION.equals(intent.getAction())) {
synchronized (backupManagerService.getQueueLock()) {
+ final ArraySet<String> pendingInits = backupManagerService.getPendingInits();
if (DEBUG) {
- Slog.v(TAG, "Running a device init");
+ Slog.v(TAG, "Running a device init; " + pendingInits.size() + " pending");
}
- String[] pendingInits = (String[]) backupManagerService.getPendingInits().toArray();
- backupManagerService.clearPendingInits();
- PerformInitializeTask initTask = new PerformInitializeTask(backupManagerService,
- pendingInits, null);
+ if (pendingInits.size() > 0) {
+ final String[] transports = pendingInits.toArray(new String[pendingInits.size()]);
+ PerformInitializeTask initTask = new PerformInitializeTask(backupManagerService,
+ transports, null);
- // Acquire the wakelock and pass it to the init thread. it will
- // be released once init concludes.
- backupManagerService.getWakelock().acquire();
- backupManagerService.getBackupHandler().post(initTask);
+ // Acquire the wakelock and pass it to the init thread. it will
+ // be released once init concludes.
+ backupManagerService.clearPendingInits();
+ backupManagerService.getWakelock().acquire();
+ backupManagerService.getBackupHandler().post(initTask);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index abbc89e..3a6478e 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -307,6 +307,12 @@
*/
private int[] mTempWhitelistAppIdArray = new int[0];
+ /**
+ * Apps in the system whitelist that have been taken out (probably because the user wanted to).
+ * They can be restored back by calling restoreAppToSystemWhitelist(String).
+ */
+ private ArrayMap<String, Integer> mRemovedFromSystemWhitelistApps = new ArrayMap<>();
+
private static final int EVENT_NULL = 0;
private static final int EVENT_NORMAL = 1;
private static final int EVENT_LIGHT_IDLE = 2;
@@ -1162,6 +1168,38 @@
}
}
+ @Override public void removeSystemPowerWhitelistApp(String name) {
+ if (DEBUG) {
+ Slog.d(TAG, "removeAppFromSystemWhitelist(name = " + name + ")");
+ }
+ getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
+ null);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ removeSystemPowerWhitelistAppInternal(name);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override public void restoreSystemPowerWhitelistApp(String name) {
+ if (DEBUG) {
+ Slog.d(TAG, "restoreAppToSystemWhitelist(name = " + name + ")");
+ }
+ getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
+ null);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ restoreSystemPowerWhitelistAppInternal(name);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ public String[] getRemovedSystemPowerWhitelistApps() {
+ return getRemovedSystemPowerWhitelistAppsInternal();
+ }
+
@Override public String[] getSystemPowerWhitelistExceptIdle() {
return getSystemPowerWhitelistExceptIdleInternal();
}
@@ -1504,6 +1542,42 @@
}
}
+ void resetSystemPowerWhitelistInternal() {
+ synchronized (this) {
+ mPowerSaveWhitelistApps.putAll(mRemovedFromSystemWhitelistApps);
+ mRemovedFromSystemWhitelistApps.clear();
+ reportPowerSaveWhitelistChangedLocked();
+ updateWhitelistAppIdsLocked();
+ writeConfigFileLocked();
+ }
+ }
+
+ public boolean restoreSystemPowerWhitelistAppInternal(String name) {
+ synchronized (this) {
+ if (!mRemovedFromSystemWhitelistApps.containsKey(name)) {
+ return false;
+ }
+ mPowerSaveWhitelistApps.put(name, mRemovedFromSystemWhitelistApps.remove(name));
+ reportPowerSaveWhitelistChangedLocked();
+ updateWhitelistAppIdsLocked();
+ writeConfigFileLocked();
+ return true;
+ }
+ }
+
+ public boolean removeSystemPowerWhitelistAppInternal(String name) {
+ synchronized (this) {
+ if (!mPowerSaveWhitelistApps.containsKey(name)) {
+ return false;
+ }
+ mRemovedFromSystemWhitelistApps.put(name, mPowerSaveWhitelistApps.remove(name));
+ reportPowerSaveWhitelistChangedLocked();
+ updateWhitelistAppIdsLocked();
+ writeConfigFileLocked();
+ return true;
+ }
+ }
+
public boolean addPowerSaveWhitelistExceptIdleInternal(String name) {
synchronized (this) {
try {
@@ -1565,6 +1639,17 @@
}
}
+ public String[] getRemovedSystemPowerWhitelistAppsInternal() {
+ synchronized (this) {
+ int size = mRemovedFromSystemWhitelistApps.size();
+ final String[] apps = new String[size];
+ for (int i = 0; i < size; i++) {
+ apps[i] = mRemovedFromSystemWhitelistApps.keyAt(i);
+ }
+ return apps;
+ }
+ }
+
public String[] getUserPowerWhitelistInternal() {
synchronized (this) {
int size = mPowerSaveWhitelistUserApps.size();
@@ -2481,21 +2566,31 @@
}
String tagName = parser.getName();
- if (tagName.equals("wl")) {
- String name = parser.getAttributeValue(null, "n");
- if (name != null) {
- try {
- ApplicationInfo ai = pm.getApplicationInfo(name,
- PackageManager.MATCH_ANY_USER);
- mPowerSaveWhitelistUserApps.put(ai.packageName,
- UserHandle.getAppId(ai.uid));
- } catch (PackageManager.NameNotFoundException e) {
+ switch (tagName) {
+ case "wl":
+ String name = parser.getAttributeValue(null, "n");
+ if (name != null) {
+ try {
+ ApplicationInfo ai = pm.getApplicationInfo(name,
+ PackageManager.MATCH_ANY_USER);
+ mPowerSaveWhitelistUserApps.put(ai.packageName,
+ UserHandle.getAppId(ai.uid));
+ } catch (PackageManager.NameNotFoundException e) {
+ }
}
- }
- } else {
- Slog.w(TAG, "Unknown element under <config>: "
- + parser.getName());
- XmlUtils.skipCurrentTag(parser);
+ break;
+ case "un-wl":
+ final String packageName = parser.getAttributeValue(null, "n");
+ if (mPowerSaveWhitelistApps.containsKey(packageName)) {
+ mRemovedFromSystemWhitelistApps.put(packageName,
+ mPowerSaveWhitelistApps.remove(packageName));
+ }
+ break;
+ default:
+ Slog.w(TAG, "Unknown element under <config>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ break;
}
}
@@ -2556,6 +2651,11 @@
out.attribute(null, "n", name);
out.endTag(null, "wl");
}
+ for (int i = 0; i < mRemovedFromSystemWhitelistApps.size(); i++) {
+ out.startTag(null, "un-wl");
+ out.attribute(null, "n", mRemovedFromSystemWhitelistApps.keyAt(i));
+ out.endTag(null, "un-wl");
+ }
out.endTag(null, "config");
out.endDocument();
}
@@ -2584,6 +2684,13 @@
pw.println(" Print currently whitelisted apps.");
pw.println(" whitelist [package ...]");
pw.println(" Add (prefix with +) or remove (prefix with -) packages.");
+ pw.println(" sys-whitelist [package ...|reset]");
+ pw.println(" Prefix the package with '-' to remove it from the system whitelist or '+'"
+ + " to put it back in the system whitelist.");
+ pw.println(" Note that only packages that were"
+ + " earlier removed from the system whitelist can be added back.");
+ pw.println(" reset will reset the whitelist to the original state");
+ pw.println(" Prints the system whitelist if no arguments are specified");
pw.println(" except-idle-whitelist [package ...|reset]");
pw.println(" Prefix the package with '+' to add it to whitelist or "
+ "'=' to check if it is already whitelisted");
@@ -2944,6 +3051,50 @@
} finally {
Binder.restoreCallingIdentity(token);
}
+ } else if ("sys-whitelist".equals(cmd)) {
+ String arg = shell.getNextArg();
+ if (arg != null) {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.DEVICE_POWER, null);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if ("reset".equals(arg)) {
+ resetSystemPowerWhitelistInternal();
+ } else {
+ do {
+ if (arg.length() < 1
+ || (arg.charAt(0) != '-' && arg.charAt(0) != '+')) {
+ pw.println("Package must be prefixed with + or - " + arg);
+ return -1;
+ }
+ final char op = arg.charAt(0);
+ final String pkg = arg.substring(1);
+ switch (op) {
+ case '+':
+ if (restoreSystemPowerWhitelistAppInternal(pkg)) {
+ pw.println("Restored " + pkg);
+ }
+ break;
+ case '-':
+ if (removeSystemPowerWhitelistAppInternal(pkg)) {
+ pw.println("Removed " + pkg);
+ }
+ break;
+ }
+ } while ((arg = shell.getNextArg()) != null);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ } else {
+ synchronized (this) {
+ for (int j=0; j<mPowerSaveWhitelistApps.size(); j++) {
+ pw.print(mPowerSaveWhitelistApps.keyAt(j));
+ pw.print(",");
+ pw.println(mPowerSaveWhitelistApps.valueAt(j));
+ }
+ }
+ }
} else {
return shell.handleDefaultCommands(cmd);
}
@@ -3027,6 +3178,14 @@
pw.println(mPowerSaveWhitelistApps.keyAt(i));
}
}
+ size = mRemovedFromSystemWhitelistApps.size();
+ if (size > 0) {
+ pw.println(" Removed from whitelist system apps:");
+ for (int i = 0; i < size; i++) {
+ pw.print(" ");
+ pw.println(mRemovedFromSystemWhitelistApps.keyAt(i));
+ }
+ }
size = mPowerSaveWhitelistUserApps.size();
if (size > 0) {
pw.println(" Whitelist user apps:");
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 555874c..2e1f142 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -344,7 +344,7 @@
private class ManagedResourceArray<T extends ManagedResource> {
SparseArray<T> mArray = new SparseArray<>();
- T get(int key) {
+ T getAndCheckOwner(int key) {
T val = mArray.get(key);
// The value should never be null unless the resource doesn't exist
// (since we do not allow null resources to be added).
@@ -723,7 +723,7 @@
throws RemoteException {
// We want to non-destructively get so that we can check credentials before removing
// this from the records.
- T record = resArray.get(resourceId);
+ T record = resArray.getAndCheckOwner(resourceId);
if (record == null) {
throw new IllegalArgumentException(
@@ -863,7 +863,8 @@
break;
case IpSecTransform.ENCAP_ESPINUDP:
case IpSecTransform.ENCAP_ESPINUDP_NON_IKE:
- if (mUdpSocketRecords.get(config.getEncapSocketResourceId()) == null) {
+ if (mUdpSocketRecords.getAndCheckOwner(
+ config.getEncapSocketResourceId()) == null) {
throw new IllegalStateException(
"No Encapsulation socket for Resource Id: "
+ config.getEncapSocketResourceId());
@@ -885,7 +886,7 @@
throw new IllegalArgumentException("Encryption and Authentication are both null");
}
- if (mSpiRecords.get(config.getSpiResourceId(direction)) == null) {
+ if (mSpiRecords.getAndCheckOwner(config.getSpiResourceId(direction)) == null) {
throw new IllegalStateException("No SPI for specified Resource Id");
}
}
@@ -913,7 +914,7 @@
UdpSocketRecord socketRecord = null;
encapType = c.getEncapType();
if (encapType != IpSecTransform.ENCAP_NONE) {
- socketRecord = mUdpSocketRecords.get(c.getEncapSocketResourceId());
+ socketRecord = mUdpSocketRecords.getAndCheckOwner(c.getEncapSocketResourceId());
encapLocalPort = socketRecord.getPort();
encapRemotePort = c.getEncapRemotePort();
}
@@ -922,7 +923,7 @@
IpSecAlgorithm auth = c.getAuthentication(direction);
IpSecAlgorithm crypt = c.getEncryption(direction);
- spis[direction] = mSpiRecords.get(c.getSpiResourceId(direction));
+ spis[direction] = mSpiRecords.getAndCheckOwner(c.getSpiResourceId(direction));
int spi = spis[direction].getSpi();
try {
mSrvConfig
@@ -976,7 +977,7 @@
// Synchronize liberally here because we are using ManagedResources in this block
TransformRecord info;
// FIXME: this code should be factored out into a security check + getter
- info = mTransformRecords.get(resourceId);
+ info = mTransformRecords.getAndCheckOwner(resourceId);
if (info == null) {
throw new IllegalArgumentException("Transform " + resourceId + " is not active");
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 340d672..0fd59ea 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -18,7 +18,6 @@
import android.app.ActivityManager;
import android.annotation.NonNull;
-import android.content.pm.PackageManagerInternal;
import android.util.ArrayMap;
import android.util.ArraySet;
import com.android.internal.content.PackageMonitor;
@@ -56,6 +55,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cf564e4..36cdb66 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -263,8 +263,8 @@
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
import android.content.pm.PathPermission;
import android.content.pm.PermissionInfo;
@@ -14579,6 +14579,9 @@
}
sb.append("\n");
}
+ if (process.info.isInstantApp()) {
+ sb.append("Instant-App: true\n");
+ }
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 7eb6eda..34eaab2 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -471,7 +471,8 @@
}
T createStackWindowController(int displayId, boolean onTop, Rect outBounds) {
- return (T) new StackWindowController(mStackId, this, displayId, onTop, outBounds);
+ return (T) new StackWindowController(mStackId, this, displayId, onTop, outBounds,
+ mStackSupervisor.mWindowManager);
}
T getWindowContainerController() {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index d2cc557..42f3550 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1235,7 +1235,7 @@
synchronized (mService) {
return mService.getPackageManagerInternalLocked().resolveIntent(intent, resolvedType,
PackageManager.MATCH_INSTANT | PackageManager.MATCH_DEFAULT_ONLY | flags
- | ActivityManagerService.STOCK_PM_FLAGS, userId);
+ | ActivityManagerService.STOCK_PM_FLAGS, userId, true);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index ccb9181..ed33d58 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1799,15 +1799,8 @@
mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
mVoiceInteractor, !mLaunchTaskBehind /* toTop */);
addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
- if (mLaunchBounds != null) {
- final int stackId = mTargetStack.mStackId;
- if (StackId.resizeStackWithLaunchBounds(stackId)) {
- mService.resizeStack(
- stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1);
- } else {
- mStartActivity.getTask().updateOverrideConfiguration(mLaunchBounds);
- }
- }
+ updateBounds(mStartActivity.getTask(), mLaunchBounds);
+
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
+ " in new task " + mStartActivity.getTask());
} else {
@@ -1971,19 +1964,15 @@
}
if (mLaunchBounds != null) {
- mInTask.updateOverrideConfiguration(mLaunchBounds);
// TODO: Shouldn't we already know what stack to use by the time we get here?
ActivityStack stack = mSupervisor.getLaunchStack(null, null, mInTask, ON_TOP);
if (stack != mInTask.getStack()) {
mInTask.reparent(stack, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE,
DEFER_RESUME, "inTaskToFront");
- stack = mInTask.getStack();
mTargetStack = mInTask.getStack();
}
- if (StackId.resizeStackWithLaunchBounds(stack.mStackId)) {
- mService.resizeStack(
- stack.mStackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1);
- }
+
+ updateBounds(mInTask, mLaunchBounds);
}
mTargetStack.moveTaskToFrontLocked(
@@ -1996,6 +1985,19 @@
return START_SUCCESS;
}
+ void updateBounds(TaskRecord task, Rect bounds) {
+ if (bounds == null) {
+ return;
+ }
+
+ final int stackId = task.getStackId();
+ if (StackId.resizeStackWithLaunchBounds(stackId)) {
+ mService.resizeStack(stackId, bounds, true, !PRESERVE_WINDOWS, ANIMATE, -1);
+ } else {
+ task.updateOverrideConfiguration(bounds);
+ }
+ }
+
private void setTaskToCurrentTopOrCreateNewTask() {
mTargetStack = computeStackFocus(mStartActivity, false, null /* bounds */, mLaunchFlags,
mOptions);
diff --git a/services/core/java/com/android/server/am/PinnedActivityStack.java b/services/core/java/com/android/server/am/PinnedActivityStack.java
index 468b867..2726979 100644
--- a/services/core/java/com/android/server/am/PinnedActivityStack.java
+++ b/services/core/java/com/android/server/am/PinnedActivityStack.java
@@ -43,7 +43,8 @@
@Override
PinnedStackWindowController createStackWindowController(int displayId, boolean onTop,
Rect outBounds) {
- return new PinnedStackWindowController(mStackId, this, displayId, onTop, outBounds);
+ return new PinnedStackWindowController(mStackId, this, displayId, onTop, outBounds,
+ mStackSupervisor.mWindowManager);
}
Rect getDefaultPictureInPictureBounds(float aspectRatio) {
diff --git a/services/core/java/com/android/server/audio/AudioEventLogger.java b/services/core/java/com/android/server/audio/AudioEventLogger.java
index a2c0f76..9ebd75b 100644
--- a/services/core/java/com/android/server/audio/AudioEventLogger.java
+++ b/services/core/java/com/android/server/audio/AudioEventLogger.java
@@ -49,9 +49,9 @@
}
/**
- * Causes the string message for the event to appear in the verbose logcat.
+ * Causes the string message for the event to appear in the logcat.
* Here is an example of how to create a new event (a StringEvent), adding it to the logger
- * (an instance of AudioEventLogger) while also making it show in the verbose logcat:
+ * (an instance of AudioEventLogger) while also making it show in the logcat:
* <pre>
* myLogger.log(
* (new StringEvent("something for logcat and logger")).printLog(MyClass.TAG) );
@@ -60,7 +60,7 @@
* @return the same instance of the event
*/
public Event printLog(String tag) {
- Log.v(tag, eventToString());
+ Log.i(tag, eventToString());
return this;
}
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index 7d742ff..c5f563c7 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -89,6 +89,9 @@
pw.println("\nMediaFocusControl dump time: "
+ DateFormat.getTimeInstance().format(new Date()));
dumpFocusStack(pw);
+ pw.println("\n");
+ // log
+ mEventLogger.dump(pw);
}
//=================================================================
@@ -120,6 +123,14 @@
private final static Object mAudioFocusLock = new Object();
/**
+ * Arbitrary maximum size of audio focus stack to prevent apps OOM'ing this process.
+ */
+ private static final int MAX_STACK_SIZE = 100;
+
+ private static final AudioEventLogger mEventLogger = new AudioEventLogger(50,
+ "focus commands as seen by MediaFocusControl");
+
+ /**
* Discard the current audio focus owner.
* Notify top of audio focus stack that it lost focus (regardless of possibility to reassign
* focus), remove it from the stack, and clear the remote control display.
@@ -643,11 +654,14 @@
protected int requestAudioFocus(AudioAttributes aa, int focusChangeHint, IBinder cb,
IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
int sdk) {
- Log.i(TAG, " AudioFocus requestAudioFocus() from uid/pid " + Binder.getCallingUid()
- + "/" + Binder.getCallingPid()
- + " clientId=" + clientId
- + " req=" + focusChangeHint
- + " flags=0x" + Integer.toHexString(flags));
+ mEventLogger.log((new AudioEventLogger.StringEvent(
+ "requestAudioFocus() from uid/pid " + Binder.getCallingUid()
+ + "/" + Binder.getCallingPid()
+ + " clientId=" + clientId + " callingPack=" + callingPackageName
+ + " req=" + focusChangeHint
+ + " flags=0x" + Integer.toHexString(flags)
+ + " sdk=" + sdk))
+ .printLog(TAG));
// we need a valid binder callback for clients
if (!cb.pingBinder()) {
Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
@@ -660,6 +674,11 @@
}
synchronized(mAudioFocusLock) {
+ if (mFocusStack.size() > MAX_STACK_SIZE) {
+ Log.e(TAG, "Max AudioFocus stack size reached, failing requestAudioFocus()");
+ return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+ }
+
boolean enteringRingOrCall = !mRingOrCallActive
& (AudioSystem.IN_VOICE_COMM_FOCUS_ID.compareTo(clientId) == 0);
if (enteringRingOrCall) { mRingOrCallActive = true; }
@@ -770,10 +789,12 @@
* */
protected int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId, AudioAttributes aa,
String callingPackageName) {
- // AudioAttributes are currently ignored, to be used for zones
- Log.i(TAG, " AudioFocus abandonAudioFocus() from uid/pid " + Binder.getCallingUid()
- + "/" + Binder.getCallingPid()
- + " clientId=" + clientId);
+ // AudioAttributes are currently ignored, to be used for zones / a11y
+ mEventLogger.log((new AudioEventLogger.StringEvent(
+ "abandonAudioFocus() from uid/pid " + Binder.getCallingUid()
+ + "/" + Binder.getCallingPid()
+ + " clientId=" + clientId))
+ .printLog(TAG));
try {
// this will take care of notifying the new focus owner if needed
synchronized(mAudioFocusLock) {
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index 057704a..cff216c 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -596,9 +596,10 @@
}
mNatUpdateCallbacksReceived++;
+ final String natDescription = String.format("%s (%s, %s) -> (%s, %s)",
+ protoName, srcAddr, srcPort, dstAddr, dstPort);
if (DBG) {
- mLog.log(String.format("NAT timeout update: %s (%s, %s) -> (%s, %s)",
- protoName, srcAddr, srcPort, dstAddr, dstPort));
+ mLog.log("NAT timeout update: " + natDescription);
}
final int timeoutSec = connectionTimeoutUpdateSecondsFor(proto);
@@ -609,7 +610,7 @@
NetlinkSocket.sendOneShotKernelMessage(OsConstants.NETLINK_NETFILTER, msg);
} catch (ErrnoException e) {
mNatUpdateNetlinkErrors++;
- mLog.e("Error updating NAT conntrack entry: " + e
+ mLog.e("Error updating NAT conntrack entry >" + natDescription + "<: " + e
+ ", msg: " + NetlinkConstants.hexify(msg));
mLog.log("NAT timeout update callbacks received: " + mNatUpdateCallbacksReceived);
mLog.log("NAT timeout update netlink errors: " + mNatUpdateNetlinkErrors);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 205e828..9cd52d7 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -46,8 +46,8 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ProviderInfo;
import android.content.pm.RegisteredServicesCache;
import android.content.pm.RegisteredServicesCacheListener;
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index ef6de4c..fddb81b 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -98,6 +98,12 @@
public static final int FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 1 << 9;
/**
+ * Flag: This display will destroy its content on removal.
+ * @hide
+ */
+ public static final int FLAG_DESTROY_CONTENT_ON_REMOVAL = 1 << 10;
+
+ /**
* Touch attachment: Display does not receive touch.
*/
public static final int TOUCH_NONE = 0;
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 8756484..d61a418c 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -473,17 +473,18 @@
}
// If the state change was from or to VR, then we need to tell the light
- // so that it can apply appropriate VR brightness settings. This should
- // happen prior to changing the brightness but also if there is no
- // brightness change at all.
+ // so that it can apply appropriate VR brightness settings. Also, update the
+ // brightness so the state is propogated to light.
+ boolean vrModeChange = false;
if ((state == Display.STATE_VR || currentState == Display.STATE_VR) &&
currentState != state) {
setVrMode(state == Display.STATE_VR);
+ vrModeChange = true;
}
// Apply brightness changes given that we are in a non-suspended state.
- if (brightnessChanged) {
+ if (brightnessChanged || vrModeChange) {
setDisplayBrightness(brightness);
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index addad0b..78a5407 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -238,6 +238,9 @@
// For private displays by default content is destroyed on removal.
mBaseDisplayInfo.removeMode = Display.REMOVE_MODE_DESTROY_CONTENT;
}
+ if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_DESTROY_CONTENT_ON_REMOVAL) != 0) {
+ mBaseDisplayInfo.removeMode = Display.REMOVE_MODE_DESTROY_CONTENT;
+ }
if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_PRESENTATION) != 0) {
mBaseDisplayInfo.flags |= Display.FLAG_PRESENTATION;
}
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index d6ab888..f86d576 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -24,6 +24,8 @@
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH;
import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT;
+import static android.hardware.display.DisplayManager
+ .VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL;
import android.content.Context;
import android.hardware.display.IVirtualDisplayCallback;
@@ -363,6 +365,9 @@
if ((mFlags & VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT) != 0) {
mInfo.flags |= DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
}
+ if ((mFlags & VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL) != 0) {
+ mInfo.flags |= DisplayDeviceInfo.FLAG_DESTROY_CONTENT_ON_REMOVAL;
+ }
mInfo.type = Display.TYPE_VIRTUAL;
mInfo.touch = ((mFlags & VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH) == 0) ?
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 8783f47..d7e9cf3 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -231,7 +231,11 @@
if (!TextUtils.isEmpty(id) && !TextUtils.isEmpty(channelName)) {
NotificationChannel channel = new NotificationChannel(id,
channelName, channelImportance);
- channel.populateFromXml(parser);
+ if (forRestore) {
+ channel.populateFromXmlForRestore(parser, mContext);
+ } else {
+ channel.populateFromXml(parser);
+ }
r.channels.put(id, channel);
}
}
@@ -394,7 +398,11 @@
}
for (NotificationChannel channel : r.channels.values()) {
- if (!forBackup || (forBackup && !channel.isDeleted())) {
+ if (forBackup) {
+ if (!channel.isDeleted()) {
+ channel.writeXmlForBackup(out, mContext);
+ }
+ } else {
channel.writeXml(out);
}
}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
deleted file mode 100644
index 59e243a..0000000
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ /dev/null
@@ -1,1246 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.app.ActivityManager;
-import android.app.DownloadManager;
-import android.app.admin.DevicePolicyManager;
-import android.companion.CompanionDeviceManager;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal.PackagesProvider;
-import android.content.pm.PackageManagerInternal.SyncAdapterPackagesProvider;
-import android.content.pm.PackageParser;
-import android.content.pm.ProviderInfo;
-import android.content.pm.ResolveInfo;
-import android.media.RingtoneManager;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.Message;
-import android.os.UserHandle;
-import android.os.storage.StorageManager;
-import android.print.PrintManager;
-import android.provider.CalendarContract;
-import android.provider.ContactsContract;
-import android.provider.MediaStore;
-import android.provider.Telephony.Sms.Intents;
-import android.telephony.TelephonyManager;
-import android.security.Credentials;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.Slog;
-import android.util.Xml;
-import com.android.internal.util.XmlUtils;
-import com.android.server.pm.permission.BasePermission;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static android.os.Process.FIRST_APPLICATION_UID;
-
-/**
- * This class is the policy for granting runtime permissions to
- * platform components and default handlers in the system such
- * that the device is usable out-of-the-box. For example, the
- * shell UID is a part of the system and the Phone app should
- * have phone related permission by default.
- */
-final class DefaultPermissionGrantPolicy {
- private static final String TAG = "DefaultPermGrantPolicy"; // must be <= 23 chars
- private static final boolean DEBUG = false;
-
- private static final int DEFAULT_FLAGS =
- PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_UNINSTALLED_PACKAGES;
-
- private static final String AUDIO_MIME_TYPE = "audio/mpeg";
-
- private static final String TAG_EXCEPTIONS = "exceptions";
- private static final String TAG_EXCEPTION = "exception";
- private static final String TAG_PERMISSION = "permission";
- private static final String ATTR_PACKAGE = "package";
- private static final String ATTR_NAME = "name";
- private static final String ATTR_FIXED = "fixed";
-
- private static final Set<String> PHONE_PERMISSIONS = new ArraySet<>();
- static {
- PHONE_PERMISSIONS.add(Manifest.permission.READ_PHONE_STATE);
- PHONE_PERMISSIONS.add(Manifest.permission.CALL_PHONE);
- PHONE_PERMISSIONS.add(Manifest.permission.READ_CALL_LOG);
- PHONE_PERMISSIONS.add(Manifest.permission.WRITE_CALL_LOG);
- PHONE_PERMISSIONS.add(Manifest.permission.ADD_VOICEMAIL);
- PHONE_PERMISSIONS.add(Manifest.permission.USE_SIP);
- PHONE_PERMISSIONS.add(Manifest.permission.PROCESS_OUTGOING_CALLS);
- }
-
- private static final Set<String> CONTACTS_PERMISSIONS = new ArraySet<>();
- static {
- CONTACTS_PERMISSIONS.add(Manifest.permission.READ_CONTACTS);
- CONTACTS_PERMISSIONS.add(Manifest.permission.WRITE_CONTACTS);
- CONTACTS_PERMISSIONS.add(Manifest.permission.GET_ACCOUNTS);
- }
-
- private static final Set<String> LOCATION_PERMISSIONS = new ArraySet<>();
- static {
- LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_FINE_LOCATION);
- LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION);
- }
-
- private static final Set<String> CALENDAR_PERMISSIONS = new ArraySet<>();
- static {
- CALENDAR_PERMISSIONS.add(Manifest.permission.READ_CALENDAR);
- CALENDAR_PERMISSIONS.add(Manifest.permission.WRITE_CALENDAR);
- }
-
- private static final Set<String> SMS_PERMISSIONS = new ArraySet<>();
- static {
- SMS_PERMISSIONS.add(Manifest.permission.SEND_SMS);
- SMS_PERMISSIONS.add(Manifest.permission.RECEIVE_SMS);
- SMS_PERMISSIONS.add(Manifest.permission.READ_SMS);
- SMS_PERMISSIONS.add(Manifest.permission.RECEIVE_WAP_PUSH);
- SMS_PERMISSIONS.add(Manifest.permission.RECEIVE_MMS);
- SMS_PERMISSIONS.add(Manifest.permission.READ_CELL_BROADCASTS);
- }
-
- private static final Set<String> MICROPHONE_PERMISSIONS = new ArraySet<>();
- static {
- MICROPHONE_PERMISSIONS.add(Manifest.permission.RECORD_AUDIO);
- }
-
- private static final Set<String> CAMERA_PERMISSIONS = new ArraySet<>();
- static {
- CAMERA_PERMISSIONS.add(Manifest.permission.CAMERA);
- }
-
- private static final Set<String> SENSORS_PERMISSIONS = new ArraySet<>();
- static {
- SENSORS_PERMISSIONS.add(Manifest.permission.BODY_SENSORS);
- }
-
- private static final Set<String> STORAGE_PERMISSIONS = new ArraySet<>();
- static {
- STORAGE_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE);
- STORAGE_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
- }
-
- private static final int MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS = 1;
-
- private static final String ACTION_TRACK = "com.android.fitness.TRACK";
-
- private final PackageManagerService mService;
- private final Handler mHandler;
-
- private PackagesProvider mLocationPackagesProvider;
- private PackagesProvider mVoiceInteractionPackagesProvider;
- private PackagesProvider mSmsAppPackagesProvider;
- private PackagesProvider mDialerAppPackagesProvider;
- private PackagesProvider mSimCallManagerPackagesProvider;
- private SyncAdapterPackagesProvider mSyncAdapterPackagesProvider;
-
- private ArrayMap<String, List<DefaultPermissionGrant>> mGrantExceptions;
-
- public DefaultPermissionGrantPolicy(PackageManagerService service) {
- mService = service;
- mHandler = new Handler(mService.mHandlerThread.getLooper()) {
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS) {
- synchronized (mService.mPackages) {
- if (mGrantExceptions == null) {
- mGrantExceptions = readDefaultPermissionExceptionsLPw();
- }
- }
- }
- }
- };
- }
-
- public void setLocationPackagesProviderLPw(PackagesProvider provider) {
- mLocationPackagesProvider = provider;
- }
-
- public void setVoiceInteractionPackagesProviderLPw(PackagesProvider provider) {
- mVoiceInteractionPackagesProvider = provider;
- }
-
- public void setSmsAppPackagesProviderLPw(PackagesProvider provider) {
- mSmsAppPackagesProvider = provider;
- }
-
- public void setDialerAppPackagesProviderLPw(PackagesProvider provider) {
- mDialerAppPackagesProvider = provider;
- }
-
- public void setSimCallManagerPackagesProviderLPw(PackagesProvider provider) {
- mSimCallManagerPackagesProvider = provider;
- }
-
- public void setSyncAdapterPackagesProviderLPw(SyncAdapterPackagesProvider provider) {
- mSyncAdapterPackagesProvider = provider;
- }
-
- public void grantDefaultPermissions(int userId) {
- if (mService.hasSystemFeature(PackageManager.FEATURE_EMBEDDED, 0)) {
- grantAllRuntimePermissions(userId);
- } else {
- grantPermissionsToSysComponentsAndPrivApps(userId);
- grantDefaultSystemHandlerPermissions(userId);
- grantDefaultPermissionExceptions(userId);
- }
- }
-
- private void grantRuntimePermissionsForPackageLocked(int userId, PackageParser.Package pkg) {
- Set<String> permissions = new ArraySet<>();
- for (String permission : pkg.requestedPermissions) {
- BasePermission bp = mService.mSettings.mPermissions.get(permission);
- if (bp != null && bp.isRuntime()) {
- permissions.add(permission);
- }
- }
- if (!permissions.isEmpty()) {
- grantRuntimePermissionsLPw(pkg, permissions, true, userId);
- }
- }
-
- private void grantAllRuntimePermissions(int userId) {
- Log.i(TAG, "Granting all runtime permissions for user " + userId);
- synchronized (mService.mPackages) {
- for (PackageParser.Package pkg : mService.mPackages.values()) {
- grantRuntimePermissionsForPackageLocked(userId, pkg);
- }
- }
- }
-
- public void scheduleReadDefaultPermissionExceptions() {
- mHandler.sendEmptyMessage(MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS);
- }
-
- private void grantPermissionsToSysComponentsAndPrivApps(int userId) {
- Log.i(TAG, "Granting permissions to platform components for user " + userId);
-
- synchronized (mService.mPackages) {
- for (PackageParser.Package pkg : mService.mPackages.values()) {
- if (!isSysComponentOrPersistentPlatformSignedPrivAppLPr(pkg)
- || !doesPackageSupportRuntimePermissions(pkg)
- || pkg.requestedPermissions.isEmpty()) {
- continue;
- }
- grantRuntimePermissionsForPackageLocked(userId, pkg);
- }
- }
- }
-
- private void grantDefaultSystemHandlerPermissions(int userId) {
- Log.i(TAG, "Granting permissions to default platform handlers for user " + userId);
-
- final PackagesProvider locationPackagesProvider;
- final PackagesProvider voiceInteractionPackagesProvider;
- final PackagesProvider smsAppPackagesProvider;
- final PackagesProvider dialerAppPackagesProvider;
- final PackagesProvider simCallManagerPackagesProvider;
- final SyncAdapterPackagesProvider syncAdapterPackagesProvider;
-
- synchronized (mService.mPackages) {
- locationPackagesProvider = mLocationPackagesProvider;
- voiceInteractionPackagesProvider = mVoiceInteractionPackagesProvider;
- smsAppPackagesProvider = mSmsAppPackagesProvider;
- dialerAppPackagesProvider = mDialerAppPackagesProvider;
- simCallManagerPackagesProvider = mSimCallManagerPackagesProvider;
- syncAdapterPackagesProvider = mSyncAdapterPackagesProvider;
- }
-
- String[] voiceInteractPackageNames = (voiceInteractionPackagesProvider != null)
- ? voiceInteractionPackagesProvider.getPackages(userId) : null;
- String[] locationPackageNames = (locationPackagesProvider != null)
- ? locationPackagesProvider.getPackages(userId) : null;
- String[] smsAppPackageNames = (smsAppPackagesProvider != null)
- ? smsAppPackagesProvider.getPackages(userId) : null;
- String[] dialerAppPackageNames = (dialerAppPackagesProvider != null)
- ? dialerAppPackagesProvider.getPackages(userId) : null;
- String[] simCallManagerPackageNames = (simCallManagerPackagesProvider != null)
- ? simCallManagerPackagesProvider.getPackages(userId) : null;
- String[] contactsSyncAdapterPackages = (syncAdapterPackagesProvider != null) ?
- syncAdapterPackagesProvider.getPackages(ContactsContract.AUTHORITY, userId) : null;
- String[] calendarSyncAdapterPackages = (syncAdapterPackagesProvider != null) ?
- syncAdapterPackagesProvider.getPackages(CalendarContract.AUTHORITY, userId) : null;
-
- synchronized (mService.mPackages) {
- // Installer
- PackageParser.Package installerPackage = getSystemPackageLPr(
- mService.mRequiredInstallerPackage);
- if (installerPackage != null
- && doesPackageSupportRuntimePermissions(installerPackage)) {
- grantRuntimePermissionsLPw(installerPackage, STORAGE_PERMISSIONS, true, userId);
- }
-
- // Verifier
- PackageParser.Package verifierPackage = getSystemPackageLPr(
- mService.mRequiredVerifierPackage);
- if (verifierPackage != null
- && doesPackageSupportRuntimePermissions(verifierPackage)) {
- grantRuntimePermissionsLPw(verifierPackage, STORAGE_PERMISSIONS, true, userId);
- grantRuntimePermissionsLPw(verifierPackage, PHONE_PERMISSIONS, false, userId);
- grantRuntimePermissionsLPw(verifierPackage, SMS_PERMISSIONS, false, userId);
- }
-
- // SetupWizard
- PackageParser.Package setupPackage = getSystemPackageLPr(
- mService.mSetupWizardPackage);
- if (setupPackage != null
- && doesPackageSupportRuntimePermissions(setupPackage)) {
- grantRuntimePermissionsLPw(setupPackage, PHONE_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(setupPackage, CONTACTS_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(setupPackage, LOCATION_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(setupPackage, CAMERA_PERMISSIONS, userId);
- }
-
- // Camera
- Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
- PackageParser.Package cameraPackage = getDefaultSystemHandlerActivityPackageLPr(
- cameraIntent, userId);
- if (cameraPackage != null
- && doesPackageSupportRuntimePermissions(cameraPackage)) {
- grantRuntimePermissionsLPw(cameraPackage, CAMERA_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(cameraPackage, MICROPHONE_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(cameraPackage, STORAGE_PERMISSIONS, userId);
- }
-
- // Media provider
- PackageParser.Package mediaStorePackage = getDefaultProviderAuthorityPackageLPr(
- MediaStore.AUTHORITY, userId);
- if (mediaStorePackage != null) {
- grantRuntimePermissionsLPw(mediaStorePackage, STORAGE_PERMISSIONS, true, userId);
- }
-
- // Downloads provider
- PackageParser.Package downloadsPackage = getDefaultProviderAuthorityPackageLPr(
- "downloads", userId);
- if (downloadsPackage != null) {
- grantRuntimePermissionsLPw(downloadsPackage, STORAGE_PERMISSIONS, true, userId);
- }
-
- // Downloads UI
- Intent downloadsUiIntent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
- PackageParser.Package downloadsUiPackage = getDefaultSystemHandlerActivityPackageLPr(
- downloadsUiIntent, userId);
- if (downloadsUiPackage != null
- && doesPackageSupportRuntimePermissions(downloadsUiPackage)) {
- grantRuntimePermissionsLPw(downloadsUiPackage, STORAGE_PERMISSIONS, true, userId);
- }
-
- // Storage provider
- PackageParser.Package storagePackage = getDefaultProviderAuthorityPackageLPr(
- "com.android.externalstorage.documents", userId);
- if (storagePackage != null) {
- grantRuntimePermissionsLPw(storagePackage, STORAGE_PERMISSIONS, true, userId);
- }
-
- // CertInstaller
- Intent certInstallerIntent = new Intent(Credentials.INSTALL_ACTION);
- PackageParser.Package certInstallerPackage = getDefaultSystemHandlerActivityPackageLPr(
- certInstallerIntent, userId);
- if (certInstallerPackage != null
- && doesPackageSupportRuntimePermissions(certInstallerPackage)) {
- grantRuntimePermissionsLPw(certInstallerPackage, STORAGE_PERMISSIONS, true, userId);
- }
-
- // Dialer
- if (dialerAppPackageNames == null) {
- Intent dialerIntent = new Intent(Intent.ACTION_DIAL);
- PackageParser.Package dialerPackage = getDefaultSystemHandlerActivityPackageLPr(
- dialerIntent, userId);
- if (dialerPackage != null) {
- grantDefaultPermissionsToDefaultSystemDialerAppLPr(dialerPackage, userId);
- }
- } else {
- for (String dialerAppPackageName : dialerAppPackageNames) {
- PackageParser.Package dialerPackage = getSystemPackageLPr(dialerAppPackageName);
- if (dialerPackage != null) {
- grantDefaultPermissionsToDefaultSystemDialerAppLPr(dialerPackage, userId);
- }
- }
- }
-
- // Sim call manager
- if (simCallManagerPackageNames != null) {
- for (String simCallManagerPackageName : simCallManagerPackageNames) {
- PackageParser.Package simCallManagerPackage =
- getSystemPackageLPr(simCallManagerPackageName);
- if (simCallManagerPackage != null) {
- grantDefaultPermissionsToDefaultSimCallManagerLPr(simCallManagerPackage,
- userId);
- }
- }
- }
-
- // SMS
- if (smsAppPackageNames == null) {
- Intent smsIntent = new Intent(Intent.ACTION_MAIN);
- smsIntent.addCategory(Intent.CATEGORY_APP_MESSAGING);
- PackageParser.Package smsPackage = getDefaultSystemHandlerActivityPackageLPr(
- smsIntent, userId);
- if (smsPackage != null) {
- grantDefaultPermissionsToDefaultSystemSmsAppLPr(smsPackage, userId);
- }
- } else {
- for (String smsPackageName : smsAppPackageNames) {
- PackageParser.Package smsPackage = getSystemPackageLPr(smsPackageName);
- if (smsPackage != null) {
- grantDefaultPermissionsToDefaultSystemSmsAppLPr(smsPackage, userId);
- }
- }
- }
-
- // Cell Broadcast Receiver
- Intent cbrIntent = new Intent(Intents.SMS_CB_RECEIVED_ACTION);
- PackageParser.Package cbrPackage =
- getDefaultSystemHandlerActivityPackageLPr(cbrIntent, userId);
- if (cbrPackage != null && doesPackageSupportRuntimePermissions(cbrPackage)) {
- grantRuntimePermissionsLPw(cbrPackage, SMS_PERMISSIONS, userId);
- }
-
- // Carrier Provisioning Service
- Intent carrierProvIntent = new Intent(Intents.SMS_CARRIER_PROVISION_ACTION);
- PackageParser.Package carrierProvPackage =
- getDefaultSystemHandlerServicePackageLPr(carrierProvIntent, userId);
- if (carrierProvPackage != null && doesPackageSupportRuntimePermissions(carrierProvPackage)) {
- grantRuntimePermissionsLPw(carrierProvPackage, SMS_PERMISSIONS, false, userId);
- }
-
- // Calendar
- Intent calendarIntent = new Intent(Intent.ACTION_MAIN);
- calendarIntent.addCategory(Intent.CATEGORY_APP_CALENDAR);
- PackageParser.Package calendarPackage = getDefaultSystemHandlerActivityPackageLPr(
- calendarIntent, userId);
- if (calendarPackage != null
- && doesPackageSupportRuntimePermissions(calendarPackage)) {
- grantRuntimePermissionsLPw(calendarPackage, CALENDAR_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(calendarPackage, CONTACTS_PERMISSIONS, userId);
- }
-
- // Calendar provider
- PackageParser.Package calendarProviderPackage = getDefaultProviderAuthorityPackageLPr(
- CalendarContract.AUTHORITY, userId);
- if (calendarProviderPackage != null) {
- grantRuntimePermissionsLPw(calendarProviderPackage, CONTACTS_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(calendarProviderPackage, CALENDAR_PERMISSIONS,
- true, userId);
- grantRuntimePermissionsLPw(calendarProviderPackage, STORAGE_PERMISSIONS, userId);
- }
-
- // Calendar provider sync adapters
- List<PackageParser.Package> calendarSyncAdapters = getHeadlessSyncAdapterPackagesLPr(
- calendarSyncAdapterPackages, userId);
- final int calendarSyncAdapterCount = calendarSyncAdapters.size();
- for (int i = 0; i < calendarSyncAdapterCount; i++) {
- PackageParser.Package calendarSyncAdapter = calendarSyncAdapters.get(i);
- if (doesPackageSupportRuntimePermissions(calendarSyncAdapter)) {
- grantRuntimePermissionsLPw(calendarSyncAdapter, CALENDAR_PERMISSIONS, userId);
- }
- }
-
- // Contacts
- Intent contactsIntent = new Intent(Intent.ACTION_MAIN);
- contactsIntent.addCategory(Intent.CATEGORY_APP_CONTACTS);
- PackageParser.Package contactsPackage = getDefaultSystemHandlerActivityPackageLPr(
- contactsIntent, userId);
- if (contactsPackage != null
- && doesPackageSupportRuntimePermissions(contactsPackage)) {
- grantRuntimePermissionsLPw(contactsPackage, CONTACTS_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(contactsPackage, PHONE_PERMISSIONS, userId);
- }
-
- // Contacts provider sync adapters
- List<PackageParser.Package> contactsSyncAdapters = getHeadlessSyncAdapterPackagesLPr(
- contactsSyncAdapterPackages, userId);
- final int contactsSyncAdapterCount = contactsSyncAdapters.size();
- for (int i = 0; i < contactsSyncAdapterCount; i++) {
- PackageParser.Package contactsSyncAdapter = contactsSyncAdapters.get(i);
- if (doesPackageSupportRuntimePermissions(contactsSyncAdapter)) {
- grantRuntimePermissionsLPw(contactsSyncAdapter, CONTACTS_PERMISSIONS, userId);
- }
- }
-
- // Contacts provider
- PackageParser.Package contactsProviderPackage = getDefaultProviderAuthorityPackageLPr(
- ContactsContract.AUTHORITY, userId);
- if (contactsProviderPackage != null) {
- grantRuntimePermissionsLPw(contactsProviderPackage, CONTACTS_PERMISSIONS,
- true, userId);
- grantRuntimePermissionsLPw(contactsProviderPackage, PHONE_PERMISSIONS,
- true, userId);
- grantRuntimePermissionsLPw(contactsProviderPackage, STORAGE_PERMISSIONS, userId);
- }
-
- // Device provisioning
- Intent deviceProvisionIntent = new Intent(
- DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE);
- PackageParser.Package deviceProvisionPackage =
- getDefaultSystemHandlerActivityPackageLPr(deviceProvisionIntent, userId);
- if (deviceProvisionPackage != null
- && doesPackageSupportRuntimePermissions(deviceProvisionPackage)) {
- grantRuntimePermissionsLPw(deviceProvisionPackage, CONTACTS_PERMISSIONS, userId);
- }
-
- // Maps
- Intent mapsIntent = new Intent(Intent.ACTION_MAIN);
- mapsIntent.addCategory(Intent.CATEGORY_APP_MAPS);
- PackageParser.Package mapsPackage = getDefaultSystemHandlerActivityPackageLPr(
- mapsIntent, userId);
- if (mapsPackage != null
- && doesPackageSupportRuntimePermissions(mapsPackage)) {
- grantRuntimePermissionsLPw(mapsPackage, LOCATION_PERMISSIONS, userId);
- }
-
- // Gallery
- Intent galleryIntent = new Intent(Intent.ACTION_MAIN);
- galleryIntent.addCategory(Intent.CATEGORY_APP_GALLERY);
- PackageParser.Package galleryPackage = getDefaultSystemHandlerActivityPackageLPr(
- galleryIntent, userId);
- if (galleryPackage != null
- && doesPackageSupportRuntimePermissions(galleryPackage)) {
- grantRuntimePermissionsLPw(galleryPackage, STORAGE_PERMISSIONS, userId);
- }
-
- // Email
- Intent emailIntent = new Intent(Intent.ACTION_MAIN);
- emailIntent.addCategory(Intent.CATEGORY_APP_EMAIL);
- PackageParser.Package emailPackage = getDefaultSystemHandlerActivityPackageLPr(
- emailIntent, userId);
- if (emailPackage != null
- && doesPackageSupportRuntimePermissions(emailPackage)) {
- grantRuntimePermissionsLPw(emailPackage, CONTACTS_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(emailPackage, CALENDAR_PERMISSIONS, userId);
- }
-
- // Browser
- PackageParser.Package browserPackage = null;
- String defaultBrowserPackage = mService.getDefaultBrowserPackageName(userId);
- if (defaultBrowserPackage != null) {
- browserPackage = getPackageLPr(defaultBrowserPackage);
- }
- if (browserPackage == null) {
- Intent browserIntent = new Intent(Intent.ACTION_MAIN);
- browserIntent.addCategory(Intent.CATEGORY_APP_BROWSER);
- browserPackage = getDefaultSystemHandlerActivityPackageLPr(
- browserIntent, userId);
- }
- if (browserPackage != null
- && doesPackageSupportRuntimePermissions(browserPackage)) {
- grantRuntimePermissionsLPw(browserPackage, LOCATION_PERMISSIONS, userId);
- }
-
- // Voice interaction
- if (voiceInteractPackageNames != null) {
- for (String voiceInteractPackageName : voiceInteractPackageNames) {
- PackageParser.Package voiceInteractPackage = getSystemPackageLPr(
- voiceInteractPackageName);
- if (voiceInteractPackage != null
- && doesPackageSupportRuntimePermissions(voiceInteractPackage)) {
- grantRuntimePermissionsLPw(voiceInteractPackage,
- CONTACTS_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(voiceInteractPackage,
- CALENDAR_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(voiceInteractPackage,
- MICROPHONE_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(voiceInteractPackage,
- PHONE_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(voiceInteractPackage,
- SMS_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(voiceInteractPackage,
- LOCATION_PERMISSIONS, userId);
- }
- }
- }
-
- if (ActivityManager.isLowRamDeviceStatic()) {
- // Allow voice search on low-ram devices
- Intent globalSearchIntent = new Intent("android.search.action.GLOBAL_SEARCH");
- PackageParser.Package globalSearchPickerPackage =
- getDefaultSystemHandlerActivityPackageLPr(globalSearchIntent, userId);
-
- if (globalSearchPickerPackage != null
- && doesPackageSupportRuntimePermissions(globalSearchPickerPackage)) {
- grantRuntimePermissionsLPw(globalSearchPickerPackage,
- MICROPHONE_PERMISSIONS, true, userId);
- grantRuntimePermissionsLPw(globalSearchPickerPackage,
- LOCATION_PERMISSIONS, true, userId);
- }
- }
-
- // Voice recognition
- Intent voiceRecoIntent = new Intent("android.speech.RecognitionService");
- voiceRecoIntent.addCategory(Intent.CATEGORY_DEFAULT);
- PackageParser.Package voiceRecoPackage = getDefaultSystemHandlerServicePackageLPr(
- voiceRecoIntent, userId);
- if (voiceRecoPackage != null
- && doesPackageSupportRuntimePermissions(voiceRecoPackage)) {
- grantRuntimePermissionsLPw(voiceRecoPackage, MICROPHONE_PERMISSIONS, userId);
- }
-
- // Location
- if (locationPackageNames != null) {
- for (String packageName : locationPackageNames) {
- PackageParser.Package locationPackage = getSystemPackageLPr(packageName);
- if (locationPackage != null
- && doesPackageSupportRuntimePermissions(locationPackage)) {
- grantRuntimePermissionsLPw(locationPackage, CONTACTS_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(locationPackage, CALENDAR_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(locationPackage, MICROPHONE_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(locationPackage, PHONE_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(locationPackage, SMS_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(locationPackage, LOCATION_PERMISSIONS,
- true, userId);
- grantRuntimePermissionsLPw(locationPackage, CAMERA_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(locationPackage, SENSORS_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(locationPackage, STORAGE_PERMISSIONS, userId);
- }
- }
- }
-
- // Music
- Intent musicIntent = new Intent(Intent.ACTION_VIEW);
- musicIntent.addCategory(Intent.CATEGORY_DEFAULT);
- musicIntent.setDataAndType(Uri.fromFile(new File("foo.mp3")),
- AUDIO_MIME_TYPE);
- PackageParser.Package musicPackage = getDefaultSystemHandlerActivityPackageLPr(
- musicIntent, userId);
- if (musicPackage != null
- && doesPackageSupportRuntimePermissions(musicPackage)) {
- grantRuntimePermissionsLPw(musicPackage, STORAGE_PERMISSIONS, userId);
- }
-
- // Home
- Intent homeIntent = new Intent(Intent.ACTION_MAIN);
- homeIntent.addCategory(Intent.CATEGORY_HOME);
- homeIntent.addCategory(Intent.CATEGORY_LAUNCHER_APP);
- PackageParser.Package homePackage = getDefaultSystemHandlerActivityPackageLPr(
- homeIntent, userId);
- if (homePackage != null
- && doesPackageSupportRuntimePermissions(homePackage)) {
- grantRuntimePermissionsLPw(homePackage, LOCATION_PERMISSIONS, false, userId);
- }
-
- // Watches
- if (mService.hasSystemFeature(PackageManager.FEATURE_WATCH, 0)) {
- // Home application on watches
- Intent wearHomeIntent = new Intent(Intent.ACTION_MAIN);
- wearHomeIntent.addCategory(Intent.CATEGORY_HOME_MAIN);
-
- PackageParser.Package wearHomePackage = getDefaultSystemHandlerActivityPackageLPr(
- wearHomeIntent, userId);
-
- if (wearHomePackage != null
- && doesPackageSupportRuntimePermissions(wearHomePackage)) {
- grantRuntimePermissionsLPw(wearHomePackage, CONTACTS_PERMISSIONS, false,
- userId);
- grantRuntimePermissionsLPw(wearHomePackage, PHONE_PERMISSIONS, true, userId);
- grantRuntimePermissionsLPw(wearHomePackage, MICROPHONE_PERMISSIONS, false,
- userId);
- grantRuntimePermissionsLPw(wearHomePackage, LOCATION_PERMISSIONS, false,
- userId);
- }
-
- // Fitness tracking on watches
- Intent trackIntent = new Intent(ACTION_TRACK);
- PackageParser.Package trackPackage = getDefaultSystemHandlerActivityPackageLPr(
- trackIntent, userId);
- if (trackPackage != null
- && doesPackageSupportRuntimePermissions(trackPackage)) {
- grantRuntimePermissionsLPw(trackPackage, SENSORS_PERMISSIONS, false, userId);
- grantRuntimePermissionsLPw(trackPackage, LOCATION_PERMISSIONS, false, userId);
- }
- }
-
- // Print Spooler
- PackageParser.Package printSpoolerPackage = getSystemPackageLPr(
- PrintManager.PRINT_SPOOLER_PACKAGE_NAME);
- if (printSpoolerPackage != null
- && doesPackageSupportRuntimePermissions(printSpoolerPackage)) {
- grantRuntimePermissionsLPw(printSpoolerPackage, LOCATION_PERMISSIONS, true, userId);
- }
-
- // EmergencyInfo
- Intent emergencyInfoIntent = new Intent(TelephonyManager.ACTION_EMERGENCY_ASSISTANCE);
- PackageParser.Package emergencyInfoPckg = getDefaultSystemHandlerActivityPackageLPr(
- emergencyInfoIntent, userId);
- if (emergencyInfoPckg != null
- && doesPackageSupportRuntimePermissions(emergencyInfoPckg)) {
- grantRuntimePermissionsLPw(emergencyInfoPckg, CONTACTS_PERMISSIONS, true, userId);
- grantRuntimePermissionsLPw(emergencyInfoPckg, PHONE_PERMISSIONS, true, userId);
- }
-
- // NFC Tag viewer
- Intent nfcTagIntent = new Intent(Intent.ACTION_VIEW);
- nfcTagIntent.setType("vnd.android.cursor.item/ndef_msg");
- PackageParser.Package nfcTagPkg = getDefaultSystemHandlerActivityPackageLPr(
- nfcTagIntent, userId);
- if (nfcTagPkg != null
- && doesPackageSupportRuntimePermissions(nfcTagPkg)) {
- grantRuntimePermissionsLPw(nfcTagPkg, CONTACTS_PERMISSIONS, false, userId);
- grantRuntimePermissionsLPw(nfcTagPkg, PHONE_PERMISSIONS, false, userId);
- }
-
- // Storage Manager
- Intent storageManagerIntent = new Intent(StorageManager.ACTION_MANAGE_STORAGE);
- PackageParser.Package storageManagerPckg = getDefaultSystemHandlerActivityPackageLPr(
- storageManagerIntent, userId);
- if (storageManagerPckg != null
- && doesPackageSupportRuntimePermissions(storageManagerPckg)) {
- grantRuntimePermissionsLPw(storageManagerPckg, STORAGE_PERMISSIONS, true, userId);
- }
-
- // Companion devices
- PackageParser.Package companionDeviceDiscoveryPackage = getSystemPackageLPr(
- CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME);
- if (companionDeviceDiscoveryPackage != null
- && doesPackageSupportRuntimePermissions(companionDeviceDiscoveryPackage)) {
- grantRuntimePermissionsLPw(companionDeviceDiscoveryPackage,
- LOCATION_PERMISSIONS, true, userId);
- }
-
- // Ringtone Picker
- Intent ringtonePickerIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
- PackageParser.Package ringtonePickerPackage =
- getDefaultSystemHandlerActivityPackageLPr(ringtonePickerIntent, userId);
- if (ringtonePickerPackage != null
- && doesPackageSupportRuntimePermissions(ringtonePickerPackage)) {
- grantRuntimePermissionsLPw(ringtonePickerPackage,
- STORAGE_PERMISSIONS, true, userId);
- }
-
- mService.mSettings.onDefaultRuntimePermissionsGrantedLPr(userId);
- }
- }
-
- private void grantDefaultPermissionsToDefaultSystemDialerAppLPr(
- PackageParser.Package dialerPackage, int userId) {
- if (doesPackageSupportRuntimePermissions(dialerPackage)) {
- boolean isPhonePermFixed =
- mService.hasSystemFeature(PackageManager.FEATURE_WATCH, 0);
- grantRuntimePermissionsLPw(
- dialerPackage, PHONE_PERMISSIONS, isPhonePermFixed, userId);
- grantRuntimePermissionsLPw(dialerPackage, CONTACTS_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(dialerPackage, SMS_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(dialerPackage, MICROPHONE_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(dialerPackage, CAMERA_PERMISSIONS, userId);
- }
- }
-
- private void grantDefaultPermissionsToDefaultSystemSmsAppLPr(
- PackageParser.Package smsPackage, int userId) {
- if (doesPackageSupportRuntimePermissions(smsPackage)) {
- grantRuntimePermissionsLPw(smsPackage, PHONE_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(smsPackage, CONTACTS_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(smsPackage, SMS_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(smsPackage, STORAGE_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(smsPackage, MICROPHONE_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(smsPackage, CAMERA_PERMISSIONS, userId);
- }
- }
-
- public void grantDefaultPermissionsToDefaultSmsAppLPr(String packageName, int userId) {
- Log.i(TAG, "Granting permissions to default sms app for user:" + userId);
- if (packageName == null) {
- return;
- }
- PackageParser.Package smsPackage = getPackageLPr(packageName);
- if (smsPackage != null && doesPackageSupportRuntimePermissions(smsPackage)) {
- grantRuntimePermissionsLPw(smsPackage, PHONE_PERMISSIONS, false, true, userId);
- grantRuntimePermissionsLPw(smsPackage, CONTACTS_PERMISSIONS, false, true, userId);
- grantRuntimePermissionsLPw(smsPackage, SMS_PERMISSIONS, false, true, userId);
- grantRuntimePermissionsLPw(smsPackage, STORAGE_PERMISSIONS, false, true, userId);
- grantRuntimePermissionsLPw(smsPackage, MICROPHONE_PERMISSIONS, false, true, userId);
- grantRuntimePermissionsLPw(smsPackage, CAMERA_PERMISSIONS, false, true, userId);
- }
- }
-
- public void grantDefaultPermissionsToDefaultDialerAppLPr(String packageName, int userId) {
- Log.i(TAG, "Granting permissions to default dialer app for user:" + userId);
- if (packageName == null) {
- return;
- }
- PackageParser.Package dialerPackage = getPackageLPr(packageName);
- if (dialerPackage != null
- && doesPackageSupportRuntimePermissions(dialerPackage)) {
- grantRuntimePermissionsLPw(dialerPackage, PHONE_PERMISSIONS, false, true, userId);
- grantRuntimePermissionsLPw(dialerPackage, CONTACTS_PERMISSIONS, false, true, userId);
- grantRuntimePermissionsLPw(dialerPackage, SMS_PERMISSIONS, false, true, userId);
- grantRuntimePermissionsLPw(dialerPackage, MICROPHONE_PERMISSIONS, false, true, userId);
- grantRuntimePermissionsLPw(dialerPackage, CAMERA_PERMISSIONS, false, true, userId);
- }
- }
-
- private void grantDefaultPermissionsToDefaultSimCallManagerLPr(
- PackageParser.Package simCallManagerPackage, int userId) {
- Log.i(TAG, "Granting permissions to sim call manager for user:" + userId);
- if (doesPackageSupportRuntimePermissions(simCallManagerPackage)) {
- grantRuntimePermissionsLPw(simCallManagerPackage, PHONE_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(simCallManagerPackage, MICROPHONE_PERMISSIONS, userId);
- }
- }
-
- public void grantDefaultPermissionsToDefaultSimCallManagerLPr(String packageName, int userId) {
- if (packageName == null) {
- return;
- }
- PackageParser.Package simCallManagerPackage = getPackageLPr(packageName);
- if (simCallManagerPackage != null) {
- grantDefaultPermissionsToDefaultSimCallManagerLPr(simCallManagerPackage, userId);
- }
- }
-
- public void grantDefaultPermissionsToEnabledCarrierAppsLPr(String[] packageNames, int userId) {
- Log.i(TAG, "Granting permissions to enabled carrier apps for user:" + userId);
- if (packageNames == null) {
- return;
- }
- for (String packageName : packageNames) {
- PackageParser.Package carrierPackage = getSystemPackageLPr(packageName);
- if (carrierPackage != null
- && doesPackageSupportRuntimePermissions(carrierPackage)) {
- grantRuntimePermissionsLPw(carrierPackage, PHONE_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(carrierPackage, LOCATION_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(carrierPackage, SMS_PERMISSIONS, userId);
- }
- }
- }
-
- public void grantDefaultPermissionsToEnabledImsServicesLPr(String[] packageNames, int userId) {
- Log.i(TAG, "Granting permissions to enabled ImsServices for user:" + userId);
- if (packageNames == null) {
- return;
- }
- for (String packageName : packageNames) {
- PackageParser.Package imsServicePackage = getSystemPackageLPr(packageName);
- if (imsServicePackage != null
- && doesPackageSupportRuntimePermissions(imsServicePackage)) {
- grantRuntimePermissionsLPw(imsServicePackage, PHONE_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(imsServicePackage, MICROPHONE_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(imsServicePackage, LOCATION_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(imsServicePackage, CAMERA_PERMISSIONS, userId);
- }
- }
- }
-
- public void grantDefaultPermissionsToDefaultBrowserLPr(String packageName, int userId) {
- Log.i(TAG, "Granting permissions to default browser for user:" + userId);
- if (packageName == null) {
- return;
- }
- PackageParser.Package browserPackage = getSystemPackageLPr(packageName);
- if (browserPackage != null
- && doesPackageSupportRuntimePermissions(browserPackage)) {
- grantRuntimePermissionsLPw(browserPackage, LOCATION_PERMISSIONS, false, false, userId);
- }
- }
-
- private PackageParser.Package getDefaultSystemHandlerActivityPackageLPr(
- Intent intent, int userId) {
- ResolveInfo handler = mService.resolveIntent(intent,
- intent.resolveType(mService.mContext.getContentResolver()), DEFAULT_FLAGS, userId);
- if (handler == null || handler.activityInfo == null) {
- return null;
- }
- ActivityInfo activityInfo = handler.activityInfo;
- if (activityInfo.packageName.equals(mService.mResolveActivity.packageName)
- && activityInfo.name.equals(mService.mResolveActivity.name)) {
- return null;
- }
- return getSystemPackageLPr(handler.activityInfo.packageName);
- }
-
- private PackageParser.Package getDefaultSystemHandlerServicePackageLPr(
- Intent intent, int userId) {
- List<ResolveInfo> handlers = mService.queryIntentServices(intent,
- intent.resolveType(mService.mContext.getContentResolver()), DEFAULT_FLAGS, userId)
- .getList();
- if (handlers == null) {
- return null;
- }
- final int handlerCount = handlers.size();
- for (int i = 0; i < handlerCount; i++) {
- ResolveInfo handler = handlers.get(i);
- PackageParser.Package handlerPackage = getSystemPackageLPr(
- handler.serviceInfo.packageName);
- if (handlerPackage != null) {
- return handlerPackage;
- }
- }
- return null;
- }
-
- private List<PackageParser.Package> getHeadlessSyncAdapterPackagesLPr(
- String[] syncAdapterPackageNames, int userId) {
- List<PackageParser.Package> syncAdapterPackages = new ArrayList<>();
-
- Intent homeIntent = new Intent(Intent.ACTION_MAIN);
- homeIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-
- for (String syncAdapterPackageName : syncAdapterPackageNames) {
- homeIntent.setPackage(syncAdapterPackageName);
-
- ResolveInfo homeActivity = mService.resolveIntent(homeIntent,
- homeIntent.resolveType(mService.mContext.getContentResolver()), DEFAULT_FLAGS,
- userId);
- if (homeActivity != null) {
- continue;
- }
-
- PackageParser.Package syncAdapterPackage = getSystemPackageLPr(syncAdapterPackageName);
- if (syncAdapterPackage != null) {
- syncAdapterPackages.add(syncAdapterPackage);
- }
- }
-
- return syncAdapterPackages;
- }
-
- private PackageParser.Package getDefaultProviderAuthorityPackageLPr(
- String authority, int userId) {
- ProviderInfo provider = mService.resolveContentProvider(authority, DEFAULT_FLAGS, userId);
- if (provider != null) {
- return getSystemPackageLPr(provider.packageName);
- }
- return null;
- }
-
- private PackageParser.Package getPackageLPr(String packageName) {
- return mService.mPackages.get(packageName);
- }
-
- private PackageParser.Package getSystemPackageLPr(String packageName) {
- PackageParser.Package pkg = getPackageLPr(packageName);
- if (pkg != null && pkg.isSystemApp()) {
- return !isSysComponentOrPersistentPlatformSignedPrivAppLPr(pkg) ? pkg : null;
- }
- return null;
- }
-
- private void grantRuntimePermissionsLPw(PackageParser.Package pkg, Set<String> permissions,
- int userId) {
- grantRuntimePermissionsLPw(pkg, permissions, false, false, userId);
- }
-
- private void grantRuntimePermissionsLPw(PackageParser.Package pkg, Set<String> permissions,
- boolean systemFixed, int userId) {
- grantRuntimePermissionsLPw(pkg, permissions, systemFixed, false, userId);
- }
-
- private void grantRuntimePermissionsLPw(PackageParser.Package pkg, Set<String> permissions,
- boolean systemFixed, boolean isDefaultPhoneOrSms, int userId) {
- if (pkg.requestedPermissions.isEmpty()) {
- return;
- }
-
- List<String> requestedPermissions = pkg.requestedPermissions;
- Set<String> grantablePermissions = null;
-
- // If this is the default Phone or SMS app we grant permissions regardless
- // whether the version on the system image declares the permission as used since
- // selecting the app as the default Phone or SMS the user makes a deliberate
- // choice to grant this app the permissions needed to function. For all other
- // apps, (default grants on first boot and user creation) we don't grant default
- // permissions if the version on the system image does not declare them.
- if (!isDefaultPhoneOrSms && pkg.isUpdatedSystemApp()) {
- PackageSetting sysPs = mService.mSettings.getDisabledSystemPkgLPr(pkg.packageName);
- if (sysPs != null && sysPs.pkg != null) {
- if (sysPs.pkg.requestedPermissions.isEmpty()) {
- return;
- }
- if (!requestedPermissions.equals(sysPs.pkg.requestedPermissions)) {
- grantablePermissions = new ArraySet<>(requestedPermissions);
- requestedPermissions = sysPs.pkg.requestedPermissions;
- }
- }
- }
-
- final int grantablePermissionCount = requestedPermissions.size();
- for (int i = 0; i < grantablePermissionCount; i++) {
- String permission = requestedPermissions.get(i);
-
- // If there is a disabled system app it may request a permission the updated
- // version ot the data partition doesn't, In this case skip the permission.
- if (grantablePermissions != null && !grantablePermissions.contains(permission)) {
- continue;
- }
-
- if (permissions.contains(permission)) {
- final int flags = mService.getPermissionFlags(permission, pkg.packageName, userId);
-
- // If any flags are set to the permission, then it is either set in
- // its current state by the system or device/profile owner or the user.
- // In all these cases we do not want to clobber the current state.
- // Unless the caller wants to override user choices. The override is
- // to make sure we can grant the needed permission to the default
- // sms and phone apps after the user chooses this in the UI.
- if (flags == 0 || isDefaultPhoneOrSms) {
- // Never clobber policy or system.
- final int fixedFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
- | PackageManager.FLAG_PERMISSION_POLICY_FIXED;
- if ((flags & fixedFlags) != 0) {
- continue;
- }
-
- mService.grantRuntimePermission(pkg.packageName, permission, userId);
- if (DEBUG) {
- Log.i(TAG, "Granted " + (systemFixed ? "fixed " : "not fixed ")
- + permission + " to default handler " + pkg.packageName);
- }
-
- int newFlags = PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
- if (systemFixed) {
- newFlags |= PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
- }
-
- mService.updatePermissionFlags(permission, pkg.packageName,
- newFlags, newFlags, userId);
- }
-
- // If a component gets a permission for being the default handler A
- // and also default handler B, we grant the weaker grant form.
- if ((flags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0
- && (flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0
- && !systemFixed) {
- if (DEBUG) {
- Log.i(TAG, "Granted not fixed " + permission + " to default handler "
- + pkg.packageName);
- }
- mService.updatePermissionFlags(permission, pkg.packageName,
- PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, 0, userId);
- }
- }
- }
- }
-
- private boolean isSysComponentOrPersistentPlatformSignedPrivAppLPr(PackageParser.Package pkg) {
- if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
- return true;
- }
- if (!pkg.isPrivilegedApp()) {
- return false;
- }
- PackageSetting sysPkg = mService.mSettings.getDisabledSystemPkgLPr(pkg.packageName);
- if (sysPkg != null && sysPkg.pkg != null) {
- if ((sysPkg.pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
- return false;
- }
- } else if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
- return false;
- }
- return PackageManagerService.compareSignatures(mService.mPlatformPackage.mSignatures,
- pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
- }
-
- private void grantDefaultPermissionExceptions(int userId) {
- synchronized (mService.mPackages) {
- mHandler.removeMessages(MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS);
-
- if (mGrantExceptions == null) {
- mGrantExceptions = readDefaultPermissionExceptionsLPw();
- }
-
- // mGrantExceptions is null only before the first read and then
- // it serves as a cache of the default grants that should be
- // performed for every user. If there is an entry then the app
- // is on the system image and supports runtime permissions.
- Set<String> permissions = null;
- final int exceptionCount = mGrantExceptions.size();
- for (int i = 0; i < exceptionCount; i++) {
- String packageName = mGrantExceptions.keyAt(i);
- PackageParser.Package pkg = getSystemPackageLPr(packageName);
- List<DefaultPermissionGrant> permissionGrants = mGrantExceptions.valueAt(i);
- final int permissionGrantCount = permissionGrants.size();
- for (int j = 0; j < permissionGrantCount; j++) {
- DefaultPermissionGrant permissionGrant = permissionGrants.get(j);
- if (permissions == null) {
- permissions = new ArraySet<>();
- } else {
- permissions.clear();
- }
- permissions.add(permissionGrant.name);
- grantRuntimePermissionsLPw(pkg, permissions,
- permissionGrant.fixed, userId);
- }
- }
- }
- }
-
- private File[] getDefaultPermissionFiles() {
- ArrayList<File> ret = new ArrayList<File>();
- File dir = new File(Environment.getRootDirectory(), "etc/default-permissions");
- if (dir.isDirectory() && dir.canRead()) {
- Collections.addAll(ret, dir.listFiles());
- }
- dir = new File(Environment.getVendorDirectory(), "etc/default-permissions");
- if (dir.isDirectory() && dir.canRead()) {
- Collections.addAll(ret, dir.listFiles());
- }
- return ret.isEmpty() ? null : ret.toArray(new File[0]);
- }
-
- private @NonNull ArrayMap<String, List<DefaultPermissionGrant>>
- readDefaultPermissionExceptionsLPw() {
- File[] files = getDefaultPermissionFiles();
- if (files == null) {
- return new ArrayMap<>(0);
- }
-
- ArrayMap<String, List<DefaultPermissionGrant>> grantExceptions = new ArrayMap<>();
-
- // Iterate over the files in the directory and scan .xml files
- for (File file : files) {
- if (!file.getPath().endsWith(".xml")) {
- Slog.i(TAG, "Non-xml file " + file + " in " + file.getParent() + " directory, ignoring");
- continue;
- }
- if (!file.canRead()) {
- Slog.w(TAG, "Default permissions file " + file + " cannot be read");
- continue;
- }
- try (
- InputStream str = new BufferedInputStream(new FileInputStream(file))
- ) {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(str, null);
- parse(parser, grantExceptions);
- } catch (XmlPullParserException | IOException e) {
- Slog.w(TAG, "Error reading default permissions file " + file, e);
- }
- }
-
- return grantExceptions;
- }
-
- private void parse(XmlPullParser parser, Map<String, List<DefaultPermissionGrant>>
- outGrantExceptions) throws IOException, XmlPullParserException {
- final int outerDepth = parser.getDepth();
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
- if (TAG_EXCEPTIONS.equals(parser.getName())) {
- parseExceptions(parser, outGrantExceptions);
- } else {
- Log.e(TAG, "Unknown tag " + parser.getName());
- }
- }
- }
-
- private void parseExceptions(XmlPullParser parser, Map<String, List<DefaultPermissionGrant>>
- outGrantExceptions) throws IOException, XmlPullParserException {
- final int outerDepth = parser.getDepth();
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
- if (TAG_EXCEPTION.equals(parser.getName())) {
- String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
-
- List<DefaultPermissionGrant> packageExceptions =
- outGrantExceptions.get(packageName);
- if (packageExceptions == null) {
- // The package must be on the system image
- PackageParser.Package pkg = getSystemPackageLPr(packageName);
- if (pkg == null) {
- Log.w(TAG, "Unknown package:" + packageName);
- XmlUtils.skipCurrentTag(parser);
- continue;
- }
-
- // The package must support runtime permissions
- if (!doesPackageSupportRuntimePermissions(pkg)) {
- Log.w(TAG, "Skipping non supporting runtime permissions package:"
- + packageName);
- XmlUtils.skipCurrentTag(parser);
- continue;
- }
- packageExceptions = new ArrayList<>();
- outGrantExceptions.put(packageName, packageExceptions);
- }
-
- parsePermission(parser, packageExceptions);
- } else {
- Log.e(TAG, "Unknown tag " + parser.getName() + "under <exceptions>");
- }
- }
- }
-
- private void parsePermission(XmlPullParser parser, List<DefaultPermissionGrant>
- outPackageExceptions) throws IOException, XmlPullParserException {
- final int outerDepth = parser.getDepth();
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
-
- if (TAG_PERMISSION.contains(parser.getName())) {
- String name = parser.getAttributeValue(null, ATTR_NAME);
- if (name == null) {
- Log.w(TAG, "Mandatory name attribute missing for permission tag");
- XmlUtils.skipCurrentTag(parser);
- continue;
- }
-
- final boolean fixed = XmlUtils.readBooleanAttribute(parser, ATTR_FIXED);
-
- DefaultPermissionGrant exception = new DefaultPermissionGrant(name, fixed);
- outPackageExceptions.add(exception);
- } else {
- Log.e(TAG, "Unknown tag " + parser.getName() + "under <exception>");
- }
- }
- }
-
- private static boolean doesPackageSupportRuntimePermissions(PackageParser.Package pkg) {
- return pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
- }
-
- private static final class DefaultPermissionGrant {
- final String name;
- final boolean fixed;
-
- public DefaultPermissionGrant(String name, boolean fixed) {
- this.name = name;
- this.fixed = fixed;
- }
- }
-}
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 37b8ebb..c964f91 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -880,8 +880,9 @@
final long identity = Binder.clearCallingIdentity();
try {
for (String grantedPermission : appInfo.getGrantedPermissions()) {
- BasePermission bp = mService.mSettings.mPermissions.get(grantedPermission);
- if (bp != null && (bp.isRuntime() || bp.isDevelopment()) && bp.isInstant()) {
+ final boolean propagatePermission =
+ mService.mSettings.canPropagatePermissionToInstantApp(grantedPermission);
+ if (propagatePermission) {
mService.grantRuntimePermission(packageName, grantedPermission, userId);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 925f595..8ebeeae 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -365,18 +365,13 @@
+ " dexoptFlags=" + printDexoptFlags(dexoptFlags)
+ " target-filter=" + compilerFilter);
- String classLoaderContext;
- if (dexUseInfo.isUnknownClassLoaderContext() ||
- dexUseInfo.isUnsupportedClassLoaderContext() ||
- dexUseInfo.isVariableClassLoaderContext()) {
- // If we have an unknown (not yet set), unsupported (custom class loaders), or a
- // variable class loader chain, compile without a context and mark the oat file with
- // SKIP_SHARED_LIBRARY_CHECK. Note that his might lead to a incorrect compilation.
- // TODO(calin): We should just extract in this case.
- classLoaderContext = SKIP_SHARED_LIBRARY_CHECK;
- } else {
- classLoaderContext = dexUseInfo.getClassLoaderContext();
- }
+ // TODO(calin): b/64530081 b/66984396. Use SKIP_SHARED_LIBRARY_CHECK for the context
+ // (instead of dexUseInfo.getClassLoaderContext()) in order to compile secondary dex files
+ // in isolation (and avoid to extract/verify the main apk if it's in the class path).
+ // Note this trades correctness for performance since the resulting slow down is
+ // unacceptable in some cases until b/64530081 is fixed.
+ String classLoaderContext = SKIP_SHARED_LIBRARY_CHECK;
+
try {
for (String isa : dexUseInfo.getLoaderIsas()) {
// Reuse the same dexopt path as for the primary apks. We don't need all the
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index a32ed17..09f9cb8 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -80,6 +80,8 @@
import com.android.internal.util.ImageUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.IoThread;
+import com.android.server.LocalServices;
+import com.android.server.pm.permission.PermissionManagerInternal;
import libcore.io.IoUtils;
@@ -122,6 +124,7 @@
private final Context mContext;
private final PackageManagerService mPm;
+ private final PermissionManagerInternal mPermissionManager;
private AppOpsManager mAppOps;
@@ -177,6 +180,7 @@
public PackageInstallerService(Context context, PackageManagerService pm) {
mContext = context;
mPm = pm;
+ mPermissionManager = LocalServices.getService(PermissionManagerInternal.class);
mInstallThread = new HandlerThread(TAG);
mInstallThread.start();
@@ -397,7 +401,8 @@
private int createSessionInternal(SessionParams params, String installerPackageName, int userId)
throws IOException {
final int callingUid = Binder.getCallingUid();
- mPm.enforceCrossUserPermission(callingUid, userId, true, true, "createSession");
+ mPermissionManager.enforceCrossUserPermission(
+ callingUid, userId, true, true, "createSession");
if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
throw new SecurityException("User restriction prevents installing");
@@ -652,7 +657,8 @@
@Override
public ParceledListSlice<SessionInfo> getAllSessions(int userId) {
- mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "getAllSessions");
+ mPermissionManager.enforceCrossUserPermission(
+ Binder.getCallingUid(), userId, true, false, "getAllSessions");
final List<SessionInfo> result = new ArrayList<>();
synchronized (mSessions) {
@@ -668,7 +674,8 @@
@Override
public ParceledListSlice<SessionInfo> getMySessions(String installerPackageName, int userId) {
- mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "getMySessions");
+ mPermissionManager.enforceCrossUserPermission(
+ Binder.getCallingUid(), userId, true, false, "getMySessions");
mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName);
final List<SessionInfo> result = new ArrayList<>();
@@ -690,7 +697,7 @@
public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,
IntentSender statusReceiver, int userId) throws RemoteException {
final int callingUid = Binder.getCallingUid();
- mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
mAppOps.checkPackage(callingUid, callerPackageName);
}
@@ -739,7 +746,8 @@
@Override
public void registerCallback(IPackageInstallerCallback callback, int userId) {
- mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "registerCallback");
+ mPermissionManager.enforceCrossUserPermission(
+ Binder.getCallingUid(), userId, true, false, "registerCallback");
mCallbacks.register(callback, userId);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d05c95f..7d1a647 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -102,10 +102,9 @@
import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
-import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_FAILURE;
-import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS;
-import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
-
+import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_FAILURE;
+import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS;
+import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
import static dalvik.system.DexFile.getNonProfileGuidedCompilerFilter;
import android.Manifest;
@@ -159,10 +158,11 @@
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.ActivityIntentInfo;
+import android.content.pm.PackageParser.Package;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.PackageStats;
@@ -282,13 +282,19 @@
import com.android.server.Watchdog;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.pm.Installer.InstallerException;
-import com.android.server.pm.PermissionsState.PermissionState;
import com.android.server.pm.Settings.DatabaseVersion;
import com.android.server.pm.Settings.VersionInfo;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.PackageDexUsage;
import com.android.server.pm.permission.BasePermission;
+import com.android.server.pm.permission.DefaultPermissionGrantPolicy;
+import com.android.server.pm.permission.PermissionManagerService;
+import com.android.server.pm.permission.PermissionManagerInternal;
+import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback;
+import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback;
+import com.android.server.pm.permission.PermissionsState;
+import com.android.server.pm.permission.PermissionsState.PermissionState;
import com.android.server.storage.DeviceStorageMonitorInternal;
import dalvik.system.CloseGuard;
@@ -338,6 +344,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -427,9 +434,6 @@
private static final int BLUETOOTH_UID = Process.BLUETOOTH_UID;
private static final int SHELL_UID = Process.SHELL_UID;
- // Cap the size of permission trees that 3rd party apps can define
- private static final int MAX_PERMISSION_TREE_FOOTPRINT = 32768; // characters of text
-
// Suffix used during package installation when copying/moving
// package apks to install directory.
private static final String INSTALL_PACKAGE_SUFFIX = "-";
@@ -860,7 +864,7 @@
String targetPath) {
return getStaticOverlayPaths(targetPackageName, targetPath);
}
- };
+ }
class ParallelPackageParserCallback extends PackageParserCallback {
List<PackageParser.Package> mOverlayPackages = null;
@@ -1002,7 +1006,9 @@
final SparseArray<IntentFilterVerificationState> mIntentFilterVerificationStates
= new SparseArray<IntentFilterVerificationState>();
+ // TODO remove this and go through mPermissonManager directly
final DefaultPermissionGrantPolicy mDefaultPermissionPolicy;
+ private final PermissionManagerInternal mPermissionManager;
// List of packages names to keep cached, even if they are uninstalled for all users
private List<String> mKeepUninstalledPackages;
@@ -1881,6 +1887,69 @@
}
}
+ private PermissionCallback mPermissionCallback = new PermissionCallback() {
+ @Override
+ public void onGidsChanged(int appId, int userId) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED);
+ }
+ });
+ }
+ @Override
+ public void onPermissionGranted(int uid, int userId) {
+ mOnPermissionChangeListeners.onPermissionsChanged(uid);
+
+ // Not critical; if this is lost, the application has to request again.
+ synchronized (mPackages) {
+ mSettings.writeRuntimePermissionsForUserLPr(userId, false);
+ }
+ }
+ @Override
+ public void onInstallPermissionGranted() {
+ synchronized (mPackages) {
+ scheduleWriteSettingsLocked();
+ }
+ }
+ @Override
+ public void onPermissionRevoked(int uid, int userId) {
+ mOnPermissionChangeListeners.onPermissionsChanged(uid);
+
+ synchronized (mPackages) {
+ // Critical; after this call the application should never have the permission
+ mSettings.writeRuntimePermissionsForUserLPr(userId, true);
+ }
+
+ final int appId = UserHandle.getAppId(uid);
+ killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
+ }
+ @Override
+ public void onInstallPermissionRevoked() {
+ synchronized (mPackages) {
+ scheduleWriteSettingsLocked();
+ }
+ }
+ @Override
+ public void onPermissionUpdated(int userId) {
+ synchronized (mPackages) {
+ mSettings.writeRuntimePermissionsForUserLPr(userId, false);
+ }
+ }
+ @Override
+ public void onInstallPermissionUpdated() {
+ synchronized (mPackages) {
+ scheduleWriteSettingsLocked();
+ }
+ }
+ @Override
+ public void onPermissionRemoved() {
+ synchronized (mPackages) {
+ mSettings.writeLPr();
+ }
+ }
+ };
+
private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
boolean killApp, boolean virtualPreload, String[] grantedPermissions,
boolean launchedForRestore, String installerPackage,
@@ -1897,7 +1966,10 @@
// review flag which is used to emulate runtime permissions for
// legacy apps.
if (grantPermissions) {
- grantRequestedRuntimePermissions(res.pkg, res.newUsers, grantedPermissions);
+ final int callingUid = Binder.getCallingUid();
+ mPermissionManager.grantRequestedRuntimePermissions(
+ res.pkg, res.newUsers, grantedPermissions, callingUid,
+ mPermissionCallback);
}
final boolean update = res.removedInfo != null
@@ -1913,9 +1985,9 @@
// app that had no children, we grant requested runtime permissions to the new
// children if the parent on the system image had them already granted.
if (res.pkg.parentPackage != null) {
- synchronized (mPackages) {
- grantRuntimePermissionsGrantedToDisabledPrivSysPackageParentLPw(res.pkg);
- }
+ final int callingUid = Binder.getCallingUid();
+ mPermissionManager.grantRuntimePermissionsGrantedToDisabledPackage(
+ res.pkg, callingUid, mPermissionCallback);
}
synchronized (mPackages) {
@@ -2080,39 +2152,6 @@
}
}
- private void grantRuntimePermissionsGrantedToDisabledPrivSysPackageParentLPw(
- PackageParser.Package pkg) {
- if (pkg.parentPackage == null) {
- return;
- }
- if (pkg.requestedPermissions == null) {
- return;
- }
- final PackageSetting disabledSysParentPs = mSettings
- .getDisabledSystemPkgLPr(pkg.parentPackage.packageName);
- if (disabledSysParentPs == null || disabledSysParentPs.pkg == null
- || !disabledSysParentPs.isPrivileged()
- || (disabledSysParentPs.childPackageNames != null
- && !disabledSysParentPs.childPackageNames.isEmpty())) {
- return;
- }
- final int[] allUserIds = sUserManager.getUserIds();
- final int permCount = pkg.requestedPermissions.size();
- for (int i = 0; i < permCount; i++) {
- String permission = pkg.requestedPermissions.get(i);
- BasePermission bp = mSettings.mPermissions.get(permission);
- if (bp == null || !(bp.isRuntime() || bp.isDevelopment())) {
- continue;
- }
- for (int userId : allUserIds) {
- if (disabledSysParentPs.getPermissionsState().hasRuntimePermission(
- permission, userId)) {
- grantRuntimePermission(pkg.packageName, permission, userId);
- }
- }
- }
- }
-
private StorageEventListener mStorageListener = new StorageEventListener() {
@Override
public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
@@ -2165,58 +2204,6 @@
}
};
- private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int[] userIds,
- String[] grantedPermissions) {
- for (int userId : userIds) {
- grantRequestedRuntimePermissionsForUser(pkg, userId, grantedPermissions);
- }
- }
-
- private void grantRequestedRuntimePermissionsForUser(PackageParser.Package pkg, int userId,
- String[] grantedPermissions) {
- PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (ps == null) {
- return;
- }
-
- PermissionsState permissionsState = ps.getPermissionsState();
-
- final int immutableFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
- | PackageManager.FLAG_PERMISSION_POLICY_FIXED;
-
- final boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
- >= Build.VERSION_CODES.M;
-
- final boolean instantApp = isInstantApp(pkg.packageName, userId);
-
- for (String permission : pkg.requestedPermissions) {
- final BasePermission bp;
- synchronized (mPackages) {
- bp = mSettings.mPermissions.get(permission);
- }
- if (bp != null && (bp.isRuntime() || bp.isDevelopment())
- && (!instantApp || bp.isInstant())
- && (supportsRuntimePermissions || !bp.isRuntimeOnly())
- && (grantedPermissions == null
- || ArrayUtils.contains(grantedPermissions, permission))) {
- final int flags = permissionsState.getPermissionFlags(permission, userId);
- if (supportsRuntimePermissions) {
- // Installer cannot change immutable permissions.
- if ((flags & immutableFlags) == 0) {
- grantRuntimePermission(pkg.packageName, permission, userId);
- }
- } else if (mPermissionReviewRequired) {
- // In permission review mode we clear the review flag when we
- // are asked to install the app with all permissions granted.
- if ((flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
- updatePermissionFlags(permission, pkg.packageName,
- PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, 0, userId);
- }
- }
- }
- }
- }
-
Bundle extrasForInstallResult(PackageInstalledInfo res) {
Bundle extras = null;
switch (res.returnCode) {
@@ -2385,7 +2372,29 @@
mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
mMetrics = new DisplayMetrics();
- mSettings = new Settings(mPackages);
+ mInstaller = installer;
+
+ // Create sub-components that provide services / data. Order here is important.
+ synchronized (mInstallLock) {
+ synchronized (mPackages) {
+ // Expose private service for system components to use.
+ LocalServices.addService(
+ PackageManagerInternal.class, new PackageManagerInternalImpl());
+ sUserManager = new UserManagerService(context, this,
+ new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
+ mPermissionManager = PermissionManagerService.create(context,
+ new DefaultPermissionGrantedCallback() {
+ @Override
+ public void onDefaultRuntimePermissionsGranted(int userId) {
+ synchronized(mPackages) {
+ mSettings.onDefaultRuntimePermissionsGrantedLPr(userId);
+ }
+ }
+ }, mPackages /*externalLock*/);
+ mDefaultPermissionPolicy = mPermissionManager.getDefaultPermissionGrantPolicy();
+ mSettings = new Settings(mPermissionManager.getPermissionSettings(), mPackages);
+ }
+ }
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
@@ -2416,7 +2425,6 @@
mSeparateProcesses = null;
}
- mInstaller = installer;
mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
"*dexopt*");
mDexManager = new DexManager(this, mPackageDexOptimizer, installer, mInstallLock);
@@ -2445,31 +2453,12 @@
mHandler = new PackageHandler(mHandlerThread.getLooper());
mProcessLoggingHandler = new ProcessLoggingHandler();
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
-
- mDefaultPermissionPolicy = new DefaultPermissionGrantPolicy(this);
mInstantAppRegistry = new InstantAppRegistry(this);
File dataDir = Environment.getDataDirectory();
mAppInstallDir = new File(dataDir, "app");
mAppLib32InstallDir = new File(dataDir, "app-lib");
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
- sUserManager = new UserManagerService(context, this,
- new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
-
- // Propagate permission configuration in to package manager.
- ArrayMap<String, SystemConfig.PermissionEntry> permConfig
- = systemConfig.getPermissions();
- for (int i=0; i<permConfig.size(); i++) {
- SystemConfig.PermissionEntry perm = permConfig.valueAt(i);
- BasePermission bp = mSettings.mPermissions.get(perm.name);
- if (bp == null) {
- bp = new BasePermission(perm.name, "android", BasePermission.TYPE_BUILTIN);
- mSettings.mPermissions.put(perm.name, bp);
- }
- if (perm.gids != null) {
- bp.setGids(perm.gids, perm.perUser);
- }
- }
ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();
final int builtInLibCount = libConfig.size();
@@ -3072,8 +3061,6 @@
// once we have a booted system.
mInstaller.setWarnIfHeld(mPackages);
- // Expose private service for system components to use.
- LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -3889,7 +3876,7 @@
public boolean isPackageAvailable(String packageName, int userId) {
if (!sUserManager.exists(userId)) return false;
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/, "is package available");
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
@@ -3932,7 +3919,7 @@
int flags, int filterCallingUid, int userId) {
if (!sUserManager.exists(userId)) return null;
flags = updateFlagsForPackage(flags, userId, packageName);
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
false /* requireFullPermission */, false /* checkShell */, "get package info");
// reader
@@ -4194,7 +4181,7 @@
if (!sUserManager.exists(userId)) return -1;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForPackage(flags, userId, packageName);
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/, "getPackageUid");
// reader
@@ -4224,7 +4211,7 @@
if (!sUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForPackage(flags, userId, packageName);
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/, "getPackageGids");
// reader
@@ -4253,86 +4240,21 @@
@Override
public PermissionInfo getPermissionInfo(String name, String packageName, int flags) {
- final int callingUid = Binder.getCallingUid();
- if (getInstantAppPackageName(callingUid) != null) {
- return null;
- }
- // reader
- synchronized (mPackages) {
- final BasePermission bp = mSettings.mPermissions.get(name);
- if (bp == null) {
- return null;
- }
- final int adjustedProtectionLevel = adjustPermissionProtectionFlagsLPr(
- bp.getProtectionLevel(), packageName, callingUid);
- return bp.generatePermissionInfo(adjustedProtectionLevel, flags);
- }
- }
-
- private int adjustPermissionProtectionFlagsLPr(int protectionLevel,
- String packageName, int uid) {
- // Signature permission flags area always reported
- final int protectionLevelMasked = protectionLevel
- & (PermissionInfo.PROTECTION_NORMAL
- | PermissionInfo.PROTECTION_DANGEROUS
- | PermissionInfo.PROTECTION_SIGNATURE);
- if (protectionLevelMasked == PermissionInfo.PROTECTION_SIGNATURE) {
- return protectionLevel;
- }
-
- // System sees all flags.
- final int appId = UserHandle.getAppId(uid);
- if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID
- || appId == Process.SHELL_UID) {
- return protectionLevel;
- }
-
- // Normalize package name to handle renamed packages and static libs
- packageName = resolveInternalPackageNameLPr(packageName,
- PackageManager.VERSION_CODE_HIGHEST);
-
- // Apps that target O see flags for all protection levels.
- final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps == null) {
- return protectionLevel;
- }
- if (ps.appId != appId) {
- return protectionLevel;
- }
-
- final PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null) {
- return protectionLevel;
- }
- if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
- return protectionLevelMasked;
- }
-
- return protectionLevel;
+ return mPermissionManager.getPermissionInfo(name, packageName, flags, getCallingUid());
}
@Override
public @Nullable ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String groupName,
int flags) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return null;
- }
- // reader
+ // TODO Move this to PermissionManager when mPermissionGroups is moved there
synchronized (mPackages) {
if (groupName != null && !mPermissionGroups.containsKey(groupName)) {
// This is thrown as NameNotFoundException
return null;
}
-
- ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10);
- for (BasePermission bp : mSettings.mPermissions.values()) {
- final PermissionInfo pi = bp.generatePermissionInfo(groupName, flags);
- if (pi != null) {
- out.add(pi);
- }
- }
- return new ParceledListSlice<>(out);
}
+ return new ParceledListSlice<>(
+ mPermissionManager.getPermissionInfoByGroup(groupName, flags, getCallingUid()));
}
@Override
@@ -4407,7 +4329,7 @@
int filterCallingUid, int userId) {
if (!sUserManager.exists(userId)) return null;
flags = updateFlagsForApplication(flags, userId, packageName);
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
false /* requireFullPermission */, false /* checkShell */, "get application info");
// writer
@@ -4716,7 +4638,8 @@
triaged = false;
}
if ((flags & PackageManager.MATCH_ANY_USER) != 0) {
- enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false,
+ mPermissionManager.enforceCrossUserPermission(
+ Binder.getCallingUid(), userId, false, false,
"MATCH_ANY_USER flag requires INTERACT_ACROSS_USERS permission at "
+ Debug.getCallers(5));
} else if ((flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0 && isCallerSystemUser
@@ -4845,7 +4768,7 @@
int filterCallingUid, int userId) {
if (!sUserManager.exists(userId)) return null;
flags = updateFlagsForComponent(flags, userId, component);
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
false /* requireFullPermission */, false /* checkShell */, "get activity info");
synchronized (mPackages) {
PackageParser.Activity a = mActivities.mActivities.get(component);
@@ -4904,7 +4827,7 @@
if (!sUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForComponent(flags, userId, component);
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */, "get receiver info");
synchronized (mPackages) {
PackageParser.Activity a = mReceivers.mActivities.get(component);
@@ -5041,7 +4964,7 @@
if (!sUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForComponent(flags, userId, component);
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */, "get service info");
synchronized (mPackages) {
PackageParser.Service s = mServices.mServices.get(component);
@@ -5065,7 +4988,7 @@
if (!sUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForComponent(flags, userId, component);
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */, "get provider info");
synchronized (mPackages) {
PackageParser.Provider p = mProviders.mProviders.get(component);
@@ -5228,39 +5151,7 @@
@Override
public int checkPermission(String permName, String pkgName, int userId) {
- if (!sUserManager.exists(userId)) {
- return PackageManager.PERMISSION_DENIED;
- }
- final int callingUid = Binder.getCallingUid();
-
- synchronized (mPackages) {
- final PackageParser.Package p = mPackages.get(pkgName);
- if (p != null && p.mExtras != null) {
- final PackageSetting ps = (PackageSetting) p.mExtras;
- if (filterAppAccessLPr(ps, callingUid, userId)) {
- return PackageManager.PERMISSION_DENIED;
- }
- final boolean instantApp = ps.getInstantApp(userId);
- final PermissionsState permissionsState = ps.getPermissionsState();
- if (permissionsState.hasPermission(permName, userId)) {
- if (instantApp) {
- BasePermission bp = mSettings.mPermissions.get(permName);
- if (bp != null && bp.isInstant()) {
- return PackageManager.PERMISSION_GRANTED;
- }
- } else {
- return PackageManager.PERMISSION_GRANTED;
- }
- }
- // Special case: ACCESS_FINE_LOCATION permission includes ACCESS_COARSE_LOCATION
- if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && permissionsState
- .hasPermission(Manifest.permission.ACCESS_FINE_LOCATION, userId)) {
- return PackageManager.PERMISSION_GRANTED;
- }
- }
- }
-
- return PackageManager.PERMISSION_DENIED;
+ return mPermissionManager.checkPermission(permName, pkgName, getCallingUid(), userId);
}
@Override
@@ -5291,8 +5182,7 @@
final PermissionsState permissionsState = settingBase.getPermissionsState();
if (permissionsState.hasPermission(permName, userId)) {
if (isUidInstantApp) {
- BasePermission bp = mSettings.mPermissions.get(permName);
- if (bp != null && bp.isInstant()) {
+ if (mPermissionManager.isPermissionInstant(permName)) {
return PackageManager.PERMISSION_GRANTED;
}
} else {
@@ -5361,359 +5251,49 @@
}
}
- /**
- * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS
- * or INTERACT_ACROSS_USERS_FULL permissions, if the userid is not for the caller.
- * @param checkShell whether to prevent shell from access if there's a debugging restriction
- * @param message the message to log on security exception
- */
- void enforceCrossUserPermission(int callingUid, int userId, boolean requireFullPermission,
- boolean checkShell, String message) {
- if (userId < 0) {
- throw new IllegalArgumentException("Invalid userId " + userId);
- }
- if (checkShell) {
- enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
- }
- if (userId == UserHandle.getUserId(callingUid)) return;
- if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
- if (requireFullPermission) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
- } else {
- try {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
- } catch (SecurityException se) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS, message);
- }
- }
- }
- }
-
- void enforceShellRestriction(String restriction, int callingUid, int userHandle) {
- if (callingUid == Process.SHELL_UID) {
- if (userHandle >= 0
- && sUserManager.hasUserRestriction(restriction, userHandle)) {
- throw new SecurityException("Shell does not have permission to access user "
- + userHandle);
- } else if (userHandle < 0) {
- Slog.e(TAG, "Unable to check shell permission for user " + userHandle + "\n\t"
- + Debug.getCallers(3));
- }
- }
- }
-
- int calculateCurrentPermissionFootprintLocked(BasePermission tree) {
- int size = 0;
- for (BasePermission perm : mSettings.mPermissions.values()) {
- size += tree.calculateFootprint(perm);
- }
- return size;
- }
-
- void enforcePermissionCapLocked(PermissionInfo info, BasePermission tree) {
- // We calculate the max size of permissions defined by this uid and throw
- // if that plus the size of 'info' would exceed our stated maximum.
- if (tree.getUid() != Process.SYSTEM_UID) {
- final int curTreeSize = calculateCurrentPermissionFootprintLocked(tree);
- if (curTreeSize + info.calculateFootprint() > MAX_PERMISSION_TREE_FOOTPRINT) {
- throw new SecurityException("Permission tree size cap exceeded");
- }
- }
- }
-
- boolean addPermissionLocked(PermissionInfo info, boolean async) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- throw new SecurityException("Instant apps can't add permissions");
- }
- if (info.labelRes == 0 && info.nonLocalizedLabel == null) {
- throw new SecurityException("Label must be specified in permission");
- }
- BasePermission tree = BasePermission.enforcePermissionTreeLP(
- mSettings.mPermissionTrees, info.name, Binder.getCallingUid());
- BasePermission bp = mSettings.mPermissions.get(info.name);
- boolean added = bp == null;
- int fixedLevel = PermissionInfo.fixProtectionLevel(info.protectionLevel);
- if (added) {
- enforcePermissionCapLocked(info, tree);
- bp = new BasePermission(info.name, tree.getSourcePackageName(),
- BasePermission.TYPE_DYNAMIC);
- } else if (bp.isDynamic()) {
- throw new SecurityException(
- "Not allowed to modify non-dynamic permission "
- + info.name);
- }
- final boolean changed = bp.addToTree(fixedLevel, info, tree);
- if (added) {
- mSettings.mPermissions.put(info.name, bp);
- }
- if (changed) {
- if (!async) {
- mSettings.writeLPr();
- } else {
- scheduleWriteSettingsLocked();
- }
- }
- return added;
+ boolean addPermission(PermissionInfo info, final boolean async) {
+ return mPermissionManager.addPermission(
+ info, async, getCallingUid(), new PermissionCallback() {
+ @Override
+ public void onPermissionChanged() {
+ if (!async) {
+ mSettings.writeLPr();
+ } else {
+ scheduleWriteSettingsLocked();
+ }
+ }
+ });
}
@Override
public boolean addPermission(PermissionInfo info) {
synchronized (mPackages) {
- return addPermissionLocked(info, false);
+ return addPermission(info, false);
}
}
@Override
public boolean addPermissionAsync(PermissionInfo info) {
synchronized (mPackages) {
- return addPermissionLocked(info, true);
+ return addPermission(info, true);
}
}
@Override
- public void removePermission(String name) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- throw new SecurityException("Instant applications don't have access to this method");
- }
- synchronized (mPackages) {
- BasePermission.enforcePermissionTreeLP(
- mSettings.mPermissionTrees, name, Binder.getCallingUid());
- BasePermission bp = mSettings.mPermissions.get(name);
- if (bp != null) {
- if (bp.isDynamic()) {
- throw new SecurityException(
- "Not allowed to modify non-dynamic permission "
- + name);
- }
- mSettings.mPermissions.remove(name);
- mSettings.writeLPr();
- }
- }
+ public void removePermission(String permName) {
+ mPermissionManager.removePermission(permName, getCallingUid(), mPermissionCallback);
}
@Override
- public void grantRuntimePermission(String packageName, String name, final int userId) {
- grantRuntimePermission(packageName, name, userId, false /* Only if not fixed by policy */);
- }
-
- private void grantRuntimePermission(String packageName, String name, final int userId,
- boolean overridePolicy) {
- if (!sUserManager.exists(userId)) {
- Log.e(TAG, "No such user:" + userId);
- return;
- }
- final int callingUid = Binder.getCallingUid();
-
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
- "grantRuntimePermission");
-
- enforceCrossUserPermission(callingUid, userId,
- true /* requireFullPermission */, true /* checkShell */,
- "grantRuntimePermission");
-
- final int uid;
- final PackageSetting ps;
-
- synchronized (mPackages) {
- final PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
- final BasePermission bp = mSettings.mPermissions.get(name);
- if (bp == null) {
- throw new IllegalArgumentException("Unknown permission: " + name);
- }
- ps = (PackageSetting) pkg.mExtras;
- if (ps == null
- || filterAppAccessLPr(ps, callingUid, userId)) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
-
- bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
-
- // If a permission review is required for legacy apps we represent
- // their permissions as always granted runtime ones since we need
- // to keep the review required permission flag per user while an
- // install permission's state is shared across all users.
- if (mPermissionReviewRequired
- && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
- && bp.isRuntime()) {
- return;
- }
-
- uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);
-
- final PermissionsState permissionsState = ps.getPermissionsState();
-
- final int flags = permissionsState.getPermissionFlags(name, userId);
- if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
- throw new SecurityException("Cannot grant system fixed permission "
- + name + " for package " + packageName);
- }
- if (!overridePolicy && (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
- throw new SecurityException("Cannot grant policy fixed permission "
- + name + " for package " + packageName);
- }
-
- if (bp.isDevelopment()) {
- // Development permissions must be handled specially, since they are not
- // normal runtime permissions. For now they apply to all users.
- if (permissionsState.grantInstallPermission(bp) !=
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- scheduleWriteSettingsLocked();
- }
- return;
- }
-
- if (ps.getInstantApp(userId) && !bp.isInstant()) {
- throw new SecurityException("Cannot grant non-ephemeral permission"
- + name + " for package " + packageName);
- }
-
- if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
- Slog.w(TAG, "Cannot grant runtime permission to a legacy app");
- return;
- }
-
- final int result = permissionsState.grantRuntimePermission(bp, userId);
- switch (result) {
- case PermissionsState.PERMISSION_OPERATION_FAILURE: {
- return;
- }
-
- case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
- final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED);
- }
- });
- }
- break;
- }
-
- if (bp.isRuntime()) {
- logPermissionGranted(mContext, name, packageName);
- }
-
- mOnPermissionChangeListeners.onPermissionsChanged(uid);
-
- // Not critical if that is lost - app has to request again.
- mSettings.writeRuntimePermissionsForUserLPr(userId, false);
- }
-
- // Only need to do this if user is initialized. Otherwise it's a new user
- // and there are no processes running as the user yet and there's no need
- // to make an expensive call to remount processes for the changed permissions.
- if (READ_EXTERNAL_STORAGE.equals(name)
- || WRITE_EXTERNAL_STORAGE.equals(name)) {
- final long token = Binder.clearCallingIdentity();
- try {
- if (sUserManager.isInitialized(userId)) {
- StorageManagerInternal storageManagerInternal = LocalServices.getService(
- StorageManagerInternal.class);
- storageManagerInternal.onExternalStoragePolicyChanged(uid, packageName);
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
+ public void grantRuntimePermission(String packageName, String permName, final int userId) {
+ mPermissionManager.grantRuntimePermission(permName, packageName, false /*overridePolicy*/,
+ getCallingUid(), userId, mPermissionCallback);
}
@Override
- public void revokeRuntimePermission(String packageName, String name, int userId) {
- revokeRuntimePermission(packageName, name, userId, false /* Only if not fixed by policy */);
- }
-
- private void revokeRuntimePermission(String packageName, String name, int userId,
- boolean overridePolicy) {
- if (!sUserManager.exists(userId)) {
- Log.e(TAG, "No such user:" + userId);
- return;
- }
-
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
- "revokeRuntimePermission");
-
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
- true /* requireFullPermission */, true /* checkShell */,
- "revokeRuntimePermission");
-
- final int appId;
-
- synchronized (mPackages) {
- final PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (ps == null
- || filterAppAccessLPr(ps, Binder.getCallingUid(), userId)) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
- final BasePermission bp = mSettings.mPermissions.get(name);
- if (bp == null) {
- throw new IllegalArgumentException("Unknown permission: " + name);
- }
-
- bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
-
- // If a permission review is required for legacy apps we represent
- // their permissions as always granted runtime ones since we need
- // to keep the review required permission flag per user while an
- // install permission's state is shared across all users.
- if (mPermissionReviewRequired
- && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
- && bp.isRuntime()) {
- return;
- }
-
- final PermissionsState permissionsState = ps.getPermissionsState();
-
- final int flags = permissionsState.getPermissionFlags(name, userId);
- if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
- throw new SecurityException("Cannot revoke system fixed permission "
- + name + " for package " + packageName);
- }
- if (!overridePolicy && (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
- throw new SecurityException("Cannot revoke policy fixed permission "
- + name + " for package " + packageName);
- }
-
- if (bp.isDevelopment()) {
- // Development permissions must be handled specially, since they are not
- // normal runtime permissions. For now they apply to all users.
- if (permissionsState.revokeInstallPermission(bp) !=
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- scheduleWriteSettingsLocked();
- }
- return;
- }
-
- if (permissionsState.revokeRuntimePermission(bp, userId) ==
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- return;
- }
-
- if (bp.isRuntime()) {
- logPermissionRevoked(mContext, name, packageName);
- }
-
- mOnPermissionChangeListeners.onPermissionsChanged(pkg.applicationInfo.uid);
-
- // Critical, after this call app should never have the permission.
- mSettings.writeRuntimePermissionsForUserLPr(userId, true);
-
- appId = UserHandle.getAppId(pkg.applicationInfo.uid);
- }
-
- killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
+ public void revokeRuntimePermission(String packageName, String permName, int userId) {
+ mPermissionManager.revokeRuntimePermission(permName, packageName, false /*overridePolicy*/,
+ getCallingUid(), userId, mPermissionCallback);
}
/**
@@ -5806,91 +5386,16 @@
}
@Override
- public int getPermissionFlags(String name, String packageName, int userId) {
- if (!sUserManager.exists(userId)) {
- return 0;
- }
-
- enforceGrantRevokeRuntimePermissionPermissions("getPermissionFlags");
-
- final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
- true /* requireFullPermission */, false /* checkShell */,
- "getPermissionFlags");
-
- synchronized (mPackages) {
- final PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null) {
- return 0;
- }
- final BasePermission bp = mSettings.mPermissions.get(name);
- if (bp == null) {
- return 0;
- }
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (ps == null
- || filterAppAccessLPr(ps, callingUid, userId)) {
- return 0;
- }
- PermissionsState permissionsState = ps.getPermissionsState();
- return permissionsState.getPermissionFlags(name, userId);
- }
+ public int getPermissionFlags(String permName, String packageName, int userId) {
+ return mPermissionManager.getPermissionFlags(permName, packageName, getCallingUid(), userId);
}
@Override
- public void updatePermissionFlags(String name, String packageName, int flagMask,
+ public void updatePermissionFlags(String permName, String packageName, int flagMask,
int flagValues, int userId) {
- if (!sUserManager.exists(userId)) {
- return;
- }
-
- enforceGrantRevokeRuntimePermissionPermissions("updatePermissionFlags");
-
- final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
- true /* requireFullPermission */, true /* checkShell */,
- "updatePermissionFlags");
-
- // Only the system can change these flags and nothing else.
- if (getCallingUid() != Process.SYSTEM_UID) {
- flagMask &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
- flagValues &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
- flagMask &= ~PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
- flagValues &= ~PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
- flagValues &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
- }
-
- synchronized (mPackages) {
- final PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (ps == null
- || filterAppAccessLPr(ps, callingUid, userId)) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
-
- final BasePermission bp = mSettings.mPermissions.get(name);
- if (bp == null) {
- throw new IllegalArgumentException("Unknown permission: " + name);
- }
-
- PermissionsState permissionsState = ps.getPermissionsState();
-
- boolean hadState = permissionsState.getRuntimePermissionState(name, userId) != null;
-
- if (permissionsState.updatePermissionFlags(bp, userId, flagMask, flagValues)) {
- // Install and runtime permissions are stored in different places,
- // so figure out what permission changed and persist the change.
- if (permissionsState.getInstallPermissionState(name) != null) {
- scheduleWriteSettingsLocked();
- } else if (permissionsState.getRuntimePermissionState(name, userId) != null
- || hadState) {
- mSettings.writeRuntimePermissionsForUserLPr(userId, false);
- }
- }
- }
+ mPermissionManager.updatePermissionFlags(
+ permName, packageName, flagMask, flagValues, getCallingUid(), userId,
+ mPermissionCallback);
}
/**
@@ -5899,52 +5404,16 @@
*/
@Override
public void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId) {
- if (!sUserManager.exists(userId)) {
- return;
- }
-
- enforceGrantRevokeRuntimePermissionPermissions("updatePermissionFlagsForAllApps");
-
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
- true /* requireFullPermission */, true /* checkShell */,
- "updatePermissionFlagsForAllApps");
-
- // Only the system can change system fixed flags.
- if (getCallingUid() != Process.SYSTEM_UID) {
- flagMask &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
- flagValues &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
- }
-
synchronized (mPackages) {
- boolean changed = false;
- final int packageCount = mPackages.size();
- for (int pkgIndex = 0; pkgIndex < packageCount; pkgIndex++) {
- final PackageParser.Package pkg = mPackages.valueAt(pkgIndex);
- final PackageSetting ps = (PackageSetting) pkg.mExtras;
- if (ps == null) {
- continue;
- }
- PermissionsState permissionsState = ps.getPermissionsState();
- changed |= permissionsState.updatePermissionFlagsForAllPermissions(
- userId, flagMask, flagValues);
- }
+ final boolean changed = mPermissionManager.updatePermissionFlagsForAllApps(
+ flagMask, flagValues, getCallingUid(), userId, mPackages.values(),
+ mPermissionCallback);
if (changed) {
mSettings.writeRuntimePermissionsForUserLPr(userId, false);
}
}
}
- private void enforceGrantRevokeRuntimePermissionPermissions(String message) {
- if (mContext.checkCallingOrSelfPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
- != PackageManager.PERMISSION_GRANTED
- && mContext.checkCallingOrSelfPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(message + " requires "
- + Manifest.permission.GRANT_RUNTIME_PERMISSIONS + " or "
- + Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
- }
- }
-
@Override
public boolean shouldShowRequestPermissionRationale(String permissionName,
String packageName, int userId) {
@@ -6136,7 +5605,7 @@
* <br />
* {@link PackageManager#SIGNATURE_NO_MATCH}: if the two signature sets differ.
*/
- static int compareSignatures(Signature[] s1, Signature[] s2) {
+ public static int compareSignatures(Signature[] s1, Signature[] s2) {
if (s1 == null) {
return s2 == null
? PackageManager.SIGNATURE_NEITHER_SIGNED
@@ -6490,9 +5959,14 @@
public ResolveInfo resolveIntent(Intent intent, String resolvedType,
int flags, int userId) {
return resolveIntentInternal(
- intent, resolvedType, flags, userId, false /*includeInstantApps*/);
+ intent, resolvedType, flags, userId, false /*resolveForStart*/);
}
+ /**
+ * Normally instant apps can only be resolved when they're visible to the caller.
+ * However, if {@code resolveForStart} is {@code true}, all instant apps are visible
+ * since we need to allow the system to start any installed application.
+ */
private ResolveInfo resolveIntentInternal(Intent intent, String resolvedType,
int flags, int userId, boolean resolveForStart) {
try {
@@ -6501,7 +5975,7 @@
if (!sUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForResolve(flags, userId, intent, callingUid, resolveForStart);
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
@@ -7082,7 +6556,7 @@
boolean resolveForStart, boolean allowDynamicSplits) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
final String instantAppPkgName = getInstantAppPackageName(filterCallingUid);
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
false /* requireFullPermission */, false /* checkShell */,
"query intent activities");
final String pkgName = intent.getPackage();
@@ -7837,7 +7311,7 @@
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForResolve(flags, userId, intent, callingUid,
false /*includeInstantApps*/);
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/,
"query intent activity options");
final String resultsAction = intent.getAction();
@@ -8018,7 +7492,7 @@
String resolvedType, int flags, int userId, boolean allowDynamicSplits) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/,
"query intent receivers");
final String instantAppPkgName = getInstantAppPackageName(callingUid);
@@ -8130,7 +7604,7 @@
String resolvedType, int flags, int userId, int callingUid,
boolean includeInstantApps) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/,
"query intent receivers");
final String instantAppPkgName = getInstantAppPackageName(callingUid);
@@ -8370,7 +7844,7 @@
if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
flags = updateFlagsForPackage(flags, userId, null);
final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, false /* checkShell */,
"get installed packages");
@@ -8457,7 +7931,7 @@
String[] permissions, int flags, int userId) {
if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
flags = updateFlagsForPackage(flags, userId, permissions);
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
"get packages holding permissions");
final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
@@ -8562,7 +8036,7 @@
mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_INSTANT_APPS,
"getEphemeralApplications");
}
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
"getEphemeralApplications");
synchronized (mPackages) {
@@ -8577,7 +8051,7 @@
@Override
public boolean isInstantApp(String packageName, int userId) {
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
"isInstantApp");
if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
@@ -8610,7 +8084,7 @@
return null;
}
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
"getInstantAppCookie");
if (!isCallerSameApp(packageName, Binder.getCallingUid())) {
@@ -8628,7 +8102,7 @@
return true;
}
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, true /* checkShell */,
"setInstantAppCookie");
if (!isCallerSameApp(packageName, Binder.getCallingUid())) {
@@ -8650,7 +8124,7 @@
mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_INSTANT_APPS,
"getInstantAppIcon");
}
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
"getInstantAppIcon");
@@ -8710,6 +8184,10 @@
@Override
public ProviderInfo resolveContentProvider(String name, int flags, int userId) {
+ return resolveContentProviderInternal(name, flags, userId);
+ }
+
+ private ProviderInfo resolveContentProviderInternal(String name, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
flags = updateFlagsForComponent(flags, userId, name);
final String instantAppPkgName = getInstantAppPackageName(Binder.getCallingUid());
@@ -10255,7 +9733,8 @@
}
}
- private void addSharedLibraryLPr(ArraySet<String> usesLibraryFiles, SharedLibraryEntry file,
+ private void addSharedLibraryLPr(Set<String> usesLibraryFiles,
+ SharedLibraryEntry file,
PackageParser.Package changingLib) {
if (file.path != null) {
usesLibraryFiles.add(file.path);
@@ -10284,7 +9763,10 @@
if (pkg == null) {
return;
}
- ArraySet<String> usesLibraryFiles = null;
+ // The collection used here must maintain the order of addition (so
+ // that libraries are searched in the correct order) and must have no
+ // duplicates.
+ Set<String> usesLibraryFiles = null;
if (pkg.usesLibraries != null) {
usesLibraryFiles = addSharedLibrariesLPw(pkg.usesLibraries,
null, null, pkg.packageName, changingLib, true,
@@ -10308,10 +9790,10 @@
}
}
- private ArraySet<String> addSharedLibrariesLPw(@NonNull List<String> requestedLibraries,
+ private Set<String> addSharedLibrariesLPw(@NonNull List<String> requestedLibraries,
@Nullable int[] requiredVersions, @Nullable String[][] requiredCertDigests,
@NonNull String packageName, @Nullable PackageParser.Package changingLib,
- boolean required, int targetSdk, @Nullable ArraySet<String> outUsedLibraries)
+ boolean required, int targetSdk, @Nullable Set<String> outUsedLibraries)
throws PackageManagerException {
final int libCount = requestedLibraries.size();
for (int i = 0; i < libCount; i++) {
@@ -10377,7 +9859,9 @@
}
if (outUsedLibraries == null) {
- outUsedLibraries = new ArraySet<>();
+ // Use LinkedHashSet to preserve the order of files added to
+ // usesLibraryFiles while eliminating duplicates.
+ outUsedLibraries = new LinkedHashSet<>();
}
addSharedLibraryLPr(outUsedLibraries, libEntry, changingLib);
}
@@ -11739,12 +11223,25 @@
}
}
- final ArrayMap<String, BasePermission> permissionMap =
- p.tree ? mSettings.mPermissionTrees
- : mSettings.mPermissions;
- final BasePermission bp = BasePermission.createOrUpdate(
- permissionMap.get(p.info.name), p, pkg, mSettings.mPermissionTrees, chatty);
- permissionMap.put(p.info.name, bp);
+ // TODO Move to PermissionManager once mPermissionTrees moves there.
+// p.tree ? mSettings.mPermissionTrees
+// : mSettings.mPermissions;
+// final BasePermission bp = BasePermission.createOrUpdate(
+// permissionMap.get(p.info.name), p, pkg, mSettings.mPermissionTrees, chatty);
+// permissionMap.put(p.info.name, bp);
+ if (p.tree) {
+ final ArrayMap<String, BasePermission> permissionMap =
+ mSettings.mPermissionTrees;
+ final BasePermission bp = BasePermission.createOrUpdate(
+ permissionMap.get(p.info.name), p, pkg, mSettings.mPermissionTrees,
+ chatty);
+ permissionMap.put(p.info.name, bp);
+ } else {
+ final BasePermission bp = BasePermission.createOrUpdate(
+ (BasePermission) mPermissionManager.getPermissionTEMP(p.info.name),
+ p, pkg, mSettings.mPermissionTrees, chatty);
+ mPermissionManager.putPermissionTEMP(p.info.name, bp);
+ }
}
N = pkg.instrumentation.size();
@@ -12474,7 +11971,7 @@
r = null;
for (i=0; i<N; i++) {
PackageParser.Permission p = pkg.permissions.get(i);
- BasePermission bp = mSettings.mPermissions.get(p.info.name);
+ BasePermission bp = (BasePermission) mPermissionManager.getPermissionTEMP(p.info.name);
if (bp == null) {
bp = mSettings.mPermissionTrees.get(p.info.name);
}
@@ -12504,8 +12001,7 @@
r = null;
for (i=0; i<N; i++) {
String perm = pkg.requestedPermissions.get(i);
- BasePermission bp = mSettings.mPermissions.get(perm);
- if (bp != null && bp.isAppOp()) {
+ if (mPermissionManager.isPermissionAppOp(perm)) {
ArraySet<String> appOpPkgs = mAppOpPermissionPackages.get(perm);
if (appOpPkgs != null) {
appOpPkgs.remove(pkg.packageName);
@@ -12644,9 +12140,10 @@
// Make sure all dynamic permissions have been assigned to a package,
// and make sure there are no dangling permissions.
- it = mSettings.mPermissions.values().iterator();
- while (it.hasNext()) {
- final BasePermission bp = it.next();
+ final Iterator<BasePermission> permissionIter =
+ mPermissionManager.getPermissionIteratorTEMP();
+ while (permissionIter.hasNext()) {
+ final BasePermission bp = permissionIter.next();
if (bp.isDynamic()) {
bp.updateDynamicPermission(mSettings.mPermissionTrees);
}
@@ -12658,13 +12155,13 @@
if (bp.getSourcePackageSetting() == null) {
Slog.w(TAG, "Removing dangling permission: " + bp.getName()
+ " from package " + bp.getSourcePackageName());
- it.remove();
+ permissionIter.remove();
} else if (changingPkg != null && changingPkg.equals(bp.getSourcePackageName())) {
if (pkgInfo == null || !hasPermission(pkgInfo, bp.getName())) {
Slog.i(TAG, "Removing old permission: " + bp.getName()
+ " from package " + bp.getSourcePackageName());
flags |= UPDATE_PERMISSIONS_ALL;
- it.remove();
+ permissionIter.remove();
}
}
}
@@ -12733,8 +12230,9 @@
// the runtime ones are written only if changed. The only cases of
// changed runtime permissions here are promotion of an install to
// runtime and revocation of a runtime from a shared user.
- changedRuntimePermissionUserIds = revokeUnusedSharedUserPermissionsLPw(
- ps.sharedUser, UserManagerService.getInstance().getUserIds());
+ changedRuntimePermissionUserIds =
+ mPermissionManager.revokeUnusedSharedUserPermissions(
+ ps.sharedUser, UserManagerService.getInstance().getUserIds());
if (!ArrayUtils.isEmpty(changedRuntimePermissionUserIds)) {
runtimePermissionsRevoked = true;
}
@@ -12746,7 +12244,7 @@
final int N = pkg.requestedPermissions.size();
for (int i=0; i<N; i++) {
final String name = pkg.requestedPermissions.get(i);
- final BasePermission bp = mSettings.mPermissions.get(name);
+ final BasePermission bp = (BasePermission) mPermissionManager.getPermissionTEMP(name);
final boolean appSupportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
>= Build.VERSION_CODES.M;
@@ -14505,7 +14003,7 @@
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, true /* checkShell */, "installPackageAsUser");
if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
@@ -14744,7 +14242,7 @@
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
PackageSetting pkgSetting;
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, true /* checkShell */,
"setApplicationHiddenSetting for user " + userId);
@@ -14846,7 +14344,7 @@
public boolean getApplicationHiddenSettingAsUser(String packageName, int userId) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, false /* checkShell */,
"getApplicationHidden for user " + userId);
PackageSetting ps;
@@ -14878,7 +14376,7 @@
null);
PackageSetting pkgSetting;
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, true /* checkShell */,
"installExistingPackage for user " + userId);
if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
@@ -14983,7 +14481,7 @@
int userId) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, true /* checkShell */,
"setPackagesSuspended for user " + userId);
@@ -15044,7 +14542,7 @@
@Override
public boolean isPackageSuspendedForUser(String packageName, int userId) {
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, false /* checkShell */,
"isPackageSuspendedForUser for user " + userId);
synchronized (mPackages) {
@@ -15491,7 +14989,7 @@
synchronized (mPackages) {
boolean result = mSettings.setDefaultBrowserPackageNameLPw(packageName, userId);
if (packageName != null) {
- mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultBrowserLPr(
+ mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultBrowser(
packageName, userId);
}
return result;
@@ -17635,66 +17133,6 @@
}
}
- private int[] revokeUnusedSharedUserPermissionsLPw(SharedUserSetting su, int[] allUserIds) {
- // Collect all used permissions in the UID
- ArraySet<String> usedPermissions = new ArraySet<>();
- final int packageCount = su.packages.size();
- for (int i = 0; i < packageCount; i++) {
- PackageSetting ps = su.packages.valueAt(i);
- if (ps.pkg == null) {
- continue;
- }
- final int requestedPermCount = ps.pkg.requestedPermissions.size();
- for (int j = 0; j < requestedPermCount; j++) {
- String permission = ps.pkg.requestedPermissions.get(j);
- BasePermission bp = mSettings.mPermissions.get(permission);
- if (bp != null) {
- usedPermissions.add(permission);
- }
- }
- }
-
- PermissionsState permissionsState = su.getPermissionsState();
- // Prune install permissions
- List<PermissionState> installPermStates = permissionsState.getInstallPermissionStates();
- final int installPermCount = installPermStates.size();
- for (int i = installPermCount - 1; i >= 0; i--) {
- PermissionState permissionState = installPermStates.get(i);
- if (!usedPermissions.contains(permissionState.getName())) {
- BasePermission bp = mSettings.mPermissions.get(permissionState.getName());
- if (bp != null) {
- permissionsState.revokeInstallPermission(bp);
- permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
- PackageManager.MASK_PERMISSION_FLAGS, 0);
- }
- }
- }
-
- int[] runtimePermissionChangedUserIds = EmptyArray.INT;
-
- // Prune runtime permissions
- for (int userId : allUserIds) {
- List<PermissionState> runtimePermStates = permissionsState
- .getRuntimePermissionStates(userId);
- final int runtimePermCount = runtimePermStates.size();
- for (int i = runtimePermCount - 1; i >= 0; i--) {
- PermissionState permissionState = runtimePermStates.get(i);
- if (!usedPermissions.contains(permissionState.getName())) {
- BasePermission bp = mSettings.mPermissions.get(permissionState.getName());
- if (bp != null) {
- permissionsState.revokeRuntimePermission(bp, userId);
- permissionsState.updatePermissionFlags(bp, userId,
- PackageManager.MASK_PERMISSION_FLAGS, 0);
- runtimePermissionChangedUserIds = ArrayUtils.appendInt(
- runtimePermissionChangedUserIds, userId);
- }
- }
- }
- }
-
- return runtimePermissionChangedUserIds;
- }
-
private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
int[] allUsers, PackageInstalledInfo res, UserHandle user, int installReason) {
// Update the parent package setting
@@ -18095,8 +17533,9 @@
int N = pkg.permissions.size();
for (int i = N-1; i >= 0; i--) {
- PackageParser.Permission perm = pkg.permissions.get(i);
- BasePermission bp = mSettings.mPermissions.get(perm.info.name);
+ final PackageParser.Permission perm = pkg.permissions.get(i);
+ final BasePermission bp =
+ (BasePermission) mPermissionManager.getPermissionTEMP(perm.info.name);
// Don't allow anyone but the system to define ephemeral permissions.
if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0
@@ -18266,7 +17705,13 @@
// TODO: Layering violation
BackgroundDexOptService.notifyPackageChanged(pkg.packageName);
- startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
+ if (!instantApp) {
+ startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
+ } else {
+ if (DEBUG_DOMAIN_VERIFICATION) {
+ Slog.d(TAG, "Not verifying instant app install for app links: " + pkgName);
+ }
+ }
try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
"installPackageLI")) {
@@ -19851,7 +19296,7 @@
android.Manifest.permission.CLEAR_APP_USER_DATA, null);
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, false /* checkShell */, "clear application data");
final PackageSetting ps = mSettings.getPackageLPr(packageName);
@@ -19990,8 +19435,9 @@
final int permissionCount = ps.pkg.requestedPermissions.size();
for (int i = 0; i < permissionCount; i++) {
- final String permissionName = ps.pkg.requestedPermissions.get(i);
- final BasePermission bp = mSettings.mPermissions.get(permissionName);
+ final String permName = ps.pkg.requestedPermissions.get(i);
+ final BasePermission bp =
+ (BasePermission) mPermissionManager.getPermissionTEMP(permName);
if (bp == null) {
continue;
}
@@ -20003,7 +19449,7 @@
for (int j = 0; j < packageCount; j++) {
PackageSetting pkg = ps.sharedUser.packages.valueAt(j);
if (pkg.pkg != null && !pkg.pkg.packageName.equals(ps.pkg.packageName)
- && pkg.pkg.requestedPermissions.contains(permissionName)) {
+ && pkg.pkg.requestedPermissions.contains(permName)) {
used = true;
break;
}
@@ -20015,11 +19461,11 @@
final PermissionsState permissionsState = ps.getPermissionsState();
- final int oldFlags = permissionsState.getPermissionFlags(permissionName, userId);
+ final int oldFlags = permissionsState.getPermissionFlags(permName, userId);
// Always clear the user settable flags.
final boolean hasInstallState =
- permissionsState.getInstallPermissionState(permissionName) != null;
+ permissionsState.getInstallPermissionState(permName) != null;
// If permission review is enabled and this is a legacy app, mark the
// permission as requiring a review as this is the initial state.
int flags = 0;
@@ -20119,7 +19565,7 @@
final int callingUid = Binder.getCallingUid();
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DELETE_CACHE_FILES, null);
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
/* requireFullPermission= */ true, /* checkShell= */ false,
"delete application cache files");
final int hasAccessInstantApps = mContext.checkCallingOrSelfPermission(
@@ -20239,7 +19685,7 @@
String opname) {
// writer
int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, false /* checkShell */, "add preferred activity");
if (filter.countActions() == 0) {
Slog.w(TAG, "Cannot set a preferred activity with no filter actions");
@@ -20304,7 +19750,7 @@
}
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, false /* checkShell */,
"replace preferred activity");
synchronized (mPackages) {
@@ -20981,8 +20427,11 @@
newFlagSet |= FLAG_PERMISSION_REVOKE_ON_UPGRADE;
}
if (DEBUG_BACKUP) {
- Slog.v(TAG, " + Restoring grant: pkg=" + pkgName + " perm=" + permName
- + " granted=" + isGranted + " bits=0x" + Integer.toHexString(newFlagSet));
+ Slog.v(TAG, " + Restoring grant:"
+ + " pkg=" + pkgName
+ + " perm=" + permName
+ + " granted=" + isGranted
+ + " bits=0x" + Integer.toHexString(newFlagSet));
}
final PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
@@ -20991,13 +20440,15 @@
Slog.v(TAG, " + already installed; applying");
}
PermissionsState perms = ps.getPermissionsState();
- BasePermission bp = mSettings.mPermissions.get(permName);
+ BasePermission bp =
+ (BasePermission) mPermissionManager.getPermissionTEMP(permName);
if (bp != null) {
if (isGranted) {
perms.grantRuntimePermission(bp, userId);
}
if (newFlagSet != 0) {
- perms.updatePermissionFlags(bp, userId, USER_RUNTIME_GRANT_MASK, newFlagSet);
+ perms.updatePermissionFlags(
+ bp, userId, USER_RUNTIME_GRANT_MASK, newFlagSet);
}
}
} else {
@@ -21026,7 +20477,8 @@
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
int callingUid = Binder.getCallingUid();
enforceOwnerRights(ownerPackage, callingUid);
- enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
+ PackageManagerServiceUtils.enforceShellRestriction(
+ UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
if (intentFilter.countActions() == 0) {
Slog.w(TAG, "Cannot set a crossProfile intent filter with no filter actions");
return;
@@ -21057,7 +20509,8 @@
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
final int callingUid = Binder.getCallingUid();
enforceOwnerRights(ownerPackage, callingUid);
- enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
+ PackageManagerServiceUtils.enforceShellRestriction(
+ UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
synchronized (mPackages) {
CrossProfileIntentResolver resolver =
mSettings.editCrossProfileIntentResolverLPw(sourceUserId);
@@ -21287,7 +20740,7 @@
permission = mContext.checkCallingOrSelfPermission(
android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
}
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, true /* checkShell */, "set enabled");
final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
boolean sendNow = false;
@@ -21576,7 +21029,7 @@
if (!sUserManager.exists(userId)) {
return;
}
- enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission*/,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission*/,
false /* checkShell */, "flushPackageRestrictions");
synchronized (mPackages) {
mSettings.writePackageRestrictionsLPr(userId);
@@ -21618,7 +21071,7 @@
final int permission = mContext.checkCallingOrSelfPermission(
android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, true /* checkShell */, "stop package");
// writer
synchronized (mPackages) {
@@ -21658,7 +21111,7 @@
public int getApplicationEnabledSetting(String packageName, int userId) {
if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */, "get enabled");
// reader
synchronized (mPackages) {
@@ -21673,7 +21126,7 @@
public int getComponentEnabledSetting(ComponentName component, int userId) {
if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/, "getComponentEnabled");
synchronized (mPackages) {
if (filterAppAccessLPr(mSettings.getPackageLPr(component.getPackageName()), callingUid,
@@ -21771,7 +21224,7 @@
// If we upgraded grant all default permissions before kicking off.
for (int userId : grantPermissionsUserIds) {
- mDefaultPermissionPolicy.grantDefaultPermissions(userId);
+ mDefaultPermissionPolicy.grantDefaultPermissions(mPackages.values(), userId);
}
if (grantPermissionsUserIds == EMPTY_INT_ARRAY) {
@@ -23856,7 +23309,9 @@
}
void onNewUserCreated(final int userId) {
- mDefaultPermissionPolicy.grantDefaultPermissions(userId);
+ synchronized(mPackages) {
+ mDefaultPermissionPolicy.grantDefaultPermissions(mPackages.values(), userId);
+ }
// If permission review for legacy apps is required, we represent
// dagerous permissions for such apps as always granted runtime
// permissions to keep per user flag state whether review is needed.
@@ -24296,70 +23751,129 @@
private class PackageManagerInternalImpl extends PackageManagerInternal {
@Override
- public void setLocationPackagesProvider(PackagesProvider provider) {
+ public void updatePermissionFlagsTEMP(String permName, String packageName, int flagMask,
+ int flagValues, int userId) {
+ PackageManagerService.this.updatePermissionFlags(
+ permName, packageName, flagMask, flagValues, userId);
+ }
+
+ @Override
+ public int getPermissionFlagsTEMP(String permName, String packageName, int userId) {
+ return PackageManagerService.this.getPermissionFlags(permName, packageName, userId);
+ }
+
+ @Override
+ public Object enforcePermissionTreeTEMP(String permName, int callingUid) {
synchronized (mPackages) {
- mDefaultPermissionPolicy.setLocationPackagesProviderLPw(provider);
+ return BasePermission.enforcePermissionTreeLP(
+ mSettings.mPermissionTrees, permName, callingUid);
}
}
+ @Override
+ public boolean isInstantApp(String packageName, int userId) {
+ return PackageManagerService.this.isInstantApp(packageName, userId);
+ }
+
+ @Override
+ public String getInstantAppPackageName(int uid) {
+ return PackageManagerService.this.getInstantAppPackageName(uid);
+ }
+
+ @Override
+ public boolean filterAppAccess(PackageParser.Package pkg, int callingUid, int userId) {
+ synchronized (mPackages) {
+ return PackageManagerService.this.filterAppAccessLPr(
+ (PackageSetting) pkg.mExtras, callingUid, userId);
+ }
+ }
+
+ @Override
+ public PackageParser.Package getPackage(String packageName) {
+ synchronized (mPackages) {
+ packageName = resolveInternalPackageNameLPr(
+ packageName, PackageManager.VERSION_CODE_HIGHEST);
+ return mPackages.get(packageName);
+ }
+ }
+
+ @Override
+ public PackageParser.Package getDisabledPackage(String packageName) {
+ synchronized (mPackages) {
+ final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
+ return (ps != null) ? ps.pkg : null;
+ }
+ }
+
+ @Override
+ public String getKnownPackageName(int knownPackage, int userId) {
+ switch(knownPackage) {
+ case PackageManagerInternal.PACKAGE_BROWSER:
+ return getDefaultBrowserPackageName(userId);
+ case PackageManagerInternal.PACKAGE_INSTALLER:
+ return mRequiredInstallerPackage;
+ case PackageManagerInternal.PACKAGE_SETUP_WIZARD:
+ return mSetupWizardPackage;
+ case PackageManagerInternal.PACKAGE_SYSTEM:
+ return "android";
+ case PackageManagerInternal.PACKAGE_VERIFIER:
+ return mRequiredVerifierPackage;
+ }
+ return null;
+ }
+
+ @Override
+ public boolean isResolveActivityComponent(ComponentInfo component) {
+ return mResolveActivity.packageName.equals(component.packageName)
+ && mResolveActivity.name.equals(component.name);
+ }
+
+ @Override
+ public void setLocationPackagesProvider(PackagesProvider provider) {
+ mDefaultPermissionPolicy.setLocationPackagesProvider(provider);
+ }
@Override
public void setVoiceInteractionPackagesProvider(PackagesProvider provider) {
- synchronized (mPackages) {
- mDefaultPermissionPolicy.setVoiceInteractionPackagesProviderLPw(provider);
- }
+ mDefaultPermissionPolicy.setVoiceInteractionPackagesProvider(provider);
}
@Override
public void setSmsAppPackagesProvider(PackagesProvider provider) {
- synchronized (mPackages) {
- mDefaultPermissionPolicy.setSmsAppPackagesProviderLPw(provider);
- }
+ mDefaultPermissionPolicy.setSmsAppPackagesProvider(provider);
}
@Override
public void setDialerAppPackagesProvider(PackagesProvider provider) {
- synchronized (mPackages) {
- mDefaultPermissionPolicy.setDialerAppPackagesProviderLPw(provider);
- }
+ mDefaultPermissionPolicy.setDialerAppPackagesProvider(provider);
}
@Override
public void setSimCallManagerPackagesProvider(PackagesProvider provider) {
- synchronized (mPackages) {
- mDefaultPermissionPolicy.setSimCallManagerPackagesProviderLPw(provider);
- }
+ mDefaultPermissionPolicy.setSimCallManagerPackagesProvider(provider);
}
@Override
public void setSyncAdapterPackagesprovider(SyncAdapterPackagesProvider provider) {
- synchronized (mPackages) {
- mDefaultPermissionPolicy.setSyncAdapterPackagesProviderLPw(provider);
- }
+ mDefaultPermissionPolicy.setSyncAdapterPackagesProvider(provider);
}
@Override
public void grantDefaultPermissionsToDefaultSmsApp(String packageName, int userId) {
- synchronized (mPackages) {
- mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultSmsAppLPr(
- packageName, userId);
- }
+ mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultSmsApp(packageName, userId);
}
@Override
public void grantDefaultPermissionsToDefaultDialerApp(String packageName, int userId) {
synchronized (mPackages) {
mSettings.setDefaultDialerPackageNameLPw(packageName, userId);
- mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultDialerAppLPr(
- packageName, userId);
}
+ mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultDialerApp(packageName, userId);
}
@Override
public void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId) {
- synchronized (mPackages) {
- mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultSimCallManagerLPr(
- packageName, userId);
- }
+ mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultSimCallManager(
+ packageName, userId);
}
@Override
@@ -24446,6 +23960,15 @@
}
@Override
+ public List<ResolveInfo> queryIntentServices(
+ Intent intent, int flags, int callingUid, int userId) {
+ final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
+ return PackageManagerService.this
+ .queryIntentServicesInternal(intent, resolvedType, flags, userId, callingUid,
+ false);
+ }
+
+ @Override
public ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
int userId) {
return PackageManagerService.this.getHomeActivitiesAsUser(allHomeCandidates, userId);
@@ -24480,17 +24003,19 @@
}
@Override
- public void grantRuntimePermission(String packageName, String name, int userId,
+ public void grantRuntimePermission(String packageName, String permName, int userId,
boolean overridePolicy) {
- PackageManagerService.this.grantRuntimePermission(packageName, name, userId,
- overridePolicy);
+ PackageManagerService.this.mPermissionManager.grantRuntimePermission(
+ permName, packageName, overridePolicy, getCallingUid(), userId,
+ mPermissionCallback);
}
@Override
- public void revokeRuntimePermission(String packageName, String name, int userId,
+ public void revokeRuntimePermission(String packageName, String permName, int userId,
boolean overridePolicy) {
- PackageManagerService.this.revokeRuntimePermission(packageName, name, userId,
- overridePolicy);
+ mPermissionManager.revokeRuntimePermission(
+ permName, packageName, overridePolicy, getCallingUid(), userId,
+ mPermissionCallback);
}
@Override
@@ -24612,9 +24137,9 @@
@Override
public ResolveInfo resolveIntent(Intent intent, String resolvedType,
- int flags, int userId) {
+ int flags, int userId, boolean resolveForStart) {
return resolveIntentInternal(
- intent, resolvedType, flags, userId, true /*resolveForStart*/);
+ intent, resolvedType, flags, userId, resolveForStart);
}
@Override
@@ -24624,6 +24149,12 @@
}
@Override
+ public ProviderInfo resolveContentProvider(String name, int flags, int userId) {
+ return PackageManagerService.this.resolveContentProviderInternal(
+ name, flags, userId);
+ }
+
+ @Override
public void addIsolatedUid(int isolatedUid, int ownerUid) {
synchronized (mPackages) {
mIsolatedOwners.put(isolatedUid, ownerUid);
@@ -24670,7 +24201,7 @@
synchronized (mPackages) {
final long identity = Binder.clearCallingIdentity();
try {
- mDefaultPermissionPolicy.grantDefaultPermissionsToEnabledCarrierAppsLPr(
+ mDefaultPermissionPolicy.grantDefaultPermissionsToEnabledCarrierApps(
packageNames, userId);
} finally {
Binder.restoreCallingIdentity(identity);
@@ -24684,7 +24215,7 @@
synchronized (mPackages) {
final long identity = Binder.clearCallingIdentity();
try {
- mDefaultPermissionPolicy.grantDefaultPermissionsToEnabledImsServicesLPr(
+ mDefaultPermissionPolicy.grantDefaultPermissionsToEnabledImsServices(
packageNames, userId);
} finally {
Binder.restoreCallingIdentity(identity);
@@ -24759,7 +24290,7 @@
@Override
public int getInstallReason(String packageName, int userId) {
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId,
+ mPermissionManager.enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, false /* checkShell */,
"get install reason");
synchronized (mPackages) {
@@ -24837,7 +24368,7 @@
public String getInstantAppAndroidId(String packageName, int userId) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_INSTANT_APPS,
"getInstantAppAndroidId");
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
"getInstantAppAndroidId");
// Make sure the target is an Instant App.
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 48ddf5e..8f7971e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -30,6 +30,8 @@
import android.content.pm.PackageParser;
import android.content.pm.ResolveInfo;
import android.os.Build;
+import android.os.Debug;
+import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.system.ErrnoException;
@@ -314,4 +316,18 @@
}
}
}
+
+ public static void enforceShellRestriction(String restriction, int callingUid, int userHandle) {
+ if (callingUid == Process.SHELL_UID) {
+ if (userHandle >= 0
+ && PackageManagerService.sUserManager.hasUserRestriction(
+ restriction, userHandle)) {
+ throw new SecurityException("Shell does not have permission to access user "
+ + userHandle);
+ } else if (userHandle < 0) {
+ Slog.e(PackageManagerService.TAG, "Unable to check shell permission for user "
+ + userHandle + "\n\t" + Debug.getCallers(3));
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 88fe3c1..83cb2db2 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -23,13 +23,15 @@
import android.service.pm.PackageProto;
import android.util.proto.ProtoOutputStream;
+import com.android.server.pm.permission.PermissionsState;
+
import java.io.File;
import java.util.List;
/**
* Settings data for a particular package we know about.
*/
-final class PackageSetting extends PackageSettingBase {
+public final class PackageSetting extends PackageSettingBase {
int appId;
PackageParser.Package pkg;
/**
@@ -110,6 +112,14 @@
: super.getPermissionsState();
}
+ public PackageParser.Package getPackage() {
+ return pkg;
+ }
+
+ public int getAppId() {
+ return appId;
+ }
+
public boolean isPrivileged() {
return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
}
@@ -138,6 +148,10 @@
return true;
}
+ public boolean hasChildPackages() {
+ return childPackageNames != null && !childPackageNames.isEmpty();
+ }
+
public void writeToProto(ProtoOutputStream proto, long fieldId, List<UserInfo> users) {
final long packageToken = proto.start(fieldId);
proto.write(PackageProto.NAME, (realName != null ? realName : name));
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 0d4878f..e19e83f 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -413,7 +413,7 @@
modifyUserState(userId).suspended = suspended;
}
- boolean getInstantApp(int userId) {
+ public boolean getInstantApp(int userId) {
return readUserState(userId).instantApp;
}
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index e17cec0..c97f5e5 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -18,6 +18,8 @@
import android.content.pm.ApplicationInfo;
+import com.android.server.pm.permission.PermissionsState;
+
abstract class SettingBase {
int pkgFlags;
int pkgPrivateFlags;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 06cf79a..0084411 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -86,8 +86,10 @@
import com.android.internal.util.JournaledFile;
import com.android.internal.util.XmlUtils;
import com.android.server.pm.Installer.InstallerException;
-import com.android.server.pm.PermissionsState.PermissionState;
import com.android.server.pm.permission.BasePermission;
+import com.android.server.pm.permission.PermissionSettings;
+import com.android.server.pm.permission.PermissionsState;
+import com.android.server.pm.permission.PermissionsState.PermissionState;
import libcore.io.IoUtils;
@@ -376,10 +378,6 @@
private final ArrayMap<Long, Integer> mKeySetRefs =
new ArrayMap<Long, Integer>();
- // Mapping from permission names to info about them.
- final ArrayMap<String, BasePermission> mPermissions =
- new ArrayMap<String, BasePermission>();
-
// Mapping from permission tree names to info about them.
final ArrayMap<String, BasePermission> mPermissionTrees =
new ArrayMap<String, BasePermission>();
@@ -417,14 +415,16 @@
private final File mSystemDir;
public final KeySetManagerService mKeySetManagerService = new KeySetManagerService(mPackages);
+ /** Settings and other information about permissions */
+ private final PermissionSettings mPermissions;
- Settings(Object lock) {
- this(Environment.getDataDirectory(), lock);
+ Settings(PermissionSettings permissions, Object lock) {
+ this(Environment.getDataDirectory(), permissions, lock);
}
- Settings(File dataDir, Object lock) {
+ Settings(File dataDir, PermissionSettings permission, Object lock) {
mLock = lock;
-
+ mPermissions = permission;
mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);
mSystemDir = new File(dataDir, "system");
@@ -487,7 +487,7 @@
final PermissionsState perms = ps.getPermissionsState();
for (RestoredPermissionGrant grant : grants) {
- BasePermission bp = mPermissions.get(grant.permissionName);
+ BasePermission bp = mPermissions.getPermission(grant.permissionName);
if (bp != null) {
if (grant.granted) {
perms.grantRuntimePermission(bp, userId);
@@ -504,6 +504,10 @@
writeRuntimePermissionsForUserLPr(userId, false);
}
+ public boolean canPropagatePermissionToInstantApp(String permName) {
+ return mPermissions.canPropagatePermissionToInstantApp(permName);
+ }
+
void setInstallerPackageName(String pkgName, String installerPkgName) {
PackageSetting p = mPackages.get(pkgName);
if (p != null) {
@@ -661,16 +665,11 @@
}
}
- // Transfer ownership of permissions from one package to another.
+ /**
+ * Transfers ownership of permissions from one package to another.
+ */
void transferPermissionsLPw(String origPackageName, String newPackageName) {
- // Transfer ownership of permissions to the new package.
- for (int i=0; i<2; i++) {
- ArrayMap<String, BasePermission> permissions =
- i == 0 ? mPermissionTrees : mPermissions;
- for (BasePermission bp : permissions.values()) {
- bp.transfer(origPackageName, newPackageName);
- }
- }
+ mPermissions.transferPermissions(origPackageName, newPackageName, mPermissionTrees);
}
/**
@@ -1058,7 +1057,7 @@
// Update permissions
for (String eachPerm : deletedPs.pkg.requestedPermissions) {
- BasePermission bp = mPermissions.get(eachPerm);
+ BasePermission bp = mPermissions.getPermission(eachPerm);
if (bp == null) {
continue;
}
@@ -2208,7 +2207,7 @@
if (tagName.equals(TAG_ITEM)) {
String name = parser.getAttributeValue(null, ATTR_NAME);
- BasePermission bp = mPermissions.get(name);
+ BasePermission bp = mPermissions.getPermission(name);
if (bp == null) {
Slog.w(PackageManagerService.TAG, "Unknown permission: " + name);
XmlUtils.skipCurrentTag(parser);
@@ -2503,9 +2502,7 @@
serializer.endTag(null, "permission-trees");
serializer.startTag(null, "permissions");
- for (BasePermission bp : mPermissions.values()) {
- writePermissionLPr(serializer, bp);
- }
+ mPermissions.writePermissions(serializer);
serializer.endTag(null, "permissions");
for (final PackageSetting pkg : mPackages.values()) {
@@ -3043,9 +3040,9 @@
if (tagName.equals("package")) {
readPackageLPw(parser);
} else if (tagName.equals("permissions")) {
- readPermissionsLPw(mPermissions, parser);
+ mPermissions.readPermissions(parser);
} else if (tagName.equals("permission-trees")) {
- readPermissionsLPw(mPermissionTrees, parser);
+ PermissionSettings.readPermissions(mPermissionTrees, parser);
} else if (tagName.equals("shared-user")) {
readSharedUserLPw(parser);
} else if (tagName.equals("preferred-packages")) {
@@ -3549,25 +3546,6 @@
}
}
- private void readPermissionsLPw(ArrayMap<String, BasePermission> out, XmlPullParser parser)
- throws IOException, XmlPullParserException {
- int outerDepth = parser.getDepth();
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
-
- if (!BasePermission.readLPw(out, parser)) {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Unknown element reading permissions: " + parser.getName() + " at "
- + parser.getPositionDescription());
- }
- XmlUtils.skipCurrentTag(parser);
- }
- }
-
private void readDisabledSysPackageLPw(XmlPullParser parser) throws XmlPullParserException,
IOException {
String name = parser.getAttributeValue(null, ATTR_NAME);
@@ -4906,11 +4884,8 @@
void dumpPermissionsLPr(PrintWriter pw, String packageName, ArraySet<String> permissionNames,
DumpState dumpState) {
- boolean printedSomething = false;
- for (BasePermission bp : mPermissions.values()) {
- printedSomething = bp.dumpPermissionsLPr(pw, packageName, permissionNames,
- mReadExternalStorageEnforced == Boolean.TRUE, printedSomething, dumpState);
- }
+ mPermissions.dumpPermissions(pw, packageName, permissionNames,
+ (mReadExternalStorageEnforced == Boolean.TRUE), dumpState);
}
void dumpSharedUsersLPr(PrintWriter pw, String packageName, ArraySet<String> permissionNames,
@@ -5341,7 +5316,7 @@
PermissionsState permissionsState = sb.getPermissionsState();
for (PermissionState permissionState
: permissionsState.getRuntimePermissionStates(userId)) {
- BasePermission bp = mPermissions.get(permissionState.getName());
+ BasePermission bp = mPermissions.getPermission(permissionState.getName());
if (bp != null) {
permissionsState.revokeRuntimePermission(bp, userId);
permissionsState.updatePermissionFlags(bp, userId,
@@ -5502,7 +5477,7 @@
switch (parser.getName()) {
case TAG_ITEM: {
String name = parser.getAttributeValue(null, ATTR_NAME);
- BasePermission bp = mPermissions.get(name);
+ BasePermission bp = mPermissions.getPermission(name);
if (bp == null) {
Slog.w(PackageManagerService.TAG, "Unknown permission:" + name);
XmlUtils.skipCurrentTag(parser);
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 06e020a..a0dadae 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -16,12 +16,18 @@
package com.android.server.pm;
+import android.annotation.Nullable;
+import android.content.pm.PackageParser;
import android.util.ArraySet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
/**
* Settings data for a particular shared user ID we know about.
*/
-final class SharedUserSetting extends SettingBase {
+public final class SharedUserSetting extends SettingBase {
final String name;
int userId;
@@ -73,4 +79,18 @@
setPrivateFlags(this.pkgPrivateFlags | packageSetting.pkgPrivateFlags);
}
}
+
+ public @Nullable List<PackageParser.Package> getPackages() {
+ if (packages == null || packages.size() == 0) {
+ return null;
+ }
+ final ArrayList<PackageParser.Package> pkgList = new ArrayList<>(packages.size());
+ for (PackageSetting ps : packages) {
+ if (ps == null) {
+ continue;
+ }
+ pkgList.add(ps.pkg);
+ }
+ return pkgList;
+ }
}
diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
index 3060840..f922ad1 100644
--- a/services/core/java/com/android/server/pm/ShortcutLauncher.java
+++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
@@ -25,6 +25,7 @@
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.ShortcutService.DumpFilter;
import com.android.server.pm.ShortcutUser.PackageWithUser;
import org.json.JSONException;
@@ -293,7 +294,7 @@
return ret;
}
- public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
+ public void dump(@NonNull PrintWriter pw, @NonNull String prefix, DumpFilter filter) {
pw.println();
pw.print(prefix);
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 9309f18..6fc1e73 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -33,6 +33,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
+import com.android.server.pm.ShortcutService.DumpFilter;
import com.android.server.pm.ShortcutService.ShortcutOperation;
import com.android.server.pm.ShortcutService.Stats;
@@ -1144,7 +1145,7 @@
return false;
}
- public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
+ public void dump(@NonNull PrintWriter pw, @NonNull String prefix, DumpFilter filter) {
pw.println();
pw.print(prefix);
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 15d2071..27560c5f 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -40,8 +40,8 @@
import android.content.pm.LauncherApps.ShortcutQuery;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
@@ -134,6 +134,7 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Predicate;
+import java.util.regex.Pattern;
/**
* TODO:
@@ -3455,121 +3456,265 @@
@VisibleForTesting
void dumpNoCheck(FileDescriptor fd, PrintWriter pw, String[] args) {
+ final DumpFilter filter = parseDumpArgs(args);
- boolean dumpMain = true;
- boolean checkin = false;
- boolean clear = false;
- boolean dumpUid = false;
- boolean dumpFiles = false;
-
- if (args != null) {
- for (String arg : args) {
- if ("-c".equals(arg)) {
- checkin = true;
-
- } else if ("--checkin".equals(arg)) {
- checkin = true;
- clear = true;
-
- } else if ("-a".equals(arg) || "--all".equals(arg)) {
- dumpUid = true;
- dumpFiles = true;
-
- } else if ("-u".equals(arg) || "--uid".equals(arg)) {
- dumpUid = true;
-
- } else if ("-f".equals(arg) || "--files".equals(arg)) {
- dumpFiles = true;
-
- } else if ("-n".equals(arg) || "--no-main".equals(arg)) {
- dumpMain = false;
- }
- }
- }
-
- if (checkin) {
+ if (filter.shouldDumpCheckIn()) {
// Other flags are not supported for checkin.
- dumpCheckin(pw, clear);
+ dumpCheckin(pw, filter.shouldCheckInClear());
} else {
- if (dumpMain) {
- dumpInner(pw);
+ if (filter.shouldDumpMain()) {
+ dumpInner(pw, filter);
pw.println();
}
- if (dumpUid) {
+ if (filter.shouldDumpUid()) {
dumpUid(pw);
pw.println();
}
- if (dumpFiles) {
+ if (filter.shouldDumpFiles()) {
dumpDumpFiles(pw);
pw.println();
}
}
}
- private void dumpInner(PrintWriter pw) {
- synchronized (mLock) {
- final long now = injectCurrentTimeMillis();
- pw.print("Now: [");
- pw.print(now);
- pw.print("] ");
- pw.print(formatTime(now));
+ private static DumpFilter parseDumpArgs(String[] args) {
+ final DumpFilter filter = new DumpFilter();
+ if (args == null) {
+ return filter;
+ }
- pw.print(" Raw last reset: [");
- pw.print(mRawLastResetTime);
- pw.print("] ");
- pw.print(formatTime(mRawLastResetTime));
+ int argIndex = 0;
+ while (argIndex < args.length) {
+ final String arg = args[argIndex++];
- final long last = getLastResetTimeLocked();
- pw.print(" Last reset: [");
- pw.print(last);
- pw.print("] ");
- pw.print(formatTime(last));
+ if ("-c".equals(arg)) {
+ filter.setDumpCheckIn(true);
+ continue;
+ }
+ if ("--checkin".equals(arg)) {
+ filter.setDumpCheckIn(true);
+ filter.setCheckInClear(true);
+ continue;
+ }
+ if ("-a".equals(arg) || "--all".equals(arg)) {
+ filter.setDumpUid(true);
+ filter.setDumpFiles(true);
+ continue;
+ }
+ if ("-u".equals(arg) || "--uid".equals(arg)) {
+ filter.setDumpUid(true);
+ continue;
+ }
+ if ("-f".equals(arg) || "--files".equals(arg)) {
+ filter.setDumpFiles(true);
+ continue;
+ }
+ if ("-n".equals(arg) || "--no-main".equals(arg)) {
+ filter.setDumpMain(false);
+ continue;
+ }
+ if ("--user".equals(arg)) {
+ if (argIndex >= args.length) {
+ throw new IllegalArgumentException("Missing user ID for --user");
+ }
+ try {
+ filter.addUser(Integer.parseInt(args[argIndex++]));
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid user ID", e);
+ }
+ continue;
+ }
+ if ("-p".equals(arg) || "--package".equals(arg)) {
+ if (argIndex >= args.length) {
+ throw new IllegalArgumentException("Missing package name for --package");
+ }
+ filter.addPackageRegex(args[argIndex++]);
+ filter.setDumpDetails(false);
+ continue;
+ }
+ if (arg.startsWith("-")) {
+ throw new IllegalArgumentException("Unknown option " + arg);
+ }
+ break;
+ }
+ while (argIndex < args.length) {
+ filter.addPackage(args[argIndex++]);
+ }
+ return filter;
+ }
- final long next = getNextResetTimeLocked();
- pw.print(" Next reset: [");
- pw.print(next);
- pw.print("] ");
- pw.print(formatTime(next));
+ static class DumpFilter {
+ private boolean mDumpCheckIn = false;
+ private boolean mCheckInClear = false;
- pw.print(" Config:");
- pw.print(" Max icon dim: ");
- pw.println(mMaxIconDimension);
- pw.print(" Icon format: ");
- pw.println(mIconPersistFormat);
- pw.print(" Icon quality: ");
- pw.println(mIconPersistQuality);
- pw.print(" saveDelayMillis: ");
- pw.println(mSaveDelayMillis);
- pw.print(" resetInterval: ");
- pw.println(mResetInterval);
- pw.print(" maxUpdatesPerInterval: ");
- pw.println(mMaxUpdatesPerInterval);
- pw.print(" maxShortcutsPerActivity: ");
- pw.println(mMaxShortcuts);
- pw.println();
+ private boolean mDumpMain = true;
+ private boolean mDumpUid = false;
+ private boolean mDumpFiles = false;
- pw.println(" Stats:");
- synchronized (mStatLock) {
- for (int i = 0; i < Stats.COUNT; i++) {
- dumpStatLS(pw, " ", i);
+ private boolean mDumpDetails = true;
+ private List<Pattern> mPackagePatterns = new ArrayList<>();
+ private List<Integer> mUsers = new ArrayList<>();
+
+ void addPackageRegex(String regex) {
+ mPackagePatterns.add(Pattern.compile(regex));
+ }
+
+ public void addPackage(String packageName) {
+ addPackageRegex(Pattern.quote(packageName));
+ }
+
+ void addUser(int userId) {
+ mUsers.add(userId);
+ }
+
+ boolean isPackageMatch(String packageName) {
+ if (mPackagePatterns.size() == 0) {
+ return true;
+ }
+ for (int i = 0; i < mPackagePatterns.size(); i++) {
+ if (mPackagePatterns.get(i).matcher(packageName).find()) {
+ return true;
}
}
+ return false;
+ }
- pw.println();
- pw.print(" #Failures: ");
- pw.println(mWtfCount);
+ boolean isUserMatch(int userId) {
+ if (mUsers.size() == 0) {
+ return true;
+ }
+ for (int i = 0; i < mUsers.size(); i++) {
+ if (mUsers.get(i) == userId) {
+ return true;
+ }
+ }
+ return false;
+ }
- if (mLastWtfStacktrace != null) {
- pw.print(" Last failure stack trace: ");
- pw.println(Log.getStackTraceString(mLastWtfStacktrace));
+ public boolean shouldDumpCheckIn() {
+ return mDumpCheckIn;
+ }
+
+ public void setDumpCheckIn(boolean dumpCheckIn) {
+ mDumpCheckIn = dumpCheckIn;
+ }
+
+ public boolean shouldCheckInClear() {
+ return mCheckInClear;
+ }
+
+ public void setCheckInClear(boolean checkInClear) {
+ mCheckInClear = checkInClear;
+ }
+
+ public boolean shouldDumpMain() {
+ return mDumpMain;
+ }
+
+ public void setDumpMain(boolean dumpMain) {
+ mDumpMain = dumpMain;
+ }
+
+ public boolean shouldDumpUid() {
+ return mDumpUid;
+ }
+
+ public void setDumpUid(boolean dumpUid) {
+ mDumpUid = dumpUid;
+ }
+
+ public boolean shouldDumpFiles() {
+ return mDumpFiles;
+ }
+
+ public void setDumpFiles(boolean dumpFiles) {
+ mDumpFiles = dumpFiles;
+ }
+
+ public boolean shouldDumpDetails() {
+ return mDumpDetails;
+ }
+
+ public void setDumpDetails(boolean dumpDetails) {
+ mDumpDetails = dumpDetails;
+ }
+ }
+
+ private void dumpInner(PrintWriter pw) {
+ dumpInner(pw, new DumpFilter());
+ }
+
+ private void dumpInner(PrintWriter pw, DumpFilter filter) {
+ synchronized (mLock) {
+ if (filter.shouldDumpDetails()) {
+ final long now = injectCurrentTimeMillis();
+ pw.print("Now: [");
+ pw.print(now);
+ pw.print("] ");
+ pw.print(formatTime(now));
+
+ pw.print(" Raw last reset: [");
+ pw.print(mRawLastResetTime);
+ pw.print("] ");
+ pw.print(formatTime(mRawLastResetTime));
+
+ final long last = getLastResetTimeLocked();
+ pw.print(" Last reset: [");
+ pw.print(last);
+ pw.print("] ");
+ pw.print(formatTime(last));
+
+ final long next = getNextResetTimeLocked();
+ pw.print(" Next reset: [");
+ pw.print(next);
+ pw.print("] ");
+ pw.print(formatTime(next));
+
+ pw.print(" Config:");
+ pw.print(" Max icon dim: ");
+ pw.println(mMaxIconDimension);
+ pw.print(" Icon format: ");
+ pw.println(mIconPersistFormat);
+ pw.print(" Icon quality: ");
+ pw.println(mIconPersistQuality);
+ pw.print(" saveDelayMillis: ");
+ pw.println(mSaveDelayMillis);
+ pw.print(" resetInterval: ");
+ pw.println(mResetInterval);
+ pw.print(" maxUpdatesPerInterval: ");
+ pw.println(mMaxUpdatesPerInterval);
+ pw.print(" maxShortcutsPerActivity: ");
+ pw.println(mMaxShortcuts);
+ pw.println();
+
+ pw.println(" Stats:");
+ synchronized (mStatLock) {
+ for (int i = 0; i < Stats.COUNT; i++) {
+ dumpStatLS(pw, " ", i);
+ }
+ }
+
+ pw.println();
+ pw.print(" #Failures: ");
+ pw.println(mWtfCount);
+
+ if (mLastWtfStacktrace != null) {
+ pw.print(" Last failure stack trace: ");
+ pw.println(Log.getStackTraceString(mLastWtfStacktrace));
+ }
+
+ pw.println();
+ mShortcutBitmapSaver.dumpLocked(pw, " ");
+
+ pw.println();
}
- pw.println();
- mShortcutBitmapSaver.dumpLocked(pw, " ");
-
for (int i = 0; i < mUsers.size(); i++) {
- pw.println();
- mUsers.valueAt(i).dump(pw, " ");
+ final ShortcutUser user = mUsers.valueAt(i);
+ if (filter.isUserMatch(user.getUserId())) {
+ user.dump(pw, " ", filter);
+ pw.println();
+ }
}
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 2c388c4..55e6d28 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -28,6 +28,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
+import com.android.server.pm.ShortcutService.DumpFilter;
import com.android.server.pm.ShortcutService.InvalidFileFormatException;
import libcore.util.Objects;
@@ -531,44 +532,54 @@
+ " S=" + restoredShortcuts[0]);
}
- public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
- pw.print(prefix);
- pw.print("User: ");
- pw.print(mUserId);
- pw.print(" Known locales: ");
- pw.print(mKnownLocales);
- pw.print(" Last app scan: [");
- pw.print(mLastAppScanTime);
- pw.print("] ");
- pw.print(ShortcutService.formatTime(mLastAppScanTime));
- pw.print(" Last app scan FP: ");
- pw.print(mLastAppScanOsFingerprint);
- pw.println();
+ public void dump(@NonNull PrintWriter pw, @NonNull String prefix, DumpFilter filter) {
+ if (filter.shouldDumpDetails()) {
+ pw.print(prefix);
+ pw.print("User: ");
+ pw.print(mUserId);
+ pw.print(" Known locales: ");
+ pw.print(mKnownLocales);
+ pw.print(" Last app scan: [");
+ pw.print(mLastAppScanTime);
+ pw.print("] ");
+ pw.print(ShortcutService.formatTime(mLastAppScanTime));
+ pw.print(" Last app scan FP: ");
+ pw.print(mLastAppScanOsFingerprint);
+ pw.println();
- prefix += prefix + " ";
+ prefix += prefix + " ";
- pw.print(prefix);
- pw.print("Cached launcher: ");
- pw.print(mCachedLauncher);
- pw.println();
+ pw.print(prefix);
+ pw.print("Cached launcher: ");
+ pw.print(mCachedLauncher);
+ pw.println();
- pw.print(prefix);
- pw.print("Last known launcher: ");
- pw.print(mLastKnownLauncher);
- pw.println();
+ pw.print(prefix);
+ pw.print("Last known launcher: ");
+ pw.print(mLastKnownLauncher);
+ pw.println();
+ }
for (int i = 0; i < mLaunchers.size(); i++) {
- mLaunchers.valueAt(i).dump(pw, prefix);
+ ShortcutLauncher launcher = mLaunchers.valueAt(i);
+ if (filter.isPackageMatch(launcher.getPackageName())) {
+ launcher.dump(pw, prefix, filter);
+ }
}
for (int i = 0; i < mPackages.size(); i++) {
- mPackages.valueAt(i).dump(pw, prefix);
+ ShortcutPackage pkg = mPackages.valueAt(i);
+ if (filter.isPackageMatch(pkg.getPackageName())) {
+ pkg.dump(pw, prefix, filter);
+ }
}
- pw.println();
- pw.print(prefix);
- pw.println("Bitmap directories: ");
- dumpDirectorySize(pw, prefix + " ", mService.getUserBitmapFilePath(mUserId));
+ if (filter.shouldDumpDetails()) {
+ pw.println();
+ pw.print(prefix);
+ pw.println("Bitmap directories: ");
+ dumpDirectorySize(pw, prefix + " ", mService.getUserBitmapFilePath(mUserId));
+ }
}
private void dumpDirectorySize(@NonNull PrintWriter pw,
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index f2d527b..1e5245c 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1055,7 +1055,7 @@
/** Called by PackageManagerService */
public boolean exists(int userId) {
- return getUserInfoNoChecks(userId) != null;
+ return mLocalService.exists(userId);
}
@Override
@@ -3502,8 +3502,8 @@
* @param userId
* @return whether the user has been initialized yet
*/
- boolean isInitialized(int userId) {
- return (getUserInfo(userId).flags & UserInfo.FLAG_INITIALIZED) != 0;
+ boolean isUserInitialized(int userId) {
+ return mLocalService.isUserInitialized(userId);
}
private class LocalService extends UserManagerInternal {
@@ -3715,6 +3715,16 @@
}
return state == UserState.STATE_RUNNING_UNLOCKED;
}
+
+ @Override
+ public boolean isUserInitialized(int userId) {
+ return (getUserInfo(userId).flags & UserInfo.FLAG_INITIALIZED) != 0;
+ }
+
+ @Override
+ public boolean exists(int userId) {
+ return getUserInfoNoChecks(userId) != null;
+ }
}
/* Remove all the users except of the system one. */
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
new file mode 100644
index 0000000..161efd3
--- /dev/null
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -0,0 +1,1296 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.permission;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.DownloadManager;
+import android.app.admin.DevicePolicyManager;
+import android.companion.CompanionDeviceManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.PackageParser;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.PackageManagerInternal.PackagesProvider;
+import android.content.pm.PackageManagerInternal.SyncAdapterPackagesProvider;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.UserHandle;
+import android.os.storage.StorageManager;
+import android.print.PrintManager;
+import android.provider.CalendarContract;
+import android.provider.ContactsContract;
+import android.provider.MediaStore;
+import android.provider.Telephony.Sms.Intents;
+import android.telephony.TelephonyManager;
+import android.security.Credentials;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+import android.util.Xml;
+import com.android.internal.util.XmlUtils;
+import com.android.server.LocalServices;
+import com.android.server.pm.PackageManagerService;
+import com.android.server.pm.PackageSetting;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static android.os.Process.FIRST_APPLICATION_UID;
+
+/**
+ * This class is the policy for granting runtime permissions to
+ * platform components and default handlers in the system such
+ * that the device is usable out-of-the-box. For example, the
+ * shell UID is a part of the system and the Phone app should
+ * have phone related permission by default.
+ * <p>
+ * NOTE: This class is at the wrong abstraction level. It is a part of the package manager
+ * service but knows about lots of higher level subsystems. The correct way to do this is
+ * to have an interface defined in the package manager but have the impl next to other
+ * policy stuff like PhoneWindowManager
+ */
+public final class DefaultPermissionGrantPolicy {
+ private static final String TAG = "DefaultPermGrantPolicy"; // must be <= 23 chars
+ private static final boolean DEBUG = false;
+
+ private static final int DEFAULT_FLAGS =
+ PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES;
+
+ private static final String AUDIO_MIME_TYPE = "audio/mpeg";
+
+ private static final String TAG_EXCEPTIONS = "exceptions";
+ private static final String TAG_EXCEPTION = "exception";
+ private static final String TAG_PERMISSION = "permission";
+ private static final String ATTR_PACKAGE = "package";
+ private static final String ATTR_NAME = "name";
+ private static final String ATTR_FIXED = "fixed";
+
+ private static final Set<String> PHONE_PERMISSIONS = new ArraySet<>();
+ static {
+ PHONE_PERMISSIONS.add(Manifest.permission.READ_PHONE_STATE);
+ PHONE_PERMISSIONS.add(Manifest.permission.CALL_PHONE);
+ PHONE_PERMISSIONS.add(Manifest.permission.READ_CALL_LOG);
+ PHONE_PERMISSIONS.add(Manifest.permission.WRITE_CALL_LOG);
+ PHONE_PERMISSIONS.add(Manifest.permission.ADD_VOICEMAIL);
+ PHONE_PERMISSIONS.add(Manifest.permission.USE_SIP);
+ PHONE_PERMISSIONS.add(Manifest.permission.PROCESS_OUTGOING_CALLS);
+ }
+
+ private static final Set<String> CONTACTS_PERMISSIONS = new ArraySet<>();
+ static {
+ CONTACTS_PERMISSIONS.add(Manifest.permission.READ_CONTACTS);
+ CONTACTS_PERMISSIONS.add(Manifest.permission.WRITE_CONTACTS);
+ CONTACTS_PERMISSIONS.add(Manifest.permission.GET_ACCOUNTS);
+ }
+
+ private static final Set<String> LOCATION_PERMISSIONS = new ArraySet<>();
+ static {
+ LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_FINE_LOCATION);
+ LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION);
+ }
+
+ private static final Set<String> CALENDAR_PERMISSIONS = new ArraySet<>();
+ static {
+ CALENDAR_PERMISSIONS.add(Manifest.permission.READ_CALENDAR);
+ CALENDAR_PERMISSIONS.add(Manifest.permission.WRITE_CALENDAR);
+ }
+
+ private static final Set<String> SMS_PERMISSIONS = new ArraySet<>();
+ static {
+ SMS_PERMISSIONS.add(Manifest.permission.SEND_SMS);
+ SMS_PERMISSIONS.add(Manifest.permission.RECEIVE_SMS);
+ SMS_PERMISSIONS.add(Manifest.permission.READ_SMS);
+ SMS_PERMISSIONS.add(Manifest.permission.RECEIVE_WAP_PUSH);
+ SMS_PERMISSIONS.add(Manifest.permission.RECEIVE_MMS);
+ SMS_PERMISSIONS.add(Manifest.permission.READ_CELL_BROADCASTS);
+ }
+
+ private static final Set<String> MICROPHONE_PERMISSIONS = new ArraySet<>();
+ static {
+ MICROPHONE_PERMISSIONS.add(Manifest.permission.RECORD_AUDIO);
+ }
+
+ private static final Set<String> CAMERA_PERMISSIONS = new ArraySet<>();
+ static {
+ CAMERA_PERMISSIONS.add(Manifest.permission.CAMERA);
+ }
+
+ private static final Set<String> SENSORS_PERMISSIONS = new ArraySet<>();
+ static {
+ SENSORS_PERMISSIONS.add(Manifest.permission.BODY_SENSORS);
+ }
+
+ private static final Set<String> STORAGE_PERMISSIONS = new ArraySet<>();
+ static {
+ STORAGE_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE);
+ STORAGE_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
+ }
+
+ private static final int MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS = 1;
+
+ private static final String ACTION_TRACK = "com.android.fitness.TRACK";
+
+ private final Handler mHandler;
+
+ private PackagesProvider mLocationPackagesProvider;
+ private PackagesProvider mVoiceInteractionPackagesProvider;
+ private PackagesProvider mSmsAppPackagesProvider;
+ private PackagesProvider mDialerAppPackagesProvider;
+ private PackagesProvider mSimCallManagerPackagesProvider;
+ private SyncAdapterPackagesProvider mSyncAdapterPackagesProvider;
+
+ private ArrayMap<String, List<DefaultPermissionGrant>> mGrantExceptions;
+ private final Context mContext;
+ private final Object mLock = new Object();
+ private final PackageManagerInternal mServiceInternal;
+ private final PermissionManagerService mPermissionManager;
+ private final DefaultPermissionGrantedCallback mPermissionGrantedCallback;
+ public interface DefaultPermissionGrantedCallback {
+ /** Callback when permissions have been granted */
+ public void onDefaultRuntimePermissionsGranted(int userId);
+ }
+
+ public DefaultPermissionGrantPolicy(Context context, Looper looper,
+ @Nullable DefaultPermissionGrantedCallback callback,
+ @NonNull PermissionManagerService permissionManager) {
+ mContext = context;
+ mHandler = new Handler(looper) {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS) {
+ synchronized (mLock) {
+ if (mGrantExceptions == null) {
+ mGrantExceptions = readDefaultPermissionExceptionsLocked();
+ }
+ }
+ }
+ }
+ };
+ mPermissionGrantedCallback = callback;
+ mPermissionManager = permissionManager;
+ mServiceInternal = LocalServices.getService(PackageManagerInternal.class);
+ }
+
+ public void setLocationPackagesProvider(PackagesProvider provider) {
+ synchronized (mLock) {
+ mLocationPackagesProvider = provider;
+ }
+ }
+
+ public void setVoiceInteractionPackagesProvider(PackagesProvider provider) {
+ synchronized (mLock) {
+ mVoiceInteractionPackagesProvider = provider;
+ }
+ }
+
+ public void setSmsAppPackagesProvider(PackagesProvider provider) {
+ synchronized (mLock) {
+ mSmsAppPackagesProvider = provider;
+ }
+ }
+
+ public void setDialerAppPackagesProvider(PackagesProvider provider) {
+ synchronized (mLock) {
+ mDialerAppPackagesProvider = provider;
+ }
+ }
+
+ public void setSimCallManagerPackagesProvider(PackagesProvider provider) {
+ synchronized (mLock) {
+ mSimCallManagerPackagesProvider = provider;
+ }
+ }
+
+ public void setSyncAdapterPackagesProvider(SyncAdapterPackagesProvider provider) {
+ synchronized (mLock) {
+ mSyncAdapterPackagesProvider = provider;
+ }
+ }
+
+ public void grantDefaultPermissions(Collection<PackageParser.Package> packages, int userId) {
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_EMBEDDED, 0)) {
+ grantAllRuntimePermissions(packages, userId);
+ } else {
+ grantPermissionsToSysComponentsAndPrivApps(packages, userId);
+ grantDefaultSystemHandlerPermissions(userId);
+ grantDefaultPermissionExceptions(userId);
+ }
+ }
+
+ private void grantRuntimePermissionsForPackage(int userId, PackageParser.Package pkg) {
+ Set<String> permissions = new ArraySet<>();
+ for (String permission : pkg.requestedPermissions) {
+ final BasePermission bp = mPermissionManager.getPermission(permission);
+ if (bp == null) {
+ continue;
+ }
+ if (bp.isRuntime()) {
+ permissions.add(permission);
+ }
+ }
+ if (!permissions.isEmpty()) {
+ grantRuntimePermissions(pkg, permissions, true, userId);
+ }
+ }
+
+ private void grantAllRuntimePermissions(
+ Collection<PackageParser.Package> packages, int userId) {
+ Log.i(TAG, "Granting all runtime permissions for user " + userId);
+ for (PackageParser.Package pkg : packages) {
+ grantRuntimePermissionsForPackage(userId, pkg);
+ }
+ }
+
+ public void scheduleReadDefaultPermissionExceptions() {
+ mHandler.sendEmptyMessage(MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS);
+ }
+
+ private void grantPermissionsToSysComponentsAndPrivApps(
+ Collection<PackageParser.Package> packages, int userId) {
+ Log.i(TAG, "Granting permissions to platform components for user " + userId);
+ for (PackageParser.Package pkg : packages) {
+ if (!isSysComponentOrPersistentPlatformSignedPrivApp(pkg)
+ || !doesPackageSupportRuntimePermissions(pkg)
+ || pkg.requestedPermissions.isEmpty()) {
+ continue;
+ }
+ grantRuntimePermissionsForPackage(userId, pkg);
+ }
+ }
+
+ private void grantDefaultSystemHandlerPermissions(int userId) {
+ Log.i(TAG, "Granting permissions to default platform handlers for user " + userId);
+
+ final PackagesProvider locationPackagesProvider;
+ final PackagesProvider voiceInteractionPackagesProvider;
+ final PackagesProvider smsAppPackagesProvider;
+ final PackagesProvider dialerAppPackagesProvider;
+ final PackagesProvider simCallManagerPackagesProvider;
+ final SyncAdapterPackagesProvider syncAdapterPackagesProvider;
+
+ synchronized (mLock) {
+ locationPackagesProvider = mLocationPackagesProvider;
+ voiceInteractionPackagesProvider = mVoiceInteractionPackagesProvider;
+ smsAppPackagesProvider = mSmsAppPackagesProvider;
+ dialerAppPackagesProvider = mDialerAppPackagesProvider;
+ simCallManagerPackagesProvider = mSimCallManagerPackagesProvider;
+ syncAdapterPackagesProvider = mSyncAdapterPackagesProvider;
+ }
+
+ String[] voiceInteractPackageNames = (voiceInteractionPackagesProvider != null)
+ ? voiceInteractionPackagesProvider.getPackages(userId) : null;
+ String[] locationPackageNames = (locationPackagesProvider != null)
+ ? locationPackagesProvider.getPackages(userId) : null;
+ String[] smsAppPackageNames = (smsAppPackagesProvider != null)
+ ? smsAppPackagesProvider.getPackages(userId) : null;
+ String[] dialerAppPackageNames = (dialerAppPackagesProvider != null)
+ ? dialerAppPackagesProvider.getPackages(userId) : null;
+ String[] simCallManagerPackageNames = (simCallManagerPackagesProvider != null)
+ ? simCallManagerPackagesProvider.getPackages(userId) : null;
+ String[] contactsSyncAdapterPackages = (syncAdapterPackagesProvider != null) ?
+ syncAdapterPackagesProvider.getPackages(ContactsContract.AUTHORITY, userId) : null;
+ String[] calendarSyncAdapterPackages = (syncAdapterPackagesProvider != null) ?
+ syncAdapterPackagesProvider.getPackages(CalendarContract.AUTHORITY, userId) : null;
+
+ // Installer
+ final String installerPackageName = mServiceInternal.getKnownPackageName(
+ PackageManagerInternal.PACKAGE_INSTALLER, userId);
+ PackageParser.Package installerPackage = getSystemPackage(installerPackageName);
+ if (installerPackage != null
+ && doesPackageSupportRuntimePermissions(installerPackage)) {
+ grantRuntimePermissions(installerPackage, STORAGE_PERMISSIONS, true, userId);
+ }
+
+ // Verifier
+ final String verifierPackageName = mServiceInternal.getKnownPackageName(
+ PackageManagerInternal.PACKAGE_VERIFIER, userId);
+ PackageParser.Package verifierPackage = getSystemPackage(verifierPackageName);
+ if (verifierPackage != null
+ && doesPackageSupportRuntimePermissions(verifierPackage)) {
+ grantRuntimePermissions(verifierPackage, STORAGE_PERMISSIONS, true, userId);
+ grantRuntimePermissions(verifierPackage, PHONE_PERMISSIONS, false, userId);
+ grantRuntimePermissions(verifierPackage, SMS_PERMISSIONS, false, userId);
+ }
+
+ // SetupWizard
+ final String setupWizardPackageName = mServiceInternal.getKnownPackageName(
+ PackageManagerInternal.PACKAGE_SETUP_WIZARD, userId);
+ PackageParser.Package setupPackage = getSystemPackage(setupWizardPackageName);
+ if (setupPackage != null
+ && doesPackageSupportRuntimePermissions(setupPackage)) {
+ grantRuntimePermissions(setupPackage, PHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(setupPackage, CONTACTS_PERMISSIONS, userId);
+ grantRuntimePermissions(setupPackage, LOCATION_PERMISSIONS, userId);
+ grantRuntimePermissions(setupPackage, CAMERA_PERMISSIONS, userId);
+ }
+
+ // Camera
+ Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+ PackageParser.Package cameraPackage = getDefaultSystemHandlerActivityPackage(
+ cameraIntent, userId);
+ if (cameraPackage != null
+ && doesPackageSupportRuntimePermissions(cameraPackage)) {
+ grantRuntimePermissions(cameraPackage, CAMERA_PERMISSIONS, userId);
+ grantRuntimePermissions(cameraPackage, MICROPHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(cameraPackage, STORAGE_PERMISSIONS, userId);
+ }
+
+ // Media provider
+ PackageParser.Package mediaStorePackage = getDefaultProviderAuthorityPackage(
+ MediaStore.AUTHORITY, userId);
+ if (mediaStorePackage != null) {
+ grantRuntimePermissions(mediaStorePackage, STORAGE_PERMISSIONS, true, userId);
+ }
+
+ // Downloads provider
+ PackageParser.Package downloadsPackage = getDefaultProviderAuthorityPackage(
+ "downloads", userId);
+ if (downloadsPackage != null) {
+ grantRuntimePermissions(downloadsPackage, STORAGE_PERMISSIONS, true, userId);
+ }
+
+ // Downloads UI
+ Intent downloadsUiIntent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
+ PackageParser.Package downloadsUiPackage = getDefaultSystemHandlerActivityPackage(
+ downloadsUiIntent, userId);
+ if (downloadsUiPackage != null
+ && doesPackageSupportRuntimePermissions(downloadsUiPackage)) {
+ grantRuntimePermissions(downloadsUiPackage, STORAGE_PERMISSIONS, true, userId);
+ }
+
+ // Storage provider
+ PackageParser.Package storagePackage = getDefaultProviderAuthorityPackage(
+ "com.android.externalstorage.documents", userId);
+ if (storagePackage != null) {
+ grantRuntimePermissions(storagePackage, STORAGE_PERMISSIONS, true, userId);
+ }
+
+ // CertInstaller
+ Intent certInstallerIntent = new Intent(Credentials.INSTALL_ACTION);
+ PackageParser.Package certInstallerPackage = getDefaultSystemHandlerActivityPackage(
+ certInstallerIntent, userId);
+ if (certInstallerPackage != null
+ && doesPackageSupportRuntimePermissions(certInstallerPackage)) {
+ grantRuntimePermissions(certInstallerPackage, STORAGE_PERMISSIONS, true, userId);
+ }
+
+ // Dialer
+ if (dialerAppPackageNames == null) {
+ Intent dialerIntent = new Intent(Intent.ACTION_DIAL);
+ PackageParser.Package dialerPackage = getDefaultSystemHandlerActivityPackage(
+ dialerIntent, userId);
+ if (dialerPackage != null) {
+ grantDefaultPermissionsToDefaultSystemDialerApp(dialerPackage, userId);
+ }
+ } else {
+ for (String dialerAppPackageName : dialerAppPackageNames) {
+ PackageParser.Package dialerPackage = getSystemPackage(dialerAppPackageName);
+ if (dialerPackage != null) {
+ grantDefaultPermissionsToDefaultSystemDialerApp(dialerPackage, userId);
+ }
+ }
+ }
+
+ // Sim call manager
+ if (simCallManagerPackageNames != null) {
+ for (String simCallManagerPackageName : simCallManagerPackageNames) {
+ PackageParser.Package simCallManagerPackage =
+ getSystemPackage(simCallManagerPackageName);
+ if (simCallManagerPackage != null) {
+ grantDefaultPermissionsToDefaultSimCallManager(simCallManagerPackage,
+ userId);
+ }
+ }
+ }
+
+ // SMS
+ if (smsAppPackageNames == null) {
+ Intent smsIntent = new Intent(Intent.ACTION_MAIN);
+ smsIntent.addCategory(Intent.CATEGORY_APP_MESSAGING);
+ PackageParser.Package smsPackage = getDefaultSystemHandlerActivityPackage(
+ smsIntent, userId);
+ if (smsPackage != null) {
+ grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId);
+ }
+ } else {
+ for (String smsPackageName : smsAppPackageNames) {
+ PackageParser.Package smsPackage = getSystemPackage(smsPackageName);
+ if (smsPackage != null) {
+ grantDefaultPermissionsToDefaultSystemSmsApp(smsPackage, userId);
+ }
+ }
+ }
+
+ // Cell Broadcast Receiver
+ Intent cbrIntent = new Intent(Intents.SMS_CB_RECEIVED_ACTION);
+ PackageParser.Package cbrPackage =
+ getDefaultSystemHandlerActivityPackage(cbrIntent, userId);
+ if (cbrPackage != null && doesPackageSupportRuntimePermissions(cbrPackage)) {
+ grantRuntimePermissions(cbrPackage, SMS_PERMISSIONS, userId);
+ }
+
+ // Carrier Provisioning Service
+ Intent carrierProvIntent = new Intent(Intents.SMS_CARRIER_PROVISION_ACTION);
+ PackageParser.Package carrierProvPackage =
+ getDefaultSystemHandlerServicePackage(carrierProvIntent, userId);
+ if (carrierProvPackage != null
+ && doesPackageSupportRuntimePermissions(carrierProvPackage)) {
+ grantRuntimePermissions(carrierProvPackage, SMS_PERMISSIONS, false, userId);
+ }
+
+ // Calendar
+ Intent calendarIntent = new Intent(Intent.ACTION_MAIN);
+ calendarIntent.addCategory(Intent.CATEGORY_APP_CALENDAR);
+ PackageParser.Package calendarPackage = getDefaultSystemHandlerActivityPackage(
+ calendarIntent, userId);
+ if (calendarPackage != null
+ && doesPackageSupportRuntimePermissions(calendarPackage)) {
+ grantRuntimePermissions(calendarPackage, CALENDAR_PERMISSIONS, userId);
+ grantRuntimePermissions(calendarPackage, CONTACTS_PERMISSIONS, userId);
+ }
+
+ // Calendar provider
+ PackageParser.Package calendarProviderPackage = getDefaultProviderAuthorityPackage(
+ CalendarContract.AUTHORITY, userId);
+ if (calendarProviderPackage != null) {
+ grantRuntimePermissions(calendarProviderPackage, CONTACTS_PERMISSIONS, userId);
+ grantRuntimePermissions(calendarProviderPackage, CALENDAR_PERMISSIONS,
+ true, userId);
+ grantRuntimePermissions(calendarProviderPackage, STORAGE_PERMISSIONS, userId);
+ }
+
+ // Calendar provider sync adapters
+ List<PackageParser.Package> calendarSyncAdapters = getHeadlessSyncAdapterPackages(
+ calendarSyncAdapterPackages, userId);
+ final int calendarSyncAdapterCount = calendarSyncAdapters.size();
+ for (int i = 0; i < calendarSyncAdapterCount; i++) {
+ PackageParser.Package calendarSyncAdapter = calendarSyncAdapters.get(i);
+ if (doesPackageSupportRuntimePermissions(calendarSyncAdapter)) {
+ grantRuntimePermissions(calendarSyncAdapter, CALENDAR_PERMISSIONS, userId);
+ }
+ }
+
+ // Contacts
+ Intent contactsIntent = new Intent(Intent.ACTION_MAIN);
+ contactsIntent.addCategory(Intent.CATEGORY_APP_CONTACTS);
+ PackageParser.Package contactsPackage = getDefaultSystemHandlerActivityPackage(
+ contactsIntent, userId);
+ if (contactsPackage != null
+ && doesPackageSupportRuntimePermissions(contactsPackage)) {
+ grantRuntimePermissions(contactsPackage, CONTACTS_PERMISSIONS, userId);
+ grantRuntimePermissions(contactsPackage, PHONE_PERMISSIONS, userId);
+ }
+
+ // Contacts provider sync adapters
+ List<PackageParser.Package> contactsSyncAdapters = getHeadlessSyncAdapterPackages(
+ contactsSyncAdapterPackages, userId);
+ final int contactsSyncAdapterCount = contactsSyncAdapters.size();
+ for (int i = 0; i < contactsSyncAdapterCount; i++) {
+ PackageParser.Package contactsSyncAdapter = contactsSyncAdapters.get(i);
+ if (doesPackageSupportRuntimePermissions(contactsSyncAdapter)) {
+ grantRuntimePermissions(contactsSyncAdapter, CONTACTS_PERMISSIONS, userId);
+ }
+ }
+
+ // Contacts provider
+ PackageParser.Package contactsProviderPackage = getDefaultProviderAuthorityPackage(
+ ContactsContract.AUTHORITY, userId);
+ if (contactsProviderPackage != null) {
+ grantRuntimePermissions(contactsProviderPackage, CONTACTS_PERMISSIONS,
+ true, userId);
+ grantRuntimePermissions(contactsProviderPackage, PHONE_PERMISSIONS,
+ true, userId);
+ grantRuntimePermissions(contactsProviderPackage, STORAGE_PERMISSIONS, userId);
+ }
+
+ // Device provisioning
+ Intent deviceProvisionIntent = new Intent(
+ DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE);
+ PackageParser.Package deviceProvisionPackage =
+ getDefaultSystemHandlerActivityPackage(deviceProvisionIntent, userId);
+ if (deviceProvisionPackage != null
+ && doesPackageSupportRuntimePermissions(deviceProvisionPackage)) {
+ grantRuntimePermissions(deviceProvisionPackage, CONTACTS_PERMISSIONS, userId);
+ }
+
+ // Maps
+ Intent mapsIntent = new Intent(Intent.ACTION_MAIN);
+ mapsIntent.addCategory(Intent.CATEGORY_APP_MAPS);
+ PackageParser.Package mapsPackage = getDefaultSystemHandlerActivityPackage(
+ mapsIntent, userId);
+ if (mapsPackage != null
+ && doesPackageSupportRuntimePermissions(mapsPackage)) {
+ grantRuntimePermissions(mapsPackage, LOCATION_PERMISSIONS, userId);
+ }
+
+ // Gallery
+ Intent galleryIntent = new Intent(Intent.ACTION_MAIN);
+ galleryIntent.addCategory(Intent.CATEGORY_APP_GALLERY);
+ PackageParser.Package galleryPackage = getDefaultSystemHandlerActivityPackage(
+ galleryIntent, userId);
+ if (galleryPackage != null
+ && doesPackageSupportRuntimePermissions(galleryPackage)) {
+ grantRuntimePermissions(galleryPackage, STORAGE_PERMISSIONS, userId);
+ }
+
+ // Email
+ Intent emailIntent = new Intent(Intent.ACTION_MAIN);
+ emailIntent.addCategory(Intent.CATEGORY_APP_EMAIL);
+ PackageParser.Package emailPackage = getDefaultSystemHandlerActivityPackage(
+ emailIntent, userId);
+ if (emailPackage != null
+ && doesPackageSupportRuntimePermissions(emailPackage)) {
+ grantRuntimePermissions(emailPackage, CONTACTS_PERMISSIONS, userId);
+ grantRuntimePermissions(emailPackage, CALENDAR_PERMISSIONS, userId);
+ }
+
+ // Browser
+ PackageParser.Package browserPackage = null;
+ String defaultBrowserPackage = mServiceInternal.getKnownPackageName(
+ PackageManagerInternal.PACKAGE_BROWSER, userId);
+ if (defaultBrowserPackage != null) {
+ browserPackage = getPackage(defaultBrowserPackage);
+ }
+ if (browserPackage == null) {
+ Intent browserIntent = new Intent(Intent.ACTION_MAIN);
+ browserIntent.addCategory(Intent.CATEGORY_APP_BROWSER);
+ browserPackage = getDefaultSystemHandlerActivityPackage(
+ browserIntent, userId);
+ }
+ if (browserPackage != null
+ && doesPackageSupportRuntimePermissions(browserPackage)) {
+ grantRuntimePermissions(browserPackage, LOCATION_PERMISSIONS, userId);
+ }
+
+ // Voice interaction
+ if (voiceInteractPackageNames != null) {
+ for (String voiceInteractPackageName : voiceInteractPackageNames) {
+ PackageParser.Package voiceInteractPackage = getSystemPackage(
+ voiceInteractPackageName);
+ if (voiceInteractPackage != null
+ && doesPackageSupportRuntimePermissions(voiceInteractPackage)) {
+ grantRuntimePermissions(voiceInteractPackage,
+ CONTACTS_PERMISSIONS, userId);
+ grantRuntimePermissions(voiceInteractPackage,
+ CALENDAR_PERMISSIONS, userId);
+ grantRuntimePermissions(voiceInteractPackage,
+ MICROPHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(voiceInteractPackage,
+ PHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(voiceInteractPackage,
+ SMS_PERMISSIONS, userId);
+ grantRuntimePermissions(voiceInteractPackage,
+ LOCATION_PERMISSIONS, userId);
+ }
+ }
+ }
+
+ if (ActivityManager.isLowRamDeviceStatic()) {
+ // Allow voice search on low-ram devices
+ Intent globalSearchIntent = new Intent("android.search.action.GLOBAL_SEARCH");
+ PackageParser.Package globalSearchPickerPackage =
+ getDefaultSystemHandlerActivityPackage(globalSearchIntent, userId);
+
+ if (globalSearchPickerPackage != null
+ && doesPackageSupportRuntimePermissions(globalSearchPickerPackage)) {
+ grantRuntimePermissions(globalSearchPickerPackage,
+ MICROPHONE_PERMISSIONS, true, userId);
+ grantRuntimePermissions(globalSearchPickerPackage,
+ LOCATION_PERMISSIONS, true, userId);
+ }
+ }
+
+ // Voice recognition
+ Intent voiceRecoIntent = new Intent("android.speech.RecognitionService");
+ voiceRecoIntent.addCategory(Intent.CATEGORY_DEFAULT);
+ PackageParser.Package voiceRecoPackage = getDefaultSystemHandlerServicePackage(
+ voiceRecoIntent, userId);
+ if (voiceRecoPackage != null
+ && doesPackageSupportRuntimePermissions(voiceRecoPackage)) {
+ grantRuntimePermissions(voiceRecoPackage, MICROPHONE_PERMISSIONS, userId);
+ }
+
+ // Location
+ if (locationPackageNames != null) {
+ for (String packageName : locationPackageNames) {
+ PackageParser.Package locationPackage = getSystemPackage(packageName);
+ if (locationPackage != null
+ && doesPackageSupportRuntimePermissions(locationPackage)) {
+ grantRuntimePermissions(locationPackage, CONTACTS_PERMISSIONS, userId);
+ grantRuntimePermissions(locationPackage, CALENDAR_PERMISSIONS, userId);
+ grantRuntimePermissions(locationPackage, MICROPHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(locationPackage, PHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(locationPackage, SMS_PERMISSIONS, userId);
+ grantRuntimePermissions(locationPackage, LOCATION_PERMISSIONS,
+ true, userId);
+ grantRuntimePermissions(locationPackage, CAMERA_PERMISSIONS, userId);
+ grantRuntimePermissions(locationPackage, SENSORS_PERMISSIONS, userId);
+ grantRuntimePermissions(locationPackage, STORAGE_PERMISSIONS, userId);
+ }
+ }
+ }
+
+ // Music
+ Intent musicIntent = new Intent(Intent.ACTION_VIEW);
+ musicIntent.addCategory(Intent.CATEGORY_DEFAULT);
+ musicIntent.setDataAndType(Uri.fromFile(new File("foo.mp3")),
+ AUDIO_MIME_TYPE);
+ PackageParser.Package musicPackage = getDefaultSystemHandlerActivityPackage(
+ musicIntent, userId);
+ if (musicPackage != null
+ && doesPackageSupportRuntimePermissions(musicPackage)) {
+ grantRuntimePermissions(musicPackage, STORAGE_PERMISSIONS, userId);
+ }
+
+ // Home
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN);
+ homeIntent.addCategory(Intent.CATEGORY_HOME);
+ homeIntent.addCategory(Intent.CATEGORY_LAUNCHER_APP);
+ PackageParser.Package homePackage = getDefaultSystemHandlerActivityPackage(
+ homeIntent, userId);
+ if (homePackage != null
+ && doesPackageSupportRuntimePermissions(homePackage)) {
+ grantRuntimePermissions(homePackage, LOCATION_PERMISSIONS, false, userId);
+ }
+
+ // Watches
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH, 0)) {
+ // Home application on watches
+ Intent wearHomeIntent = new Intent(Intent.ACTION_MAIN);
+ wearHomeIntent.addCategory(Intent.CATEGORY_HOME_MAIN);
+
+ PackageParser.Package wearHomePackage = getDefaultSystemHandlerActivityPackage(
+ wearHomeIntent, userId);
+
+ if (wearHomePackage != null
+ && doesPackageSupportRuntimePermissions(wearHomePackage)) {
+ grantRuntimePermissions(wearHomePackage, CONTACTS_PERMISSIONS, false,
+ userId);
+ grantRuntimePermissions(wearHomePackage, PHONE_PERMISSIONS, true, userId);
+ grantRuntimePermissions(wearHomePackage, MICROPHONE_PERMISSIONS, false,
+ userId);
+ grantRuntimePermissions(wearHomePackage, LOCATION_PERMISSIONS, false,
+ userId);
+ }
+
+ // Fitness tracking on watches
+ Intent trackIntent = new Intent(ACTION_TRACK);
+ PackageParser.Package trackPackage = getDefaultSystemHandlerActivityPackage(
+ trackIntent, userId);
+ if (trackPackage != null
+ && doesPackageSupportRuntimePermissions(trackPackage)) {
+ grantRuntimePermissions(trackPackage, SENSORS_PERMISSIONS, false, userId);
+ grantRuntimePermissions(trackPackage, LOCATION_PERMISSIONS, false, userId);
+ }
+ }
+
+ // Print Spooler
+ PackageParser.Package printSpoolerPackage = getSystemPackage(
+ PrintManager.PRINT_SPOOLER_PACKAGE_NAME);
+ if (printSpoolerPackage != null
+ && doesPackageSupportRuntimePermissions(printSpoolerPackage)) {
+ grantRuntimePermissions(printSpoolerPackage, LOCATION_PERMISSIONS, true, userId);
+ }
+
+ // EmergencyInfo
+ Intent emergencyInfoIntent = new Intent(TelephonyManager.ACTION_EMERGENCY_ASSISTANCE);
+ PackageParser.Package emergencyInfoPckg = getDefaultSystemHandlerActivityPackage(
+ emergencyInfoIntent, userId);
+ if (emergencyInfoPckg != null
+ && doesPackageSupportRuntimePermissions(emergencyInfoPckg)) {
+ grantRuntimePermissions(emergencyInfoPckg, CONTACTS_PERMISSIONS, true, userId);
+ grantRuntimePermissions(emergencyInfoPckg, PHONE_PERMISSIONS, true, userId);
+ }
+
+ // NFC Tag viewer
+ Intent nfcTagIntent = new Intent(Intent.ACTION_VIEW);
+ nfcTagIntent.setType("vnd.android.cursor.item/ndef_msg");
+ PackageParser.Package nfcTagPkg = getDefaultSystemHandlerActivityPackage(
+ nfcTagIntent, userId);
+ if (nfcTagPkg != null
+ && doesPackageSupportRuntimePermissions(nfcTagPkg)) {
+ grantRuntimePermissions(nfcTagPkg, CONTACTS_PERMISSIONS, false, userId);
+ grantRuntimePermissions(nfcTagPkg, PHONE_PERMISSIONS, false, userId);
+ }
+
+ // Storage Manager
+ Intent storageManagerIntent = new Intent(StorageManager.ACTION_MANAGE_STORAGE);
+ PackageParser.Package storageManagerPckg = getDefaultSystemHandlerActivityPackage(
+ storageManagerIntent, userId);
+ if (storageManagerPckg != null
+ && doesPackageSupportRuntimePermissions(storageManagerPckg)) {
+ grantRuntimePermissions(storageManagerPckg, STORAGE_PERMISSIONS, true, userId);
+ }
+
+ // Companion devices
+ PackageParser.Package companionDeviceDiscoveryPackage = getSystemPackage(
+ CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME);
+ if (companionDeviceDiscoveryPackage != null
+ && doesPackageSupportRuntimePermissions(companionDeviceDiscoveryPackage)) {
+ grantRuntimePermissions(companionDeviceDiscoveryPackage,
+ LOCATION_PERMISSIONS, true, userId);
+ }
+
+ // Ringtone Picker
+ Intent ringtonePickerIntent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
+ PackageParser.Package ringtonePickerPackage =
+ getDefaultSystemHandlerActivityPackage(ringtonePickerIntent, userId);
+ if (ringtonePickerPackage != null
+ && doesPackageSupportRuntimePermissions(ringtonePickerPackage)) {
+ grantRuntimePermissions(ringtonePickerPackage,
+ STORAGE_PERMISSIONS, true, userId);
+ }
+
+ if (mPermissionGrantedCallback != null) {
+ mPermissionGrantedCallback.onDefaultRuntimePermissionsGranted(userId);
+ }
+ }
+
+ private void grantDefaultPermissionsToDefaultSystemDialerApp(
+ PackageParser.Package dialerPackage, int userId) {
+ if (doesPackageSupportRuntimePermissions(dialerPackage)) {
+ boolean isPhonePermFixed =
+ mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH, 0);
+ grantRuntimePermissions(
+ dialerPackage, PHONE_PERMISSIONS, isPhonePermFixed, userId);
+ grantRuntimePermissions(dialerPackage, CONTACTS_PERMISSIONS, userId);
+ grantRuntimePermissions(dialerPackage, SMS_PERMISSIONS, userId);
+ grantRuntimePermissions(dialerPackage, MICROPHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(dialerPackage, CAMERA_PERMISSIONS, userId);
+ }
+ }
+
+ private void grantDefaultPermissionsToDefaultSystemSmsApp(
+ PackageParser.Package smsPackage, int userId) {
+ if (doesPackageSupportRuntimePermissions(smsPackage)) {
+ grantRuntimePermissions(smsPackage, PHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(smsPackage, CONTACTS_PERMISSIONS, userId);
+ grantRuntimePermissions(smsPackage, SMS_PERMISSIONS, userId);
+ grantRuntimePermissions(smsPackage, STORAGE_PERMISSIONS, userId);
+ grantRuntimePermissions(smsPackage, MICROPHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(smsPackage, CAMERA_PERMISSIONS, userId);
+ }
+ }
+
+ public void grantDefaultPermissionsToDefaultSmsApp(String packageName, int userId) {
+ Log.i(TAG, "Granting permissions to default sms app for user:" + userId);
+ if (packageName == null) {
+ return;
+ }
+ PackageParser.Package smsPackage = getPackage(packageName);
+ if (smsPackage != null && doesPackageSupportRuntimePermissions(smsPackage)) {
+ grantRuntimePermissions(smsPackage, PHONE_PERMISSIONS, false, true, userId);
+ grantRuntimePermissions(smsPackage, CONTACTS_PERMISSIONS, false, true, userId);
+ grantRuntimePermissions(smsPackage, SMS_PERMISSIONS, false, true, userId);
+ grantRuntimePermissions(smsPackage, STORAGE_PERMISSIONS, false, true, userId);
+ grantRuntimePermissions(smsPackage, MICROPHONE_PERMISSIONS, false, true, userId);
+ grantRuntimePermissions(smsPackage, CAMERA_PERMISSIONS, false, true, userId);
+ }
+ }
+
+ public void grantDefaultPermissionsToDefaultDialerApp(String packageName, int userId) {
+ Log.i(TAG, "Granting permissions to default dialer app for user:" + userId);
+ if (packageName == null) {
+ return;
+ }
+ PackageParser.Package dialerPackage = getPackage(packageName);
+ if (dialerPackage != null
+ && doesPackageSupportRuntimePermissions(dialerPackage)) {
+ grantRuntimePermissions(dialerPackage, PHONE_PERMISSIONS, false, true, userId);
+ grantRuntimePermissions(dialerPackage, CONTACTS_PERMISSIONS, false, true, userId);
+ grantRuntimePermissions(dialerPackage, SMS_PERMISSIONS, false, true, userId);
+ grantRuntimePermissions(dialerPackage, MICROPHONE_PERMISSIONS, false, true, userId);
+ grantRuntimePermissions(dialerPackage, CAMERA_PERMISSIONS, false, true, userId);
+ }
+ }
+
+ private void grantDefaultPermissionsToDefaultSimCallManager(
+ PackageParser.Package simCallManagerPackage, int userId) {
+ Log.i(TAG, "Granting permissions to sim call manager for user:" + userId);
+ if (doesPackageSupportRuntimePermissions(simCallManagerPackage)) {
+ grantRuntimePermissions(simCallManagerPackage, PHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(simCallManagerPackage, MICROPHONE_PERMISSIONS, userId);
+ }
+ }
+
+ public void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId) {
+ if (packageName == null) {
+ return;
+ }
+ PackageParser.Package simCallManagerPackage = getPackage(packageName);
+ if (simCallManagerPackage != null) {
+ grantDefaultPermissionsToDefaultSimCallManager(simCallManagerPackage, userId);
+ }
+ }
+
+ public void grantDefaultPermissionsToEnabledCarrierApps(String[] packageNames, int userId) {
+ Log.i(TAG, "Granting permissions to enabled carrier apps for user:" + userId);
+ if (packageNames == null) {
+ return;
+ }
+ for (String packageName : packageNames) {
+ PackageParser.Package carrierPackage = getSystemPackage(packageName);
+ if (carrierPackage != null
+ && doesPackageSupportRuntimePermissions(carrierPackage)) {
+ grantRuntimePermissions(carrierPackage, PHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(carrierPackage, LOCATION_PERMISSIONS, userId);
+ grantRuntimePermissions(carrierPackage, SMS_PERMISSIONS, userId);
+ }
+ }
+ }
+
+ public void grantDefaultPermissionsToEnabledImsServices(String[] packageNames, int userId) {
+ Log.i(TAG, "Granting permissions to enabled ImsServices for user:" + userId);
+ if (packageNames == null) {
+ return;
+ }
+ for (String packageName : packageNames) {
+ PackageParser.Package imsServicePackage = getSystemPackage(packageName);
+ if (imsServicePackage != null
+ && doesPackageSupportRuntimePermissions(imsServicePackage)) {
+ grantRuntimePermissions(imsServicePackage, PHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(imsServicePackage, MICROPHONE_PERMISSIONS, userId);
+ grantRuntimePermissions(imsServicePackage, LOCATION_PERMISSIONS, userId);
+ grantRuntimePermissions(imsServicePackage, CAMERA_PERMISSIONS, userId);
+ }
+ }
+ }
+
+ public void grantDefaultPermissionsToDefaultBrowser(String packageName, int userId) {
+ Log.i(TAG, "Granting permissions to default browser for user:" + userId);
+ if (packageName == null) {
+ return;
+ }
+ PackageParser.Package browserPackage = getSystemPackage(packageName);
+ if (browserPackage != null
+ && doesPackageSupportRuntimePermissions(browserPackage)) {
+ grantRuntimePermissions(browserPackage, LOCATION_PERMISSIONS, false, false, userId);
+ }
+ }
+
+ private PackageParser.Package getDefaultSystemHandlerActivityPackage(
+ Intent intent, int userId) {
+ ResolveInfo handler = mServiceInternal.resolveIntent(intent,
+ intent.resolveType(mContext.getContentResolver()), DEFAULT_FLAGS, userId, false);
+ if (handler == null || handler.activityInfo == null) {
+ return null;
+ }
+ if (mServiceInternal.isResolveActivityComponent(handler.activityInfo)) {
+ return null;
+ }
+ return getSystemPackage(handler.activityInfo.packageName);
+ }
+
+ private PackageParser.Package getDefaultSystemHandlerServicePackage(
+ Intent intent, int userId) {
+ List<ResolveInfo> handlers = mServiceInternal.queryIntentServices(
+ intent, DEFAULT_FLAGS, Binder.getCallingUid(), userId);
+ if (handlers == null) {
+ return null;
+ }
+ final int handlerCount = handlers.size();
+ for (int i = 0; i < handlerCount; i++) {
+ ResolveInfo handler = handlers.get(i);
+ PackageParser.Package handlerPackage = getSystemPackage(
+ handler.serviceInfo.packageName);
+ if (handlerPackage != null) {
+ return handlerPackage;
+ }
+ }
+ return null;
+ }
+
+ private List<PackageParser.Package> getHeadlessSyncAdapterPackages(
+ String[] syncAdapterPackageNames, int userId) {
+ List<PackageParser.Package> syncAdapterPackages = new ArrayList<>();
+
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN);
+ homeIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+
+ for (String syncAdapterPackageName : syncAdapterPackageNames) {
+ homeIntent.setPackage(syncAdapterPackageName);
+
+ ResolveInfo homeActivity = mServiceInternal.resolveIntent(homeIntent,
+ homeIntent.resolveType(mContext.getContentResolver()), DEFAULT_FLAGS,
+ userId, false);
+ if (homeActivity != null) {
+ continue;
+ }
+
+ PackageParser.Package syncAdapterPackage = getSystemPackage(syncAdapterPackageName);
+ if (syncAdapterPackage != null) {
+ syncAdapterPackages.add(syncAdapterPackage);
+ }
+ }
+
+ return syncAdapterPackages;
+ }
+
+ private PackageParser.Package getDefaultProviderAuthorityPackage(
+ String authority, int userId) {
+ ProviderInfo provider =
+ mServiceInternal.resolveContentProvider(authority, DEFAULT_FLAGS, userId);
+ if (provider != null) {
+ return getSystemPackage(provider.packageName);
+ }
+ return null;
+ }
+
+ private PackageParser.Package getPackage(String packageName) {
+ return mServiceInternal.getPackage(packageName);
+ }
+
+ private PackageParser.Package getSystemPackage(String packageName) {
+ PackageParser.Package pkg = getPackage(packageName);
+ if (pkg != null && pkg.isSystemApp()) {
+ return !isSysComponentOrPersistentPlatformSignedPrivApp(pkg) ? pkg : null;
+ }
+ return null;
+ }
+
+ private void grantRuntimePermissions(PackageParser.Package pkg, Set<String> permissions,
+ int userId) {
+ grantRuntimePermissions(pkg, permissions, false, false, userId);
+ }
+
+ private void grantRuntimePermissions(PackageParser.Package pkg, Set<String> permissions,
+ boolean systemFixed, int userId) {
+ grantRuntimePermissions(pkg, permissions, systemFixed, false, userId);
+ }
+
+ private void grantRuntimePermissions(PackageParser.Package pkg, Set<String> permissions,
+ boolean systemFixed, boolean isDefaultPhoneOrSms, int userId) {
+ if (pkg.requestedPermissions.isEmpty()) {
+ return;
+ }
+
+ List<String> requestedPermissions = pkg.requestedPermissions;
+ Set<String> grantablePermissions = null;
+
+ // If this is the default Phone or SMS app we grant permissions regardless
+ // whether the version on the system image declares the permission as used since
+ // selecting the app as the default Phone or SMS the user makes a deliberate
+ // choice to grant this app the permissions needed to function. For all other
+ // apps, (default grants on first boot and user creation) we don't grant default
+ // permissions if the version on the system image does not declare them.
+ if (!isDefaultPhoneOrSms && pkg.isUpdatedSystemApp()) {
+ final PackageParser.Package disabledPkg =
+ mServiceInternal.getDisabledPackage(pkg.packageName);
+ if (disabledPkg != null) {
+ if (disabledPkg.requestedPermissions.isEmpty()) {
+ return;
+ }
+ if (!requestedPermissions.equals(disabledPkg.requestedPermissions)) {
+ grantablePermissions = new ArraySet<>(requestedPermissions);
+ requestedPermissions = disabledPkg.requestedPermissions;
+ }
+ }
+ }
+
+ final int grantablePermissionCount = requestedPermissions.size();
+ for (int i = 0; i < grantablePermissionCount; i++) {
+ String permission = requestedPermissions.get(i);
+
+ // If there is a disabled system app it may request a permission the updated
+ // version ot the data partition doesn't, In this case skip the permission.
+ if (grantablePermissions != null && !grantablePermissions.contains(permission)) {
+ continue;
+ }
+
+ if (permissions.contains(permission)) {
+ final int flags = mServiceInternal.getPermissionFlagsTEMP(
+ permission, pkg.packageName, userId);
+
+ // If any flags are set to the permission, then it is either set in
+ // its current state by the system or device/profile owner or the user.
+ // In all these cases we do not want to clobber the current state.
+ // Unless the caller wants to override user choices. The override is
+ // to make sure we can grant the needed permission to the default
+ // sms and phone apps after the user chooses this in the UI.
+ if (flags == 0 || isDefaultPhoneOrSms) {
+ // Never clobber policy or system.
+ final int fixedFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
+ | PackageManager.FLAG_PERMISSION_POLICY_FIXED;
+ if ((flags & fixedFlags) != 0) {
+ continue;
+ }
+
+ mServiceInternal.grantRuntimePermission(
+ pkg.packageName, permission, userId, false);
+ if (DEBUG) {
+ Log.i(TAG, "Granted " + (systemFixed ? "fixed " : "not fixed ")
+ + permission + " to default handler " + pkg.packageName);
+ }
+
+ int newFlags = PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+ if (systemFixed) {
+ newFlags |= PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+ }
+
+ mServiceInternal.updatePermissionFlagsTEMP(permission, pkg.packageName,
+ newFlags, newFlags, userId);
+ }
+
+ // If a component gets a permission for being the default handler A
+ // and also default handler B, we grant the weaker grant form.
+ if ((flags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0
+ && (flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0
+ && !systemFixed) {
+ if (DEBUG) {
+ Log.i(TAG, "Granted not fixed " + permission + " to default handler "
+ + pkg.packageName);
+ }
+ mServiceInternal.updatePermissionFlagsTEMP(permission, pkg.packageName,
+ PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, 0, userId);
+ }
+ }
+ }
+ }
+
+ private boolean isSysComponentOrPersistentPlatformSignedPrivApp(PackageParser.Package pkg) {
+ if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
+ return true;
+ }
+ if (!pkg.isPrivilegedApp()) {
+ return false;
+ }
+ final PackageParser.Package disabledPkg =
+ mServiceInternal.getDisabledPackage(pkg.packageName);
+ if (disabledPkg != null) {
+ if ((disabledPkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
+ return false;
+ }
+ } else if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
+ return false;
+ }
+ final String systemPackageName = mServiceInternal.getKnownPackageName(
+ PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM);
+ final PackageParser.Package systemPackage = getPackage(systemPackageName);
+ return PackageManagerService.compareSignatures(systemPackage.mSignatures,
+ pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
+ }
+
+ private void grantDefaultPermissionExceptions(int userId) {
+ mHandler.removeMessages(MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS);
+
+ synchronized (mLock) {
+ // mGrantExceptions is null only before the first read and then
+ // it serves as a cache of the default grants that should be
+ // performed for every user. If there is an entry then the app
+ // is on the system image and supports runtime permissions.
+ if (mGrantExceptions == null) {
+ mGrantExceptions = readDefaultPermissionExceptionsLocked();
+ }
+ }
+
+ Set<String> permissions = null;
+ final int exceptionCount = mGrantExceptions.size();
+ for (int i = 0; i < exceptionCount; i++) {
+ String packageName = mGrantExceptions.keyAt(i);
+ PackageParser.Package pkg = getSystemPackage(packageName);
+ List<DefaultPermissionGrant> permissionGrants = mGrantExceptions.valueAt(i);
+ final int permissionGrantCount = permissionGrants.size();
+ for (int j = 0; j < permissionGrantCount; j++) {
+ DefaultPermissionGrant permissionGrant = permissionGrants.get(j);
+ if (permissions == null) {
+ permissions = new ArraySet<>();
+ } else {
+ permissions.clear();
+ }
+ permissions.add(permissionGrant.name);
+ grantRuntimePermissions(pkg, permissions,
+ permissionGrant.fixed, userId);
+ }
+ }
+ }
+
+ private File[] getDefaultPermissionFiles() {
+ ArrayList<File> ret = new ArrayList<File>();
+ File dir = new File(Environment.getRootDirectory(), "etc/default-permissions");
+ if (dir.isDirectory() && dir.canRead()) {
+ Collections.addAll(ret, dir.listFiles());
+ }
+ dir = new File(Environment.getVendorDirectory(), "etc/default-permissions");
+ if (dir.isDirectory() && dir.canRead()) {
+ Collections.addAll(ret, dir.listFiles());
+ }
+ return ret.isEmpty() ? null : ret.toArray(new File[0]);
+ }
+
+ private @NonNull ArrayMap<String, List<DefaultPermissionGrant>>
+ readDefaultPermissionExceptionsLocked() {
+ File[] files = getDefaultPermissionFiles();
+ if (files == null) {
+ return new ArrayMap<>(0);
+ }
+
+ ArrayMap<String, List<DefaultPermissionGrant>> grantExceptions = new ArrayMap<>();
+
+ // Iterate over the files in the directory and scan .xml files
+ for (File file : files) {
+ if (!file.getPath().endsWith(".xml")) {
+ Slog.i(TAG, "Non-xml file " + file
+ + " in " + file.getParent() + " directory, ignoring");
+ continue;
+ }
+ if (!file.canRead()) {
+ Slog.w(TAG, "Default permissions file " + file + " cannot be read");
+ continue;
+ }
+ try (
+ InputStream str = new BufferedInputStream(new FileInputStream(file))
+ ) {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(str, null);
+ parse(parser, grantExceptions);
+ } catch (XmlPullParserException | IOException e) {
+ Slog.w(TAG, "Error reading default permissions file " + file, e);
+ }
+ }
+
+ return grantExceptions;
+ }
+
+ private void parse(XmlPullParser parser, Map<String, List<DefaultPermissionGrant>>
+ outGrantExceptions) throws IOException, XmlPullParserException {
+ final int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ if (TAG_EXCEPTIONS.equals(parser.getName())) {
+ parseExceptions(parser, outGrantExceptions);
+ } else {
+ Log.e(TAG, "Unknown tag " + parser.getName());
+ }
+ }
+ }
+
+ private void parseExceptions(XmlPullParser parser, Map<String, List<DefaultPermissionGrant>>
+ outGrantExceptions) throws IOException, XmlPullParserException {
+ final int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ if (TAG_EXCEPTION.equals(parser.getName())) {
+ String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+
+ List<DefaultPermissionGrant> packageExceptions =
+ outGrantExceptions.get(packageName);
+ if (packageExceptions == null) {
+ // The package must be on the system image
+ PackageParser.Package pkg = getSystemPackage(packageName);
+ if (pkg == null) {
+ Log.w(TAG, "Unknown package:" + packageName);
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+
+ // The package must support runtime permissions
+ if (!doesPackageSupportRuntimePermissions(pkg)) {
+ Log.w(TAG, "Skipping non supporting runtime permissions package:"
+ + packageName);
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ packageExceptions = new ArrayList<>();
+ outGrantExceptions.put(packageName, packageExceptions);
+ }
+
+ parsePermission(parser, packageExceptions);
+ } else {
+ Log.e(TAG, "Unknown tag " + parser.getName() + "under <exceptions>");
+ }
+ }
+ }
+
+ private void parsePermission(XmlPullParser parser, List<DefaultPermissionGrant>
+ outPackageExceptions) throws IOException, XmlPullParserException {
+ final int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ if (TAG_PERMISSION.contains(parser.getName())) {
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+ if (name == null) {
+ Log.w(TAG, "Mandatory name attribute missing for permission tag");
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+
+ final boolean fixed = XmlUtils.readBooleanAttribute(parser, ATTR_FIXED);
+
+ DefaultPermissionGrant exception = new DefaultPermissionGrant(name, fixed);
+ outPackageExceptions.add(exception);
+ } else {
+ Log.e(TAG, "Unknown tag " + parser.getName() + "under <exception>");
+ }
+ }
+ }
+
+ private static boolean doesPackageSupportRuntimePermissions(PackageParser.Package pkg) {
+ return pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
+ }
+
+ private static final class DefaultPermissionGrant {
+ final String name;
+ final boolean fixed;
+
+ public DefaultPermissionGrant(String name, boolean fixed) {
+ this.name = name;
+ this.fixed = fixed;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
new file mode 100644
index 0000000..3b20b42
--- /dev/null
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.permission;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageParser;
+import android.content.pm.PermissionInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManager.PermissionInfoFlags;
+import android.content.pm.PackageParser.Permission;
+
+import com.android.server.pm.SharedUserSetting;
+import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Internal interfaces to be used by other components within the system server.
+ */
+public abstract class PermissionManagerInternal {
+ /**
+ * Callbacks invoked when interesting actions have been taken on a permission.
+ * <p>
+ * NOTE: The current arguments are merely to support the existing use cases. This
+ * needs to be properly thought out with appropriate arguments for each of the
+ * callback methods.
+ */
+ public static class PermissionCallback {
+ public void onGidsChanged(int appId, int userId) {
+ }
+ public void onPermissionChanged() {
+ }
+ public void onPermissionGranted(int uid, int userId) {
+ }
+ public void onInstallPermissionGranted() {
+ }
+ public void onPermissionRevoked(int uid, int userId) {
+ }
+ public void onInstallPermissionRevoked() {
+ }
+ public void onPermissionUpdated(int userId) {
+ }
+ public void onPermissionRemoved() {
+ }
+ public void onInstallPermissionUpdated() {
+ }
+ }
+
+ public abstract void grantRuntimePermission(
+ @NonNull String permName, @NonNull String packageName, boolean overridePolicy,
+ int callingUid, int userId, @Nullable PermissionCallback callback);
+ public abstract void grantRuntimePermissionsGrantedToDisabledPackage(
+ @NonNull PackageParser.Package pkg, int callingUid,
+ @Nullable PermissionCallback callback);
+ public abstract void grantRequestedRuntimePermissions(
+ @NonNull PackageParser.Package pkg, @NonNull int[] userIds,
+ @NonNull String[] grantedPermissions, int callingUid,
+ @Nullable PermissionCallback callback);
+ public abstract void revokeRuntimePermission(@NonNull String permName,
+ @NonNull String packageName, boolean overridePolicy, int callingUid, int userId,
+ @Nullable PermissionCallback callback);
+ public abstract int[] revokeUnusedSharedUserPermissions(@NonNull SharedUserSetting suSetting,
+ @NonNull int[] allUserIds);
+
+
+ public abstract boolean addPermission(@NonNull PermissionInfo info, boolean async,
+ int callingUid, @Nullable PermissionCallback callback);
+ public abstract void removePermission(@NonNull String permName, int callingUid,
+ @Nullable PermissionCallback callback);
+
+ public abstract int getPermissionFlags(@NonNull String permName,
+ @NonNull String packageName, int callingUid, int userId);
+ /**
+ * Retrieve all of the information we know about a particular permission.
+ */
+ public abstract @Nullable PermissionInfo getPermissionInfo(@NonNull String permName,
+ @NonNull String packageName, @PermissionInfoFlags int flags, int callingUid);
+ /**
+ * Retrieve all of the permissions associated with a particular group.
+ */
+ public abstract @Nullable List<PermissionInfo> getPermissionInfoByGroup(@NonNull String group,
+ @PermissionInfoFlags int flags, int callingUid);
+ public abstract boolean isPermissionAppOp(@NonNull String permName);
+ public abstract boolean isPermissionInstant(@NonNull String permName);
+
+ /**
+ * Updates the flags associated with a permission by replacing the flags in
+ * the specified mask with the provided flag values.
+ */
+ public abstract void updatePermissionFlags(@NonNull String permName,
+ @NonNull String packageName, int flagMask, int flagValues, int callingUid, int userId,
+ @Nullable PermissionCallback callback);
+ /**
+ * Updates the flags for all applications by replacing the flags in the specified mask
+ * with the provided flag values.
+ */
+ public abstract boolean updatePermissionFlagsForAllApps(int flagMask, int flagValues,
+ int callingUid, int userId, @NonNull Collection<PackageParser.Package> packages,
+ @Nullable PermissionCallback callback);
+
+ public abstract int checkPermission(@NonNull String permName, @NonNull String packageName,
+ int callingUid, int userId);
+
+ /**
+ * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
+ * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userid} is not for the caller.
+ * @param checkShell whether to prevent shell from access if there's a debugging restriction
+ * @param message the message to log on security exception
+ */
+ public abstract void enforceCrossUserPermission(int callingUid, int userId,
+ boolean requireFullPermission, boolean checkShell, @NonNull String message);
+ public abstract void enforceGrantRevokeRuntimePermissionPermissions(@NonNull String message);
+
+ public abstract @NonNull PermissionSettings getPermissionSettings();
+ public abstract @NonNull DefaultPermissionGrantPolicy getDefaultPermissionGrantPolicy();
+
+ /** HACK HACK methods to allow for partial migration of data to the PermissionManager class */
+ public abstract Iterator<BasePermission> getPermissionIteratorTEMP();
+ public abstract @Nullable BasePermission getPermissionTEMP(@NonNull String permName);
+ public abstract void putPermissionTEMP(@NonNull String permName,
+ @NonNull BasePermission permission);
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
new file mode 100644
index 0000000..6c031a6
--- /dev/null
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -0,0 +1,1081 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.permission;
+
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.PackageParser;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.PermissionInfo;
+import android.content.pm.PackageParser.Package;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.UserManagerInternal;
+import android.os.storage.StorageManagerInternal;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.FgThread;
+import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
+import com.android.server.SystemConfig;
+import com.android.server.Watchdog;
+import com.android.server.pm.PackageManagerService;
+import com.android.server.pm.PackageManagerServiceUtils;
+import com.android.server.pm.PackageSetting;
+import com.android.server.pm.ProcessLoggingHandler;
+import com.android.server.pm.SharedUserSetting;
+import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback;
+import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback;
+import com.android.server.pm.permission.PermissionsState.PermissionState;
+
+import libcore.util.EmptyArray;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Manages all permissions and handles permissions related tasks.
+ */
+public class PermissionManagerService {
+ private static final String TAG = "PackageManager";
+
+ /** All dangerous permission names in the same order as the events in MetricsEvent */
+ private static final List<String> ALL_DANGEROUS_PERMISSIONS = Arrays.asList(
+ Manifest.permission.READ_CALENDAR,
+ Manifest.permission.WRITE_CALENDAR,
+ Manifest.permission.CAMERA,
+ Manifest.permission.READ_CONTACTS,
+ Manifest.permission.WRITE_CONTACTS,
+ Manifest.permission.GET_ACCOUNTS,
+ Manifest.permission.ACCESS_FINE_LOCATION,
+ Manifest.permission.ACCESS_COARSE_LOCATION,
+ Manifest.permission.RECORD_AUDIO,
+ Manifest.permission.READ_PHONE_STATE,
+ Manifest.permission.CALL_PHONE,
+ Manifest.permission.READ_CALL_LOG,
+ Manifest.permission.WRITE_CALL_LOG,
+ Manifest.permission.ADD_VOICEMAIL,
+ Manifest.permission.USE_SIP,
+ Manifest.permission.PROCESS_OUTGOING_CALLS,
+ Manifest.permission.READ_CELL_BROADCASTS,
+ Manifest.permission.BODY_SENSORS,
+ Manifest.permission.SEND_SMS,
+ Manifest.permission.RECEIVE_SMS,
+ Manifest.permission.READ_SMS,
+ Manifest.permission.RECEIVE_WAP_PUSH,
+ Manifest.permission.RECEIVE_MMS,
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ Manifest.permission.READ_PHONE_NUMBERS,
+ Manifest.permission.ANSWER_PHONE_CALLS);
+
+ /** Cap the size of permission trees that 3rd party apps can define */
+ private static final int MAX_PERMISSION_TREE_FOOTPRINT = 32768; // characters of text
+
+ /** Lock to protect internal data access */
+ private final Object mLock;
+
+ /** Internal connection to the package manager */
+ private final PackageManagerInternal mPackageManagerInt;
+
+ /** Internal connection to the user manager */
+ private final UserManagerInternal mUserManagerInt;
+
+ /** Default permission policy to provide proper behaviour out-of-the-box */
+ private final DefaultPermissionGrantPolicy mDefaultPermissionGrantPolicy;
+
+ /** Internal storage for permissions and related settings */
+ private final PermissionSettings mSettings;
+
+ private final HandlerThread mHandlerThread;
+ private final Handler mHandler;
+ private final Context mContext;
+
+ PermissionManagerService(Context context,
+ @Nullable DefaultPermissionGrantedCallback defaultGrantCallback,
+ @NonNull Object externalLock) {
+ mContext = context;
+ mLock = externalLock;
+ mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class);
+ mUserManagerInt = LocalServices.getService(UserManagerInternal.class);
+ mSettings = new PermissionSettings(context, mLock);
+
+ mHandlerThread = new ServiceThread(TAG,
+ Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+ Watchdog.getInstance().addThread(mHandler);
+
+ mDefaultPermissionGrantPolicy = new DefaultPermissionGrantPolicy(
+ context, mHandlerThread.getLooper(), defaultGrantCallback, this);
+
+ // propagate permission configuration
+ final ArrayMap<String, SystemConfig.PermissionEntry> permConfig =
+ SystemConfig.getInstance().getPermissions();
+ synchronized (mLock) {
+ for (int i=0; i<permConfig.size(); i++) {
+ final SystemConfig.PermissionEntry perm = permConfig.valueAt(i);
+ BasePermission bp = mSettings.getPermissionLocked(perm.name);
+ if (bp == null) {
+ bp = new BasePermission(perm.name, "android", BasePermission.TYPE_BUILTIN);
+ mSettings.putPermissionLocked(perm.name, bp);
+ }
+ if (perm.gids != null) {
+ bp.setGids(perm.gids, perm.perUser);
+ }
+ }
+ }
+
+ LocalServices.addService(
+ PermissionManagerInternal.class, new PermissionManagerInternalImpl());
+ }
+
+ /**
+ * Creates and returns an initialized, internal service for use by other components.
+ * <p>
+ * The object returned is identical to the one returned by the LocalServices class using:
+ * {@code LocalServices.getService(PermissionManagerInternal.class);}
+ * <p>
+ * NOTE: The external lock is temporary and should be removed. This needs to be a
+ * lock created by the permission manager itself.
+ */
+ public static PermissionManagerInternal create(Context context,
+ @Nullable DefaultPermissionGrantedCallback defaultGrantCallback,
+ @NonNull Object externalLock) {
+ final PermissionManagerInternal permMgrInt =
+ LocalServices.getService(PermissionManagerInternal.class);
+ if (permMgrInt != null) {
+ return permMgrInt;
+ }
+ new PermissionManagerService(context, defaultGrantCallback, externalLock);
+ return LocalServices.getService(PermissionManagerInternal.class);
+ }
+
+ @Nullable BasePermission getPermission(String permName) {
+ synchronized (mLock) {
+ return mSettings.getPermissionLocked(permName);
+ }
+ }
+
+ private int checkPermission(String permName, String pkgName, int callingUid, int userId) {
+ if (!mUserManagerInt.exists(userId)) {
+ return PackageManager.PERMISSION_DENIED;
+ }
+
+ final PackageParser.Package pkg = mPackageManagerInt.getPackage(pkgName);
+ if (pkg != null && pkg.mExtras != null) {
+ if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
+ return PackageManager.PERMISSION_DENIED;
+ }
+ final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ final boolean instantApp = ps.getInstantApp(userId);
+ final PermissionsState permissionsState = ps.getPermissionsState();
+ if (permissionsState.hasPermission(permName, userId)) {
+ if (instantApp) {
+ synchronized (mLock) {
+ BasePermission bp = mSettings.getPermissionLocked(permName);
+ if (bp != null && bp.isInstant()) {
+ return PackageManager.PERMISSION_GRANTED;
+ }
+ }
+ } else {
+ return PackageManager.PERMISSION_GRANTED;
+ }
+ }
+ // Special case: ACCESS_FINE_LOCATION permission includes ACCESS_COARSE_LOCATION
+ if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && permissionsState
+ .hasPermission(Manifest.permission.ACCESS_FINE_LOCATION, userId)) {
+ return PackageManager.PERMISSION_GRANTED;
+ }
+ }
+
+ return PackageManager.PERMISSION_DENIED;
+ }
+
+ private PermissionInfo getPermissionInfo(String name, String packageName, int flags,
+ int callingUid) {
+ if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
+ return null;
+ }
+ // reader
+ synchronized (mLock) {
+ final BasePermission bp = mSettings.getPermissionLocked(name);
+ if (bp == null) {
+ return null;
+ }
+ final int adjustedProtectionLevel = adjustPermissionProtectionFlagsLocked(
+ bp.getProtectionLevel(), packageName, callingUid);
+ return bp.generatePermissionInfo(adjustedProtectionLevel, flags);
+ }
+ }
+
+ private List<PermissionInfo> getPermissionInfoByGroup(
+ String groupName, int flags, int callingUid) {
+ if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
+ return null;
+ }
+ // reader
+ synchronized (mLock) {
+ // TODO Uncomment when mPermissionGroups moves to this class
+// if (groupName != null && !mPermissionGroups.containsKey(groupName)) {
+// // This is thrown as NameNotFoundException
+// return null;
+// }
+
+ final ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10);
+ for (BasePermission bp : mSettings.getAllPermissionsLocked()) {
+ final PermissionInfo pi = bp.generatePermissionInfo(groupName, flags);
+ if (pi != null) {
+ out.add(pi);
+ }
+ }
+ return out;
+ }
+ }
+
+ private int adjustPermissionProtectionFlagsLocked(
+ int protectionLevel, String packageName, int uid) {
+ // Signature permission flags area always reported
+ final int protectionLevelMasked = protectionLevel
+ & (PermissionInfo.PROTECTION_NORMAL
+ | PermissionInfo.PROTECTION_DANGEROUS
+ | PermissionInfo.PROTECTION_SIGNATURE);
+ if (protectionLevelMasked == PermissionInfo.PROTECTION_SIGNATURE) {
+ return protectionLevel;
+ }
+ // System sees all flags.
+ final int appId = UserHandle.getAppId(uid);
+ if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID
+ || appId == Process.SHELL_UID) {
+ return protectionLevel;
+ }
+ // Normalize package name to handle renamed packages and static libs
+ final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+ if (pkg == null) {
+ return protectionLevel;
+ }
+ if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
+ return protectionLevelMasked;
+ }
+ // Apps that target O see flags for all protection levels.
+ final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ if (ps == null) {
+ return protectionLevel;
+ }
+ if (ps.getAppId() != appId) {
+ return protectionLevel;
+ }
+ return protectionLevel;
+ }
+
+ private boolean addPermission(
+ PermissionInfo info, int callingUid, PermissionCallback callback) {
+ if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
+ throw new SecurityException("Instant apps can't add permissions");
+ }
+ if (info.labelRes == 0 && info.nonLocalizedLabel == null) {
+ throw new SecurityException("Label must be specified in permission");
+ }
+ final BasePermission tree = (BasePermission) mPackageManagerInt.enforcePermissionTreeTEMP(
+ info.name, callingUid);
+ final boolean added;
+ final boolean changed;
+ synchronized (mLock) {
+ BasePermission bp = mSettings.getPermissionLocked(info.name);
+ added = bp == null;
+ int fixedLevel = PermissionInfo.fixProtectionLevel(info.protectionLevel);
+ if (added) {
+ enforcePermissionCapLocked(info, tree);
+ bp = new BasePermission(info.name, tree.getSourcePackageName(),
+ BasePermission.TYPE_DYNAMIC);
+ } else if (bp.isDynamic()) {
+ throw new SecurityException(
+ "Not allowed to modify non-dynamic permission "
+ + info.name);
+ }
+ changed = bp.addToTree(fixedLevel, info, tree);
+ if (added) {
+ mSettings.putPermissionLocked(info.name, bp);
+ }
+ }
+ if (changed && callback != null) {
+ callback.onPermissionChanged();
+ }
+ return added;
+ }
+
+ private void removePermission(
+ String permName, int callingUid, PermissionCallback callback) {
+ if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
+ throw new SecurityException("Instant applications don't have access to this method");
+ }
+ final BasePermission tree = (BasePermission) mPackageManagerInt.enforcePermissionTreeTEMP(
+ permName, callingUid);
+ synchronized (mLock) {
+ final BasePermission bp = mSettings.getPermissionLocked(permName);
+ if (bp == null) {
+ return;
+ }
+ if (bp.isDynamic()) {
+ throw new SecurityException(
+ "Not allowed to modify non-dynamic permission "
+ + permName);
+ }
+ mSettings.removePermissionLocked(permName);
+ if (callback != null) {
+ callback.onPermissionRemoved();
+ }
+ }
+ }
+
+ private void grantRuntimePermissionsGrantedToDisabledPackageLocked(
+ PackageParser.Package pkg, int callingUid, PermissionCallback callback) {
+ if (pkg.parentPackage == null) {
+ return;
+ }
+ if (pkg.requestedPermissions == null) {
+ return;
+ }
+ final PackageParser.Package disabledPkg =
+ mPackageManagerInt.getDisabledPackage(pkg.parentPackage.packageName);
+ if (disabledPkg == null || disabledPkg.mExtras == null) {
+ return;
+ }
+ final PackageSetting disabledPs = (PackageSetting) disabledPkg.mExtras;
+ if (!disabledPs.isPrivileged() || disabledPs.hasChildPackages()) {
+ return;
+ }
+ final int permCount = pkg.requestedPermissions.size();
+ for (int i = 0; i < permCount; i++) {
+ String permission = pkg.requestedPermissions.get(i);
+ BasePermission bp = mSettings.getPermissionLocked(permission);
+ if (bp == null || !(bp.isRuntime() || bp.isDevelopment())) {
+ continue;
+ }
+ for (int userId : mUserManagerInt.getUserIds()) {
+ if (disabledPs.getPermissionsState().hasRuntimePermission(permission, userId)) {
+ grantRuntimePermission(
+ permission, pkg.packageName, false, callingUid, userId, callback);
+ }
+ }
+ }
+ }
+
+ private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int[] userIds,
+ String[] grantedPermissions, int callingUid, PermissionCallback callback) {
+ for (int userId : userIds) {
+ grantRequestedRuntimePermissionsForUser(pkg, userId, grantedPermissions, callingUid,
+ callback);
+ }
+ }
+
+ private void grantRequestedRuntimePermissionsForUser(PackageParser.Package pkg, int userId,
+ String[] grantedPermissions, int callingUid, PermissionCallback callback) {
+ PackageSetting ps = (PackageSetting) pkg.mExtras;
+ if (ps == null) {
+ return;
+ }
+
+ PermissionsState permissionsState = ps.getPermissionsState();
+
+ final int immutableFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
+ | PackageManager.FLAG_PERMISSION_POLICY_FIXED;
+
+ final boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
+ >= Build.VERSION_CODES.M;
+
+ final boolean instantApp = mPackageManagerInt.isInstantApp(pkg.packageName, userId);
+
+ for (String permission : pkg.requestedPermissions) {
+ final BasePermission bp;
+ synchronized (mLock) {
+ bp = mSettings.getPermissionLocked(permission);
+ }
+ if (bp != null && (bp.isRuntime() || bp.isDevelopment())
+ && (!instantApp || bp.isInstant())
+ && (supportsRuntimePermissions || !bp.isRuntimeOnly())
+ && (grantedPermissions == null
+ || ArrayUtils.contains(grantedPermissions, permission))) {
+ final int flags = permissionsState.getPermissionFlags(permission, userId);
+ if (supportsRuntimePermissions) {
+ // Installer cannot change immutable permissions.
+ if ((flags & immutableFlags) == 0) {
+ grantRuntimePermission(permission, pkg.packageName, false, callingUid,
+ userId, callback);
+ }
+ } else if (mSettings.mPermissionReviewRequired) {
+ // In permission review mode we clear the review flag when we
+ // are asked to install the app with all permissions granted.
+ if ((flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
+ updatePermissionFlags(permission, pkg.packageName,
+ PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, 0, callingUid,
+ userId, callback);
+ }
+ }
+ }
+ }
+ }
+
+ private void grantRuntimePermission(String permName, String packageName, boolean overridePolicy,
+ int callingUid, final int userId, PermissionCallback callback) {
+ if (!mUserManagerInt.exists(userId)) {
+ Log.e(TAG, "No such user:" + userId);
+ return;
+ }
+
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+ "grantRuntimePermission");
+
+ enforceCrossUserPermission(callingUid, userId,
+ true /* requireFullPermission */, true /* checkShell */,
+ "grantRuntimePermission");
+
+ final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+ if (pkg == null || pkg.mExtras == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ final BasePermission bp;
+ synchronized(mLock) {
+ bp = mSettings.getPermissionLocked(permName);
+ }
+ if (bp == null) {
+ throw new IllegalArgumentException("Unknown permission: " + permName);
+ }
+ if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+
+ bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
+
+ // If a permission review is required for legacy apps we represent
+ // their permissions as always granted runtime ones since we need
+ // to keep the review required permission flag per user while an
+ // install permission's state is shared across all users.
+ if (mSettings.mPermissionReviewRequired
+ && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
+ && bp.isRuntime()) {
+ return;
+ }
+
+ final int uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);
+
+ final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ final PermissionsState permissionsState = ps.getPermissionsState();
+
+ final int flags = permissionsState.getPermissionFlags(permName, userId);
+ if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
+ throw new SecurityException("Cannot grant system fixed permission "
+ + permName + " for package " + packageName);
+ }
+ if (!overridePolicy && (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
+ throw new SecurityException("Cannot grant policy fixed permission "
+ + permName + " for package " + packageName);
+ }
+
+ if (bp.isDevelopment()) {
+ // Development permissions must be handled specially, since they are not
+ // normal runtime permissions. For now they apply to all users.
+ if (permissionsState.grantInstallPermission(bp) !=
+ PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ if (callback != null) {
+ callback.onInstallPermissionGranted();
+ }
+ }
+ return;
+ }
+
+ if (ps.getInstantApp(userId) && !bp.isInstant()) {
+ throw new SecurityException("Cannot grant non-ephemeral permission"
+ + permName + " for package " + packageName);
+ }
+
+ if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+ Slog.w(TAG, "Cannot grant runtime permission to a legacy app");
+ return;
+ }
+
+ final int result = permissionsState.grantRuntimePermission(bp, userId);
+ switch (result) {
+ case PermissionsState.PERMISSION_OPERATION_FAILURE: {
+ return;
+ }
+
+ case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
+ if (callback != null) {
+ callback.onGidsChanged(UserHandle.getAppId(pkg.applicationInfo.uid), userId);
+ }
+ }
+ break;
+ }
+
+ if (bp.isRuntime()) {
+ logPermissionGranted(mContext, permName, packageName);
+ }
+
+ if (callback != null) {
+ callback.onPermissionGranted(uid, userId);
+ }
+
+ // Only need to do this if user is initialized. Otherwise it's a new user
+ // and there are no processes running as the user yet and there's no need
+ // to make an expensive call to remount processes for the changed permissions.
+ if (READ_EXTERNAL_STORAGE.equals(permName)
+ || WRITE_EXTERNAL_STORAGE.equals(permName)) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (mUserManagerInt.isUserInitialized(userId)) {
+ StorageManagerInternal storageManagerInternal = LocalServices.getService(
+ StorageManagerInternal.class);
+ storageManagerInternal.onExternalStoragePolicyChanged(uid, packageName);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ }
+
+ private void revokeRuntimePermission(String permName, String packageName,
+ boolean overridePolicy, int callingUid, int userId, PermissionCallback callback) {
+ if (!mUserManagerInt.exists(userId)) {
+ Log.e(TAG, "No such user:" + userId);
+ return;
+ }
+
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
+ "revokeRuntimePermission");
+
+ enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ true /* requireFullPermission */, true /* checkShell */,
+ "revokeRuntimePermission");
+
+ final int appId;
+
+ final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+ if (pkg == null || pkg.mExtras == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ if (mPackageManagerInt.filterAppAccess(pkg, Binder.getCallingUid(), userId)) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ final BasePermission bp = mSettings.getPermissionLocked(permName);
+ if (bp == null) {
+ throw new IllegalArgumentException("Unknown permission: " + permName);
+ }
+
+ bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg);
+
+ // If a permission review is required for legacy apps we represent
+ // their permissions as always granted runtime ones since we need
+ // to keep the review required permission flag per user while an
+ // install permission's state is shared across all users.
+ if (mSettings.mPermissionReviewRequired
+ && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
+ && bp.isRuntime()) {
+ return;
+ }
+
+ final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ final PermissionsState permissionsState = ps.getPermissionsState();
+
+ final int flags = permissionsState.getPermissionFlags(permName, userId);
+ if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
+ throw new SecurityException("Cannot revoke system fixed permission "
+ + permName + " for package " + packageName);
+ }
+ if (!overridePolicy && (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
+ throw new SecurityException("Cannot revoke policy fixed permission "
+ + permName + " for package " + packageName);
+ }
+
+ if (bp.isDevelopment()) {
+ // Development permissions must be handled specially, since they are not
+ // normal runtime permissions. For now they apply to all users.
+ if (permissionsState.revokeInstallPermission(bp) !=
+ PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ if (callback != null) {
+ callback.onInstallPermissionRevoked();
+ }
+ }
+ return;
+ }
+
+ if (permissionsState.revokeRuntimePermission(bp, userId) ==
+ PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ return;
+ }
+
+ if (bp.isRuntime()) {
+ logPermissionRevoked(mContext, permName, packageName);
+ }
+
+ if (callback != null) {
+ final int uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);
+ callback.onPermissionRevoked(pkg.applicationInfo.uid, userId);
+ }
+ }
+
+ private int[] revokeUnusedSharedUserPermissions(SharedUserSetting suSetting, int[] allUserIds) {
+ // Collect all used permissions in the UID
+ final ArraySet<String> usedPermissions = new ArraySet<>();
+ final List<PackageParser.Package> pkgList = suSetting.getPackages();
+ if (pkgList == null || pkgList.size() == 0) {
+ return EmptyArray.INT;
+ }
+ for (PackageParser.Package pkg : pkgList) {
+ final int requestedPermCount = pkg.requestedPermissions.size();
+ for (int j = 0; j < requestedPermCount; j++) {
+ String permission = pkg.requestedPermissions.get(j);
+ BasePermission bp = mSettings.getPermissionLocked(permission);
+ if (bp != null) {
+ usedPermissions.add(permission);
+ }
+ }
+ }
+
+ PermissionsState permissionsState = suSetting.getPermissionsState();
+ // Prune install permissions
+ List<PermissionState> installPermStates = permissionsState.getInstallPermissionStates();
+ final int installPermCount = installPermStates.size();
+ for (int i = installPermCount - 1; i >= 0; i--) {
+ PermissionState permissionState = installPermStates.get(i);
+ if (!usedPermissions.contains(permissionState.getName())) {
+ BasePermission bp = mSettings.getPermissionLocked(permissionState.getName());
+ if (bp != null) {
+ permissionsState.revokeInstallPermission(bp);
+ permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
+ PackageManager.MASK_PERMISSION_FLAGS, 0);
+ }
+ }
+ }
+
+ int[] runtimePermissionChangedUserIds = EmptyArray.INT;
+
+ // Prune runtime permissions
+ for (int userId : allUserIds) {
+ List<PermissionState> runtimePermStates = permissionsState
+ .getRuntimePermissionStates(userId);
+ final int runtimePermCount = runtimePermStates.size();
+ for (int i = runtimePermCount - 1; i >= 0; i--) {
+ PermissionState permissionState = runtimePermStates.get(i);
+ if (!usedPermissions.contains(permissionState.getName())) {
+ BasePermission bp = mSettings.getPermissionLocked(permissionState.getName());
+ if (bp != null) {
+ permissionsState.revokeRuntimePermission(bp, userId);
+ permissionsState.updatePermissionFlags(bp, userId,
+ PackageManager.MASK_PERMISSION_FLAGS, 0);
+ runtimePermissionChangedUserIds = ArrayUtils.appendInt(
+ runtimePermissionChangedUserIds, userId);
+ }
+ }
+ }
+ }
+
+ return runtimePermissionChangedUserIds;
+ }
+
+ private int getPermissionFlags(String permName, String packageName, int callingUid, int userId) {
+ if (!mUserManagerInt.exists(userId)) {
+ return 0;
+ }
+
+ enforceGrantRevokeRuntimePermissionPermissions("getPermissionFlags");
+
+ enforceCrossUserPermission(callingUid, userId,
+ true /* requireFullPermission */, false /* checkShell */,
+ "getPermissionFlags");
+
+ final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+ if (pkg == null || pkg.mExtras == null) {
+ return 0;
+ }
+ synchronized (mLock) {
+ if (mSettings.getPermissionLocked(permName) == null) {
+ return 0;
+ }
+ }
+ if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
+ return 0;
+ }
+ final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ PermissionsState permissionsState = ps.getPermissionsState();
+ return permissionsState.getPermissionFlags(permName, userId);
+ }
+
+ private void updatePermissionFlags(String permName, String packageName, int flagMask,
+ int flagValues, int callingUid, int userId, PermissionCallback callback) {
+ if (!mUserManagerInt.exists(userId)) {
+ return;
+ }
+
+ enforceGrantRevokeRuntimePermissionPermissions("updatePermissionFlags");
+
+ enforceCrossUserPermission(callingUid, userId,
+ true /* requireFullPermission */, true /* checkShell */,
+ "updatePermissionFlags");
+
+ // Only the system can change these flags and nothing else.
+ if (callingUid != Process.SYSTEM_UID) {
+ flagMask &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+ flagValues &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+ flagMask &= ~PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+ flagValues &= ~PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+ flagValues &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+ }
+
+ final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+ if (pkg == null || pkg.mExtras == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+
+ final BasePermission bp;
+ synchronized (mLock) {
+ bp = mSettings.getPermissionLocked(permName);
+ }
+ if (bp == null) {
+ throw new IllegalArgumentException("Unknown permission: " + permName);
+ }
+
+ final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ final PermissionsState permissionsState = ps.getPermissionsState();
+ final boolean hadState =
+ permissionsState.getRuntimePermissionState(permName, userId) != null;
+ final boolean permissionUpdated =
+ permissionsState.updatePermissionFlags(bp, userId, flagMask, flagValues);
+ if (permissionUpdated && callback != null) {
+ // Install and runtime permissions are stored in different places,
+ // so figure out what permission changed and persist the change.
+ if (permissionsState.getInstallPermissionState(permName) != null) {
+ callback.onInstallPermissionUpdated();
+ } else if (permissionsState.getRuntimePermissionState(permName, userId) != null
+ || hadState) {
+ callback.onPermissionUpdated(userId);
+ }
+ }
+ }
+
+ private boolean updatePermissionFlagsForAllApps(int flagMask, int flagValues, int callingUid,
+ int userId, Collection<Package> packages, PermissionCallback callback) {
+ if (!mUserManagerInt.exists(userId)) {
+ return false;
+ }
+
+ enforceGrantRevokeRuntimePermissionPermissions(
+ "updatePermissionFlagsForAllApps");
+ enforceCrossUserPermission(callingUid, userId,
+ true /* requireFullPermission */, true /* checkShell */,
+ "updatePermissionFlagsForAllApps");
+
+ // Only the system can change system fixed flags.
+ if (callingUid != Process.SYSTEM_UID) {
+ flagMask &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+ flagValues &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+ }
+
+ boolean changed = false;
+ for (PackageParser.Package pkg : packages) {
+ final PackageSetting ps = (PackageSetting) pkg.mExtras;
+ if (ps == null) {
+ continue;
+ }
+ PermissionsState permissionsState = ps.getPermissionsState();
+ changed |= permissionsState.updatePermissionFlagsForAllPermissions(
+ userId, flagMask, flagValues);
+ }
+ return changed;
+ }
+
+ private void enforceGrantRevokeRuntimePermissionPermissions(String message) {
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
+ != PackageManager.PERMISSION_GRANTED
+ && mContext.checkCallingOrSelfPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(message + " requires "
+ + Manifest.permission.GRANT_RUNTIME_PERMISSIONS + " or "
+ + Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
+ }
+ }
+
+ /**
+ * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS
+ * or INTERACT_ACROSS_USERS_FULL permissions, if the userid is not for the caller.
+ * @param checkShell whether to prevent shell from access if there's a debugging restriction
+ * @param message the message to log on security exception
+ */
+ private void enforceCrossUserPermission(int callingUid, int userId,
+ boolean requireFullPermission, boolean checkShell, String message) {
+ if (userId < 0) {
+ throw new IllegalArgumentException("Invalid userId " + userId);
+ }
+ if (checkShell) {
+ PackageManagerServiceUtils.enforceShellRestriction(
+ UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
+ }
+ if (userId == UserHandle.getUserId(callingUid)) return;
+ if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
+ if (requireFullPermission) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
+ } else {
+ try {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
+ } catch (SecurityException se) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS, message);
+ }
+ }
+ }
+ }
+
+ private int calculateCurrentPermissionFootprintLocked(BasePermission tree) {
+ int size = 0;
+ for (BasePermission perm : mSettings.getAllPermissionsLocked()) {
+ size += tree.calculateFootprint(perm);
+ }
+ return size;
+ }
+
+ private void enforcePermissionCapLocked(PermissionInfo info, BasePermission tree) {
+ // We calculate the max size of permissions defined by this uid and throw
+ // if that plus the size of 'info' would exceed our stated maximum.
+ if (tree.getUid() != Process.SYSTEM_UID) {
+ final int curTreeSize = calculateCurrentPermissionFootprintLocked(tree);
+ if (curTreeSize + info.calculateFootprint() > MAX_PERMISSION_TREE_FOOTPRINT) {
+ throw new SecurityException("Permission tree size cap exceeded");
+ }
+ }
+ }
+
+ /**
+ * Get the first event id for the permission.
+ *
+ * <p>There are four events for each permission: <ul>
+ * <li>Request permission: first id + 0</li>
+ * <li>Grant permission: first id + 1</li>
+ * <li>Request for permission denied: first id + 2</li>
+ * <li>Revoke permission: first id + 3</li>
+ * </ul></p>
+ *
+ * @param name name of the permission
+ *
+ * @return The first event id for the permission
+ */
+ private static int getBaseEventId(@NonNull String name) {
+ int eventIdIndex = ALL_DANGEROUS_PERMISSIONS.indexOf(name);
+
+ if (eventIdIndex == -1) {
+ if (AppOpsManager.permissionToOpCode(name) == AppOpsManager.OP_NONE
+ || Build.IS_USER) {
+ Log.i(TAG, "Unknown permission " + name);
+
+ return MetricsEvent.ACTION_PERMISSION_REQUEST_UNKNOWN;
+ } else {
+ // Most likely #ALL_DANGEROUS_PERMISSIONS needs to be updated.
+ //
+ // Also update
+ // - EventLogger#ALL_DANGEROUS_PERMISSIONS
+ // - metrics_constants.proto
+ throw new IllegalStateException("Unknown permission " + name);
+ }
+ }
+
+ return MetricsEvent.ACTION_PERMISSION_REQUEST_READ_CALENDAR + eventIdIndex * 4;
+ }
+
+ /**
+ * Log that a permission was revoked.
+ *
+ * @param context Context of the caller
+ * @param name name of the permission
+ * @param packageName package permission if for
+ */
+ private static void logPermissionRevoked(@NonNull Context context, @NonNull String name,
+ @NonNull String packageName) {
+ MetricsLogger.action(context, getBaseEventId(name) + 3, packageName);
+ }
+
+ /**
+ * Log that a permission request was granted.
+ *
+ * @param context Context of the caller
+ * @param name name of the permission
+ * @param packageName package permission if for
+ */
+ private static void logPermissionGranted(@NonNull Context context, @NonNull String name,
+ @NonNull String packageName) {
+ MetricsLogger.action(context, getBaseEventId(name) + 1, packageName);
+ }
+
+ private class PermissionManagerInternalImpl extends PermissionManagerInternal {
+ @Override
+ public boolean addPermission(PermissionInfo info, boolean async, int callingUid,
+ PermissionCallback callback) {
+ return PermissionManagerService.this.addPermission(info, callingUid, callback);
+ }
+ @Override
+ public void removePermission(String permName, int callingUid,
+ PermissionCallback callback) {
+ PermissionManagerService.this.removePermission(permName, callingUid, callback);
+ }
+ @Override
+ public void grantRuntimePermission(String permName, String packageName,
+ boolean overridePolicy, int callingUid, int userId,
+ PermissionCallback callback) {
+ PermissionManagerService.this.grantRuntimePermission(
+ permName, packageName, overridePolicy, callingUid, userId, callback);
+ }
+ @Override
+ public void grantRequestedRuntimePermissions(PackageParser.Package pkg, int[] userIds,
+ String[] grantedPermissions, int callingUid, PermissionCallback callback) {
+ PermissionManagerService.this.grantRequestedRuntimePermissions(
+ pkg, userIds, grantedPermissions, callingUid, callback);
+ }
+ @Override
+ public void grantRuntimePermissionsGrantedToDisabledPackage(PackageParser.Package pkg,
+ int callingUid, PermissionCallback callback) {
+ PermissionManagerService.this.grantRuntimePermissionsGrantedToDisabledPackageLocked(
+ pkg, callingUid, callback);
+ }
+ @Override
+ public void revokeRuntimePermission(String permName, String packageName,
+ boolean overridePolicy, int callingUid, int userId,
+ PermissionCallback callback) {
+ PermissionManagerService.this.revokeRuntimePermission(permName, packageName,
+ overridePolicy, callingUid, userId, callback);
+ }
+ @Override
+ public int[] revokeUnusedSharedUserPermissions(SharedUserSetting suSetting,
+ int[] allUserIds) {
+ return PermissionManagerService.this.revokeUnusedSharedUserPermissions(
+ (SharedUserSetting) suSetting, allUserIds);
+ }
+ @Override
+ public int getPermissionFlags(String permName, String packageName, int callingUid,
+ int userId) {
+ return PermissionManagerService.this.getPermissionFlags(permName, packageName,
+ callingUid, userId);
+ }
+ @Override
+ public void updatePermissionFlags(String permName, String packageName, int flagMask,
+ int flagValues, int callingUid, int userId, PermissionCallback callback) {
+ PermissionManagerService.this.updatePermissionFlags(
+ permName, packageName, flagMask, flagValues, callingUid, userId, callback);
+ }
+ @Override
+ public boolean updatePermissionFlagsForAllApps(int flagMask, int flagValues, int callingUid,
+ int userId, Collection<Package> packages, PermissionCallback callback) {
+ return PermissionManagerService.this.updatePermissionFlagsForAllApps(
+ flagMask, flagValues, callingUid, userId, packages, callback);
+ }
+ @Override
+ public void enforceCrossUserPermission(int callingUid, int userId,
+ boolean requireFullPermission, boolean checkShell, String message) {
+ PermissionManagerService.this.enforceCrossUserPermission(callingUid, userId,
+ requireFullPermission, checkShell, message);
+ }
+ @Override
+ public void enforceGrantRevokeRuntimePermissionPermissions(String message) {
+ PermissionManagerService.this.enforceGrantRevokeRuntimePermissionPermissions(message);
+ }
+ @Override
+ public int checkPermission(String permName, String packageName, int callingUid,
+ int userId) {
+ return PermissionManagerService.this.checkPermission(
+ permName, packageName, callingUid, userId);
+ }
+ @Override
+ public PermissionInfo getPermissionInfo(String permName, String packageName, int flags,
+ int callingUid) {
+ return PermissionManagerService.this.getPermissionInfo(
+ permName, packageName, flags, callingUid);
+ }
+ @Override
+ public List<PermissionInfo> getPermissionInfoByGroup(String group, int flags,
+ int callingUid) {
+ return PermissionManagerService.this.getPermissionInfoByGroup(group, flags, callingUid);
+ }
+ @Override
+ public boolean isPermissionInstant(String permName) {
+ synchronized (PermissionManagerService.this.mLock) {
+ final BasePermission bp = mSettings.getPermissionLocked(permName);
+ return (bp != null && bp.isInstant());
+ }
+ }
+ @Override
+ public boolean isPermissionAppOp(String permName) {
+ synchronized (PermissionManagerService.this.mLock) {
+ final BasePermission bp = mSettings.getPermissionLocked(permName);
+ return (bp != null && bp.isAppOp());
+ }
+ }
+ @Override
+ public PermissionSettings getPermissionSettings() {
+ return mSettings;
+ }
+ @Override
+ public DefaultPermissionGrantPolicy getDefaultPermissionGrantPolicy() {
+ return mDefaultPermissionGrantPolicy;
+ }
+ @Override
+ public BasePermission getPermissionTEMP(String permName) {
+ synchronized (PermissionManagerService.this.mLock) {
+ return mSettings.getPermissionLocked(permName);
+ }
+ }
+ @Override
+ public void putPermissionTEMP(String permName, BasePermission permission) {
+ synchronized (PermissionManagerService.this.mLock) {
+ mSettings.putPermissionLocked(permName, (BasePermission) permission);
+ }
+ }
+ @Override
+ public Iterator<BasePermission> getPermissionIteratorTEMP() {
+ synchronized (PermissionManagerService.this.mLock) {
+ return mSettings.getAllPermissionsLocked().iterator();
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionSettings.java b/services/core/java/com/android/server/pm/permission/PermissionSettings.java
new file mode 100644
index 0000000..7a2e5ecc
--- /dev/null
+++ b/services/core/java/com/android/server/pm/permission/PermissionSettings.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.permission;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+
+import com.android.internal.R;
+import com.android.internal.util.XmlUtils;
+import com.android.server.pm.DumpState;
+import com.android.server.pm.PackageManagerService;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Collection;
+
+/**
+ * Permissions and other related data. This class is not meant for
+ * direct access outside of the permission package with the sole exception
+ * of package settings. Instead, it should be reference either from the
+ * permission manager or package settings.
+ */
+public class PermissionSettings {
+
+ final boolean mPermissionReviewRequired;
+ /**
+ * All of the permissions known to the system. The mapping is from permission
+ * name to permission object.
+ */
+ private final ArrayMap<String, BasePermission> mPermissions =
+ new ArrayMap<String, BasePermission>();
+ private final Object mLock;
+
+ PermissionSettings(@NonNull Context context, @NonNull Object lock) {
+ mPermissionReviewRequired =
+ context.getResources().getBoolean(R.bool.config_permissionReviewRequired);
+ mLock = lock;
+ }
+
+ public @Nullable BasePermission getPermission(@NonNull String permName) {
+ synchronized (mLock) {
+ return getPermissionLocked(permName);
+ }
+ }
+
+ /**
+ * Transfers ownership of permissions from one package to another.
+ */
+ public void transferPermissions(String origPackageName, String newPackageName,
+ ArrayMap<String, BasePermission> permissionTrees) {
+ synchronized (mLock) {
+ for (int i=0; i<2; i++) {
+ ArrayMap<String, BasePermission> permissions =
+ i == 0 ? permissionTrees : mPermissions;
+ for (BasePermission bp : permissions.values()) {
+ bp.transfer(origPackageName, newPackageName);
+ }
+ }
+ }
+ }
+
+ public boolean canPropagatePermissionToInstantApp(String permName) {
+ synchronized (mLock) {
+ final BasePermission bp = mPermissions.get(permName);
+ return (bp != null && (bp.isRuntime() || bp.isDevelopment()) && bp.isInstant());
+ }
+ }
+
+ public void readPermissions(XmlPullParser parser) throws IOException, XmlPullParserException {
+ synchronized (mLock) {
+ readPermissions(mPermissions, parser);
+ }
+ }
+
+ public void writePermissions(XmlSerializer serializer) throws IOException {
+ for (BasePermission bp : mPermissions.values()) {
+ bp.writeLPr(serializer);
+ }
+ }
+
+ public static void readPermissions(ArrayMap<String, BasePermission> out, XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ if (!BasePermission.readLPw(out, parser)) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element reading permissions: " + parser.getName() + " at "
+ + parser.getPositionDescription());
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ public void dumpPermissions(PrintWriter pw, String packageName,
+ ArraySet<String> permissionNames, boolean externalStorageEnforced,
+ DumpState dumpState) {
+ synchronized (mLock) {
+ boolean printedSomething = false;
+ for (BasePermission bp : mPermissions.values()) {
+ printedSomething = bp.dumpPermissionsLPr(pw, packageName, permissionNames,
+ externalStorageEnforced, printedSomething, dumpState);
+ }
+ }
+ }
+
+ @Nullable BasePermission getPermissionLocked(@NonNull String permName) {
+ return mPermissions.get(permName);
+ }
+
+ void putPermissionLocked(@NonNull String permName, @NonNull BasePermission permission) {
+ mPermissions.put(permName, permission);
+ }
+
+ void removePermissionLocked(@NonNull String permName) {
+ mPermissions.remove(permName);
+ }
+
+ Collection<BasePermission> getAllPermissionsLocked() {
+ return mPermissions.values();
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PermissionsState.java b/services/core/java/com/android/server/pm/permission/PermissionsState.java
similarity index 99%
rename from services/core/java/com/android/server/pm/PermissionsState.java
rename to services/core/java/com/android/server/pm/permission/PermissionsState.java
index 8b42a99..11df380 100644
--- a/services/core/java/com/android/server/pm/PermissionsState.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionsState.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm;
+package com.android.server.pm.permission;
import android.content.pm.PackageManager;
import android.os.UserHandle;
@@ -24,7 +24,6 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.permission.BasePermission;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index f10bf1a..83fd549 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -529,7 +529,7 @@
*/
@Override
public void disable2ForUser(int what, IBinder token, String pkg, int userId) {
- enforceStatusBar();
+ enforceStatusBarService();
synchronized (mLock) {
disableLocked(userId, what, token, pkg, 2);
diff --git a/services/core/java/com/android/server/utils/ManagedApplicationService.java b/services/core/java/com/android/server/utils/ManagedApplicationService.java
index 1ea7058..c555388 100644
--- a/services/core/java/com/android/server/utils/ManagedApplicationService.java
+++ b/services/core/java/com/android/server/utils/ManagedApplicationService.java
@@ -16,19 +16,24 @@
package com.android.server.utils;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.IInterface;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Slog;
+import java.text.SimpleDateFormat;
import java.util.Objects;
+import java.util.Date;
/**
* Manages the lifecycle of an application-provided service bound from system server.
@@ -38,6 +43,40 @@
public class ManagedApplicationService {
private final String TAG = getClass().getSimpleName();
+ /**
+ * Attempt to reconnect service forever if an onBindingDied or onServiceDisconnected event
+ * is received.
+ */
+ public static final int RETRY_FOREVER = 1;
+
+ /**
+ * Never attempt to reconnect the service - a single onBindingDied or onServiceDisconnected
+ * event will cause this to fully unbind the service and never attempt to reconnect.
+ */
+ public static final int RETRY_NEVER = 2;
+
+ /**
+ * Attempt to reconnect the service until the maximum number of retries is reached, then stop.
+ *
+ * The first retry will occur MIN_RETRY_DURATION_MS after the disconnection, and each
+ * subsequent retry will occur after 2x the duration used for the previous retry up to the
+ * MAX_RETRY_DURATION_MS duration.
+ *
+ * In this case, retries mean a full unbindService/bindService pair to handle cases when the
+ * usual service re-connection logic in ActiveServices has very high backoff times or when the
+ * serviceconnection has fully died due to a package update or similar.
+ */
+ public static final int RETRY_BEST_EFFORT = 3;
+
+ // Maximum number of retries before giving up (for RETRY_BEST_EFFORT).
+ private static final int MAX_RETRY_COUNT = 4;
+ // Max time between retry attempts.
+ private static final long MAX_RETRY_DURATION_MS = 16000;
+ // Min time between retry attempts.
+ private static final long MIN_RETRY_DURATION_MS = 2000;
+ // Time since the last retry attempt after which to clear the retry attempt counter.
+ private static final long RETRY_RESET_TIME_MS = MAX_RETRY_DURATION_MS * 4;
+
private final Context mContext;
private final int mUserId;
private final ComponentName mComponent;
@@ -45,27 +84,75 @@
private final String mSettingsAction;
private final BinderChecker mChecker;
private final boolean mIsImportant;
-
- private final DeathRecipient mDeathRecipient = new DeathRecipient() {
- @Override
- public void binderDied() {
- synchronized (mLock) {
- mBoundInterface = null;
- }
- }
- };
+ private final int mRetryType;
+ private final Handler mHandler;
+ private final Runnable mRetryRunnable = this::doRetry;
+ private final EventCallback mEventCb;
private final Object mLock = new Object();
// State protected by mLock
- private ServiceConnection mPendingConnection;
private ServiceConnection mConnection;
private IInterface mBoundInterface;
private PendingEvent mPendingEvent;
+ private int mRetryCount;
+ private long mLastRetryTimeMs;
+ private long mNextRetryDurationMs = MIN_RETRY_DURATION_MS;
+ private boolean mRetrying;
+
+ public static interface LogFormattable {
+ String toLogString(SimpleDateFormat dateFormat);
+ }
+
+ /**
+ * Lifecycle event of this managed service.
+ */
+ public static class LogEvent implements LogFormattable {
+ public static final int EVENT_CONNECTED = 1;
+ public static final int EVENT_DISCONNECTED = 2;
+ public static final int EVENT_BINDING_DIED = 3;
+ public static final int EVENT_STOPPED_PERMANENTLY = 4;
+
+ // Time of the events in "current time ms" timebase.
+ public final long timestamp;
+ // Name of the component for this system service.
+ public final ComponentName component;
+ // ID of the event that occurred.
+ public final int event;
+
+ public LogEvent(long timestamp, ComponentName component, int event) {
+ this.timestamp = timestamp;
+ this.component = component;
+ this.event = event;
+ }
+
+ @Override
+ public String toLogString(SimpleDateFormat dateFormat) {
+ return dateFormat.format(new Date(timestamp)) + " " + eventToString(event)
+ + " Managed Service: "
+ + ((component == null) ? "None" : component.flattenToString());
+ }
+
+ public static String eventToString(int event) {
+ switch (event) {
+ case EVENT_CONNECTED:
+ return "Connected";
+ case EVENT_DISCONNECTED:
+ return "Disconnected";
+ case EVENT_BINDING_DIED:
+ return "Binding Died For";
+ case EVENT_STOPPED_PERMANENTLY:
+ return "Permanently Stopped";
+ default:
+ return "Unknown Event Occurred";
+ }
+ }
+ }
private ManagedApplicationService(final Context context, final ComponentName component,
final int userId, int clientLabel, String settingsAction,
- BinderChecker binderChecker, boolean isImportant) {
+ BinderChecker binderChecker, boolean isImportant, int retryType, Handler handler,
+ EventCallback eventCallback) {
mContext = context;
mComponent = component;
mUserId = userId;
@@ -73,6 +160,9 @@
mSettingsAction = settingsAction;
mChecker = binderChecker;
mIsImportant = isImportant;
+ mRetryType = retryType;
+ mHandler = handler;
+ mEventCb = eventCallback;
}
/**
@@ -87,7 +177,17 @@
* Implement to call IInterface methods after service is connected.
*/
public interface PendingEvent {
- void runEvent(IInterface service) throws RemoteException;
+ void runEvent(IInterface service) throws RemoteException;
+ }
+
+ /**
+ * Implement to be notified about any problems with remote service.
+ */
+ public interface EventCallback {
+ /**
+ * Called when an sevice lifecycle event occurs.
+ */
+ void onServiceEvent(LogEvent event);
}
/**
@@ -97,21 +197,28 @@
* @param component the {@link ComponentName} of the application service to bind.
* @param userId the user ID of user to bind the application service as.
* @param clientLabel the resource ID of a label displayed to the user indicating the
- * binding service.
+ * binding service, or 0 if none is desired.
* @param settingsAction an action that can be used to open the Settings UI to enable/disable
- * binding to these services.
- * @param binderChecker an interface used to validate the returned binder object.
+ * binding to these services, or null if none is desired.
+ * @param binderChecker an interface used to validate the returned binder object, or null if
+ * this interface is unchecked.
* @param isImportant bind the user service with BIND_IMPORTANT.
+ * @param retryType reconnect behavior to have when bound service is disconnected.
+ * @param handler the Handler to use for retries and delivering EventCallbacks.
+ * @param eventCallback a callback used to deliver disconnection events, or null if you
+ * don't care.
* @return a ManagedApplicationService instance.
*/
public static ManagedApplicationService build(@NonNull final Context context,
- @NonNull final ComponentName component, final int userId, @NonNull int clientLabel,
- @NonNull String settingsAction, @NonNull BinderChecker binderChecker,
- boolean isImportant) {
+ @NonNull final ComponentName component, final int userId, int clientLabel,
+ @Nullable String settingsAction, @Nullable BinderChecker binderChecker,
+ boolean isImportant, int retryType, @NonNull Handler handler,
+ @Nullable EventCallback eventCallback) {
return new ManagedApplicationService(context, component, userId, clientLabel,
- settingsAction, binderChecker, isImportant);
+ settingsAction, binderChecker, isImportant, retryType, handler, eventCallback);
}
+
/**
* @return the user ID of the user that owns the bound service.
*/
@@ -142,13 +249,12 @@
return true;
}
-
- /**
- * Send an event to run as soon as the binder interface is available.
- *
- * @param event a {@link PendingEvent} to send.
- */
- public void sendEvent(@NonNull PendingEvent event) {
+ /**
+ * Send an event to run as soon as the binder interface is available.
+ *
+ * @param event a {@link PendingEvent} to send.
+ */
+ public void sendEvent(@NonNull PendingEvent event) {
IInterface iface;
synchronized (mLock) {
iface = mBoundInterface;
@@ -171,15 +277,13 @@
*/
public void disconnect() {
synchronized (mLock) {
- // Wipe out pending connections
- mPendingConnection = null;
-
// Unbind existing connection, if it exists
- if (mConnection != null) {
- mContext.unbindService(mConnection);
- mConnection = null;
+ if (mConnection == null) {
+ return;
}
+ mContext.unbindService(mConnection);
+ mConnection = null;
mBoundInterface = null;
}
}
@@ -189,48 +293,70 @@
*/
public void connect() {
synchronized (mLock) {
- if (mConnection != null || mPendingConnection != null) {
+ if (mConnection != null) {
// We're already connected or are trying to connect
return;
}
- final PendingIntent pendingIntent = PendingIntent.getActivity(
- mContext, 0, new Intent(mSettingsAction), 0);
- final Intent intent = new Intent().setComponent(mComponent).
- putExtra(Intent.EXTRA_CLIENT_LABEL, mClientLabel).
- putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
+ Intent intent = new Intent().setComponent(mComponent);
+ if (mClientLabel != 0) {
+ intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mClientLabel);
+ }
+ if (mSettingsAction != null) {
+ intent.putExtra(Intent.EXTRA_CLIENT_INTENT,
+ PendingIntent.getActivity(mContext, 0, new Intent(mSettingsAction), 0));
+ }
- final ServiceConnection serviceConnection = new ServiceConnection() {
+ mConnection = new ServiceConnection() {
+ @Override
+ public void onBindingDied(ComponentName componentName) {
+ final long timestamp = System.currentTimeMillis();
+ Slog.w(TAG, "Service binding died: " + componentName);
+ synchronized (mLock) {
+ if (mConnection != this) {
+ return;
+ }
+ mHandler.post(() -> {
+ mEventCb.onServiceEvent(new LogEvent(timestamp, mComponent,
+ LogEvent.EVENT_BINDING_DIED));
+ });
+
+ mBoundInterface = null;
+ startRetriesLocked();
+ }
+ }
+
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
+ final long timestamp = System.currentTimeMillis();
+ Slog.i(TAG, "Service connected: " + componentName);
IInterface iface = null;
PendingEvent pendingEvent = null;
synchronized (mLock) {
- if (mPendingConnection == this) {
- // No longer pending, remove from pending connection
- mPendingConnection = null;
- mConnection = this;
- } else {
- // Service connection wasn't pending, must have been disconnected
- mContext.unbindService(this);
+ if (mConnection != this) {
+ // Must've been unbound.
return;
}
+ mHandler.post(() -> {
+ mEventCb.onServiceEvent(new LogEvent(timestamp, mComponent,
+ LogEvent.EVENT_CONNECTED));
+ });
- try {
- iBinder.linkToDeath(mDeathRecipient, 0);
+ stopRetriesLocked();
+
+ mBoundInterface = null;
+ if (mChecker != null) {
mBoundInterface = mChecker.asInterface(iBinder);
if (!mChecker.checkType(mBoundInterface)) {
- // Received an invalid binder, disconnect
- mContext.unbindService(this);
+ // Received an invalid binder, disconnect.
mBoundInterface = null;
+ Slog.w(TAG, "Invalid binder from " + componentName);
+ startRetriesLocked();
+ return;
}
iface = mBoundInterface;
pendingEvent = mPendingEvent;
mPendingEvent = null;
- } catch (RemoteException e) {
- // DOA
- Slog.w(TAG, "Unable to bind service: " + intent, e);
- mBoundInterface = null;
}
}
if (iface != null && pendingEvent != null) {
@@ -238,31 +364,44 @@
pendingEvent.runEvent(iface);
} catch (RuntimeException | RemoteException ex) {
Slog.e(TAG, "Received exception from user service: ", ex);
+ startRetriesLocked();
}
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
- Slog.w(TAG, "Service disconnected: " + intent);
- mConnection = null;
- mBoundInterface = null;
+ final long timestamp = System.currentTimeMillis();
+ Slog.w(TAG, "Service disconnected: " + componentName);
+ synchronized (mLock) {
+ if (mConnection != this) {
+ return;
+ }
+
+ mHandler.post(() -> {
+ mEventCb.onServiceEvent(new LogEvent(timestamp, mComponent,
+ LogEvent.EVENT_DISCONNECTED));
+ });
+
+ mBoundInterface = null;
+ startRetriesLocked();
+ }
}
};
- mPendingConnection = serviceConnection;
-
int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
if (mIsImportant) {
flags |= Context.BIND_IMPORTANT;
}
try {
- if (!mContext.bindServiceAsUser(intent, serviceConnection, flags,
+ if (!mContext.bindServiceAsUser(intent, mConnection, flags,
new UserHandle(mUserId))) {
Slog.w(TAG, "Unable to bind service: " + intent);
+ startRetriesLocked();
}
} catch (SecurityException e) {
Slog.w(TAG, "Unable to bind service: " + intent, e);
+ startRetriesLocked();
}
}
}
@@ -270,4 +409,81 @@
private boolean matches(final ComponentName component, final int userId) {
return Objects.equals(mComponent, component) && mUserId == userId;
}
+
+ private void startRetriesLocked() {
+ if (checkAndDeliverServiceDiedCbLocked()) {
+ // If we delivered the service callback, disconnect and stop retrying.
+ disconnect();
+ return;
+ }
+
+ if (mRetrying) {
+ // Retry already queued, don't queue a new one.
+ return;
+ }
+ mRetrying = true;
+ queueRetryLocked();
+ }
+
+ private void stopRetriesLocked() {
+ mRetrying = false;
+ mHandler.removeCallbacks(mRetryRunnable);
+ }
+
+ private void queueRetryLocked() {
+ long now = SystemClock.uptimeMillis();
+ if ((now - mLastRetryTimeMs) > RETRY_RESET_TIME_MS) {
+ // It's been longer than the reset time since we last had to retry. Re-initialize.
+ mNextRetryDurationMs = MIN_RETRY_DURATION_MS;
+ mRetryCount = 0;
+ }
+ mLastRetryTimeMs = now;
+ mHandler.postDelayed(mRetryRunnable, mNextRetryDurationMs);
+ mNextRetryDurationMs = Math.min(2 * mNextRetryDurationMs, MAX_RETRY_DURATION_MS);
+ mRetryCount++;
+ }
+
+ private boolean checkAndDeliverServiceDiedCbLocked() {
+
+ if (mRetryType == RETRY_NEVER || (mRetryType == RETRY_BEST_EFFORT
+ && mRetryCount >= MAX_RETRY_COUNT)) {
+ // If we never retry, or we've exhausted our retries, post the onServiceDied callback.
+ Slog.e(TAG, "Service " + mComponent + " has died too much, not retrying.");
+ if (mEventCb != null) {
+ final long timestamp = System.currentTimeMillis();
+ mHandler.post(() -> {
+ mEventCb.onServiceEvent(new LogEvent(timestamp, mComponent,
+ LogEvent.EVENT_STOPPED_PERMANENTLY));
+ });
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private void doRetry() {
+ synchronized (mLock) {
+ if (mConnection == null) {
+ // We disconnected for good. Don't attempt to retry.
+ return;
+ }
+ if (!mRetrying) {
+ // We successfully connected. Don't attempt to retry.
+ return;
+ }
+ Slog.i(TAG, "Attempting to reconnect " + mComponent + "...");
+ // While frameworks may restart the remote Service if we stay bound, we have little
+ // control of the backoff timing for reconnecting the service. In the event of a
+ // process crash, the backoff time can be very large (1-30 min), which is not
+ // acceptable for the types of services this is used for. Instead force an unbind/bind
+ // sequence to cause a more immediate retry.
+ disconnect();
+ if (checkAndDeliverServiceDiedCbLocked()) {
+ // No more retries.
+ return;
+ }
+ queueRetryLocked();
+ connect();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/vr/Vr2dDisplay.java b/services/core/java/com/android/server/vr/Vr2dDisplay.java
index 5721415..95d03d4 100644
--- a/services/core/java/com/android/server/vr/Vr2dDisplay.java
+++ b/services/core/java/com/android/server/vr/Vr2dDisplay.java
@@ -296,6 +296,7 @@
flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT;
flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
+ flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL;
mVirtualDisplay = mDisplayManager.createVirtualDisplay(null /* projection */,
DISPLAY_NAME, mVirtualDisplayWidth, mVirtualDisplayHeight, mVirtualDisplayDpi,
null /* surface */, flags, null /* callback */, null /* handler */,
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 830ebda..1511aee3 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -66,6 +66,8 @@
import com.android.server.SystemConfig;
import com.android.server.SystemService;
import com.android.server.utils.ManagedApplicationService.PendingEvent;
+import com.android.server.utils.ManagedApplicationService.LogEvent;
+import com.android.server.utils.ManagedApplicationService.LogFormattable;
import com.android.server.vr.EnabledComponentsObserver.EnabledComponentChangeListener;
import com.android.server.utils.ManagedApplicationService;
import com.android.server.utils.ManagedApplicationService.BinderChecker;
@@ -108,7 +110,7 @@
static final boolean DBG = false;
private static final int PENDING_STATE_DELAY_MS = 300;
- private static final int EVENT_LOG_SIZE = 32;
+ private static final int EVENT_LOG_SIZE = 64;
private static final int INVALID_APPOPS_MODE = -1;
/** Null set of sleep sleep flags. */
private static final int FLAG_NONE = 0;
@@ -134,6 +136,7 @@
private int mVrAppProcessId;
private EnabledComponentsObserver mComponentObserver;
private ManagedApplicationService mCurrentVrService;
+ private ManagedApplicationService mCurrentVrCompositorService;
private ComponentName mDefaultVrService;
private Context mContext;
private ComponentName mCurrentVrModeComponent;
@@ -147,7 +150,8 @@
private int mPreviousCoarseLocationMode = INVALID_APPOPS_MODE;
private int mPreviousManageOverlayMode = INVALID_APPOPS_MODE;
private VrState mPendingState;
- private final ArrayDeque<VrState> mLoggingDeque = new ArrayDeque<>(EVENT_LOG_SIZE);
+ private boolean mLogLimitHit;
+ private final ArrayDeque<LogFormattable> mLoggingDeque = new ArrayDeque<>(EVENT_LOG_SIZE);
private final NotificationAccessManager mNotifAccessManager = new NotificationAccessManager();
private INotificationManager mNotificationManager;
/** Tracks the state of the screen and keyguard UI.*/
@@ -160,6 +164,30 @@
private Vr2dDisplay mVr2dDisplay;
private boolean mBootsToVr;
+ // Handles events from the managed services (e.g. VrListenerService and any bound VR compositor
+ // service).
+ private final ManagedApplicationService.EventCallback mEventCallback
+ = new ManagedApplicationService.EventCallback() {
+ @Override
+ public void onServiceEvent(LogEvent event) {
+ logEvent(event);
+
+ ComponentName component = null;
+ synchronized (mLock) {
+ component = ((mCurrentVrService == null) ? null : mCurrentVrService.getComponent());
+ }
+
+ // If not on an AIO device and we permanently stopped trying to connect to the
+ // VrListenerService (or don't have one bound), leave persistent VR mode and VR mode.
+ if (!mBootsToVr && event.event == LogEvent.EVENT_STOPPED_PERMANENTLY &&
+ (component == null || component.equals(event.component))) {
+ Slog.e(TAG, "VrListenerSevice has died permanently, leaving system VR mode.");
+ // We're not a native VR device. Leave VR + persistent mode.
+ setPersistentVrModeEnabled(false);
+ }
+ }
+ };
+
private static final int MSG_VR_STATE_CHANGE = 0;
private static final int MSG_PENDING_VR_STATE_CHANGE = 1;
private static final int MSG_PERSISTENT_VR_MODE_STATE_CHANGE = 2;
@@ -276,7 +304,24 @@
}
};
- private static class VrState {
+ // Event used to log when settings are changed for dumpsys logs.
+ private static class SettingEvent implements LogFormattable {
+ public final long timestamp;
+ public final String what;
+
+ SettingEvent(String what) {
+ this.timestamp = System.currentTimeMillis();
+ this.what = what;
+ }
+
+ @Override
+ public String toLogString(SimpleDateFormat dateFormat) {
+ return dateFormat.format(new Date(timestamp)) + " " + what;
+ }
+ }
+
+ // Event used to track changes of the primary on-screen VR activity.
+ private static class VrState implements LogFormattable {
final boolean enabled;
final boolean running2dInVr;
final int userId;
@@ -286,7 +331,6 @@
final long timestamp;
final boolean defaultPermissionsGranted;
-
VrState(boolean enabled, boolean running2dInVr, ComponentName targetPackageName, int userId,
int processId, ComponentName callingPackage) {
this.enabled = enabled;
@@ -310,6 +354,39 @@
this.defaultPermissionsGranted = defaultPermissionsGranted;
this.timestamp = System.currentTimeMillis();
}
+
+ @Override
+ public String toLogString(SimpleDateFormat dateFormat) {
+ String tab = " ";
+ String newLine = "\n";
+ StringBuilder sb = new StringBuilder(dateFormat.format(new Date(timestamp)));
+ sb.append(tab);
+ sb.append("State changed to:");
+ sb.append(tab);
+ sb.append((enabled) ? "ENABLED" : "DISABLED");
+ sb.append(newLine);
+ if (enabled) {
+ sb.append(tab);
+ sb.append("User=");
+ sb.append(userId);
+ sb.append(newLine);
+ sb.append(tab);
+ sb.append("Current VR Activity=");
+ sb.append((callingPackage == null) ? "None" : callingPackage.flattenToString());
+ sb.append(newLine);
+ sb.append(tab);
+ sb.append("Bound VrListenerService=");
+ sb.append((targetPackageName == null) ? "None"
+ : targetPackageName.flattenToString());
+ sb.append(newLine);
+ if (defaultPermissionsGranted) {
+ sb.append(tab);
+ sb.append("Default permissions granted to the bound VrListenerService.");
+ sb.append(newLine);
+ }
+ }
+ return sb.toString();
+ }
}
private static final BinderChecker sBinderChecker = new BinderChecker() {
@@ -490,6 +567,13 @@
}
@Override
+ public void setAndBindCompositor(String componentName) {
+ enforceCallerPermissionAnyOf(Manifest.permission.RESTRICTED_VR_ACCESS);
+ VrManagerService.this.setAndBindCompositor(
+ (componentName == null) ? null : ComponentName.unflattenFromString(componentName));
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
@@ -497,6 +581,12 @@
pw.println("VR mode is currently: " + ((mVrModeAllowed) ? "allowed" : "disallowed"));
pw.println("Persistent VR mode is currently: " +
((mPersistentVrModeEnabled) ? "enabled" : "disabled"));
+ pw.println("Currently bound VR listener service: "
+ + ((mCurrentVrService == null)
+ ? "None" : mCurrentVrService.getComponent().flattenToString()));
+ pw.println("Currently bound VR compositor service: "
+ + ((mCurrentVrCompositorService == null)
+ ? "None" : mCurrentVrCompositorService.getComponent().flattenToString()));
pw.println("Previous state transitions:\n");
String tab = " ";
dumpStateTransitions(pw);
@@ -785,6 +875,7 @@
+ mCurrentVrService.getComponent() + " for user "
+ mCurrentVrService.getUserId());
mCurrentVrService.disconnect();
+ updateCompositorServiceLocked(UserHandle.USER_NULL, null);
mCurrentVrService = null;
} else {
nothingChanged = true;
@@ -798,6 +889,7 @@
Slog.i(TAG, "VR mode component changed to " + component
+ ", disconnecting " + mCurrentVrService.getComponent()
+ " for user " + mCurrentVrService.getUserId());
+ updateCompositorServiceLocked(UserHandle.USER_NULL, null);
createAndConnectService(component, userId);
sendUpdatedCaller = true;
} else {
@@ -985,7 +1077,7 @@
private void createAndConnectService(@NonNull ComponentName component, int userId) {
- mCurrentVrService = VrManagerService.create(mContext, component, userId);
+ mCurrentVrService = createVrListenerService(component, userId);
mCurrentVrService.connect();
Slog.i(TAG, "Connecting " + component + " for user " + userId);
}
@@ -1020,13 +1112,27 @@
}
/**
- * Helper function for making ManagedApplicationService instances.
+ * Helper function for making ManagedApplicationService for VrListenerService instances.
*/
- private static ManagedApplicationService create(@NonNull Context context,
- @NonNull ComponentName component, int userId) {
- return ManagedApplicationService.build(context, component, userId,
+ private ManagedApplicationService createVrListenerService(@NonNull ComponentName component,
+ int userId) {
+ int retryType = (mBootsToVr) ? ManagedApplicationService.RETRY_FOREVER
+ : ManagedApplicationService.RETRY_NEVER;
+ return ManagedApplicationService.build(mContext, component, userId,
R.string.vr_listener_binding_label, Settings.ACTION_VR_LISTENER_SETTINGS,
- sBinderChecker, /*isImportant*/true);
+ sBinderChecker, /*isImportant*/true, retryType, mHandler, mEventCallback);
+ }
+
+ /**
+ * Helper function for making ManagedApplicationService for VR Compositor instances.
+ */
+ private ManagedApplicationService createVrCompositorService(@NonNull ComponentName component,
+ int userId) {
+ int retryType = (mBootsToVr) ? ManagedApplicationService.RETRY_FOREVER
+ : ManagedApplicationService.RETRY_BEST_EFFORT;
+ return ManagedApplicationService.build(mContext, component, userId, /*clientLabel*/0,
+ /*settingsAction*/null, /*binderChecker*/null, /*isImportant*/true, retryType,
+ mHandler, /*disconnectCallback*/mEventCallback);
}
/**
@@ -1057,44 +1163,35 @@
private void logStateLocked() {
ComponentName currentBoundService = (mCurrentVrService == null) ? null :
- mCurrentVrService.getComponent();
- VrState current = new VrState(mVrModeEnabled, mRunning2dInVr, currentBoundService,
- mCurrentVrModeUser, mVrAppProcessId, mCurrentVrModeComponent, mWasDefaultGranted);
- if (mLoggingDeque.size() == EVENT_LOG_SIZE) {
- mLoggingDeque.removeFirst();
+ mCurrentVrService.getComponent();
+ logEvent(new VrState(mVrModeEnabled, mRunning2dInVr, currentBoundService,
+ mCurrentVrModeUser, mVrAppProcessId, mCurrentVrModeComponent, mWasDefaultGranted));
+ }
+
+ private void logEvent(LogFormattable event) {
+ synchronized (mLoggingDeque) {
+ if (mLoggingDeque.size() == EVENT_LOG_SIZE) {
+ mLoggingDeque.removeFirst();
+ mLogLimitHit = true;
+ }
+ mLoggingDeque.add(event);
}
- mLoggingDeque.add(current);
}
private void dumpStateTransitions(PrintWriter pw) {
SimpleDateFormat d = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
- String tab = " ";
- if (mLoggingDeque.size() == 0) {
- pw.print(tab);
- pw.println("None");
- }
- for (VrState state : mLoggingDeque) {
- pw.print(d.format(new Date(state.timestamp)));
- pw.print(tab);
- pw.print("State changed to:");
- pw.print(tab);
- pw.println((state.enabled) ? "ENABLED" : "DISABLED");
- if (state.enabled) {
- pw.print(tab);
- pw.print("User=");
- pw.println(state.userId);
- pw.print(tab);
- pw.print("Current VR Activity=");
- pw.println((state.callingPackage == null) ?
- "None" : state.callingPackage.flattenToString());
- pw.print(tab);
- pw.print("Bound VrListenerService=");
- pw.println((state.targetPackageName == null) ?
- "None" : state.targetPackageName.flattenToString());
- if (state.defaultPermissionsGranted) {
- pw.print(tab);
- pw.println("Default permissions granted to the bound VrListenerService.");
- }
+ synchronized (mLoggingDeque) {
+ if (mLoggingDeque.size() == 0) {
+ pw.print(" ");
+ pw.println("None");
+ }
+
+ if (mLogLimitHit) {
+ pw.println("..."); // Indicates log overflow
+ }
+
+ for (LogFormattable event : mLoggingDeque) {
+ pw.println(event.toLogString(d));
}
}
}
@@ -1177,10 +1274,41 @@
return INVALID_DISPLAY;
}
+ private void setAndBindCompositor(ComponentName componentName) {
+ final int userId = UserHandle.getCallingUserId();
+ final long token = Binder.clearCallingIdentity();
+ synchronized (mLock) {
+ updateCompositorServiceLocked(userId, componentName);
+ }
+ Binder.restoreCallingIdentity(token);
+ }
+
+ private void updateCompositorServiceLocked(int userId, ComponentName componentName) {
+ if (mCurrentVrCompositorService != null
+ && mCurrentVrCompositorService.disconnectIfNotMatching(componentName, userId)) {
+ Slog.i(TAG, "Disconnecting compositor service: "
+ + mCurrentVrCompositorService.getComponent());
+ // Check if existing service matches the requested one, if not (or if the requested
+ // component is null) disconnect it.
+ mCurrentVrCompositorService = null;
+ }
+
+ if (componentName != null && mCurrentVrCompositorService == null) {
+ // We don't have an existing service matching the requested component, so attempt to
+ // connect one.
+ Slog.i(TAG, "Connecting compositor service: " + componentName);
+ mCurrentVrCompositorService = createVrCompositorService(componentName, userId);
+ mCurrentVrCompositorService.connect();
+ }
+ }
+
private void setPersistentModeAndNotifyListenersLocked(boolean enabled) {
if (mPersistentVrModeEnabled == enabled) {
return;
}
+ String eventName = "Persistent VR mode " + ((enabled) ? "enabled" : "disabled");
+ Slog.i(TAG, eventName);
+ logEvent(new SettingEvent(eventName));
mPersistentVrModeEnabled = enabled;
mHandler.sendMessage(mHandler.obtainMessage(MSG_PERSISTENT_VR_MODE_STATE_CHANGE,
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index c76b905..5365e27 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -16,10 +16,10 @@
package com.android.server.wm;
-import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -78,11 +78,8 @@
// requires that the duration of the two animations are the same.
SurfaceControl thumbnail;
int thumbnailTransactionSeq;
- // TODO(b/62029108): combine both members into a private one. Create a member function to set
- // the thumbnail layer to +1 to the highest layer position and replace all setter instances
- // with this function. Remove all unnecessary calls to both variables in other classes.
- int thumbnailLayer;
- int thumbnailForceAboveLayer;
+ private int mThumbnailLayer;
+
Animation thumbnailAnimation;
final Transformation thumbnailTransformation = new Transformation();
// This flag indicates that the destruction of the thumbnail surface is synchronized with
@@ -256,7 +253,7 @@
private void updateLayers() {
mAppToken.getDisplayContent().assignWindowLayers(false /* relayoutNeeded */);
- thumbnailLayer = mAppToken.getHighestAnimLayer();
+ updateThumbnailLayer();
}
private void stepThumbnailAnimation(long currentTime) {
@@ -280,26 +277,35 @@
thumbnail.setPosition(tmpFloats[Matrix.MTRANS_X], tmpFloats[Matrix.MTRANS_Y]);
if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail,
"thumbnail", "alpha=" + thumbnailTransformation.getAlpha()
- + " layer=" + thumbnailLayer
+ + " layer=" + mThumbnailLayer
+ " matrix=[" + tmpFloats[Matrix.MSCALE_X]
+ "," + tmpFloats[Matrix.MSKEW_Y]
+ "][" + tmpFloats[Matrix.MSKEW_X]
+ "," + tmpFloats[Matrix.MSCALE_Y] + "]");
thumbnail.setAlpha(thumbnailTransformation.getAlpha());
- if (thumbnailForceAboveLayer > 0) {
- thumbnail.setLayer(thumbnailForceAboveLayer + 1);
- } else {
- // The thumbnail is layered below the window immediately above this
- // token's anim layer.
- thumbnail.setLayer(thumbnailLayer + WindowManagerService.WINDOW_LAYER_MULTIPLIER
- - WindowManagerService.LAYER_OFFSET_THUMBNAIL);
- }
+ updateThumbnailLayer();
thumbnail.setMatrix(tmpFloats[Matrix.MSCALE_X], tmpFloats[Matrix.MSKEW_Y],
tmpFloats[Matrix.MSKEW_X], tmpFloats[Matrix.MSCALE_Y]);
thumbnail.setWindowCrop(thumbnailTransformation.getClipRect());
}
/**
+ * Updates the thumbnail layer z order to just above the highest animation layer if changed
+ */
+ void updateThumbnailLayer() {
+ if (thumbnail != null) {
+ final int layer = mAppToken.getHighestAnimLayer();
+ if (layer != mThumbnailLayer) {
+ if (DEBUG_LAYERS) Slog.v(TAG,
+ "Setting thumbnail layer " + mAppToken + ": layer=" + layer);
+ thumbnail.setLayer(layer + WindowManagerService.WINDOW_LAYER_MULTIPLIER
+ - WindowManagerService.LAYER_OFFSET_THUMBNAIL);
+ mThumbnailLayer = layer;
+ }
+ }
+ }
+
+ /**
* Sometimes we need to synchronize the first frame of animation with some external event, e.g.
* Recents hiding some of its content. To achieve this, we prolong the start of the animaiton
* and keep producing the first frame of the animation.
@@ -473,7 +479,7 @@
}
if (thumbnail != null) {
pw.print(prefix); pw.print("thumbnail="); pw.print(thumbnail);
- pw.print(" layer="); pw.println(thumbnailLayer);
+ pw.print(" layer="); pw.println(mThumbnailLayer);
pw.print(prefix); pw.print("thumbnailAnimation="); pw.println(thumbnailAnimation);
pw.print(prefix); pw.print("thumbnailTransformation=");
pw.println(thumbnailTransformation.toShortString());
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 78f8157..a1eeff8 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1170,7 +1170,6 @@
wAppAnimator.thumbnail.destroy();
}
wAppAnimator.thumbnail = tAppAnimator.thumbnail;
- wAppAnimator.thumbnailLayer = tAppAnimator.thumbnailLayer;
wAppAnimator.thumbnailAnimation = tAppAnimator.thumbnailAnimation;
tAppAnimator.thumbnail = null;
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index bdf46c7..0e68a8f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -392,10 +392,6 @@
!= mTmpWindowAnimator.mAnimTransactionSequence) {
appAnimator.thumbnailTransactionSeq =
mTmpWindowAnimator.mAnimTransactionSequence;
- appAnimator.thumbnailLayer = 0;
- }
- if (appAnimator.thumbnailLayer < winAnimator.mAnimLayer) {
- appAnimator.thumbnailLayer = winAnimator.mAnimLayer;
}
}
};
@@ -969,10 +965,10 @@
final int lastOrientation = mLastOrientation;
final boolean oldAltOrientation = mAltOrientation;
int rotation = mService.mPolicy.rotationForOrientationLw(lastOrientation, oldRotation);
- final boolean rotateSeamlessly = mService.mPolicy.shouldRotateSeamlessly(oldRotation,
+ boolean mayRotateSeamlessly = mService.mPolicy.shouldRotateSeamlessly(oldRotation,
rotation);
- if (rotateSeamlessly) {
+ if (mayRotateSeamlessly) {
final WindowState seamlessRotated = getWindow((w) -> w.mSeamlesslyRotated);
if (seamlessRotated != null) {
// We can't rotate (seamlessly or not) while waiting for the last seamless rotation
@@ -981,7 +977,20 @@
// window-removal.
return false;
}
+
+ // In the presence of the PINNED stack or System Alert
+ // windows we unforuntately can not seamlessly rotate.
+ if (getStackById(PINNED_STACK_ID) != null) {
+ mayRotateSeamlessly = false;
+ }
+ for (int i = 0; i < mService.mSessions.size(); i++) {
+ if (mService.mSessions.valueAt(i).hasAlertWindowSurfaces()) {
+ mayRotateSeamlessly = false;
+ break;
+ }
+ }
}
+ final boolean rotateSeamlessly = mayRotateSeamlessly;
// TODO: Implement forced rotation changes.
// Set mAltOrientation to indicate that the application is receiving
diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowController.java b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
index 2215f20..41f076d 100644
--- a/services/core/java/com/android/server/wm/PinnedStackWindowController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
@@ -37,8 +37,8 @@
private Rect mTmpToBounds = new Rect();
public PinnedStackWindowController(int stackId, PinnedStackWindowListener listener,
- int displayId, boolean onTop, Rect outBounds) {
- super(stackId, listener, displayId, onTop, outBounds, WindowManagerService.getInstance());
+ int displayId, boolean onTop, Rect outBounds, WindowManagerService service) {
+ super(stackId, listener, displayId, onTop, outBounds, service);
}
/**
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 1781247..4dd147e 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -719,4 +719,8 @@
public String toString() {
return mStringName;
}
+
+ boolean hasAlertWindowSurfaces() {
+ return !mAlertWindowSurfaces.isEmpty();
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index fdd2ade..7caf2fe 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -266,20 +266,8 @@
w.mLayer = layer;
w.mWinAnimator.mAnimLayer = w.getAnimLayerAdjustment()
+ w.getSpecialWindowAnimLayerAdjustment();
- if (w.mAppToken != null && w.mAppToken.mAppAnimator.thumbnailForceAboveLayer > 0) {
- if (w.mWinAnimator.mAnimLayer > w.mAppToken.mAppAnimator.thumbnailForceAboveLayer) {
- w.mAppToken.mAppAnimator.thumbnailForceAboveLayer = w.mWinAnimator.mAnimLayer;
- }
- // TODO(b/62029108): the entire contents of the if statement should call the refactored
- // function to set the thumbnail layer for w.AppToken
- int highestLayer = w.mAppToken.getHighestAnimLayer();
- if (highestLayer > 0) {
- if (w.mAppToken.mAppAnimator.thumbnail != null
- && w.mAppToken.mAppAnimator.thumbnailForceAboveLayer != highestLayer) {
- w.mAppToken.mAppAnimator.thumbnailForceAboveLayer = highestLayer;
- w.mAppToken.mAppAnimator.thumbnail.setLayer(highestLayer + 1);
- }
- }
+ if (w.mAppToken != null) {
+ w.mAppToken.mAppAnimator.updateThumbnailLayer();
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 88625d3..af1fa2f 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -342,10 +342,7 @@
mTmpLayerAndToken.token = null;
handleClosingApps(transit, animLp, voiceInteraction, mTmpLayerAndToken);
final AppWindowToken topClosingApp = mTmpLayerAndToken.token;
- final int topClosingLayer = mTmpLayerAndToken.layer;
-
- final AppWindowToken topOpeningApp = handleOpeningApps(transit,
- animLp, voiceInteraction, topClosingLayer);
+ final AppWindowToken topOpeningApp = handleOpeningApps(transit, animLp, voiceInteraction);
mService.mAppTransition.setLastAppTransition(transit, topOpeningApp, topClosingApp);
@@ -387,8 +384,9 @@
}
private AppWindowToken handleOpeningApps(int transit, LayoutParams animLp,
- boolean voiceInteraction, int topClosingLayer) {
+ boolean voiceInteraction) {
AppWindowToken topOpeningApp = null;
+ int topOpeningLayer = Integer.MIN_VALUE;
final int appsCount = mService.mOpeningApps.size();
for (int i = 0; i < appsCount; i++) {
AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
@@ -422,7 +420,6 @@
}
mService.mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
- int topOpeningLayer = 0;
if (animLp != null) {
final int layer = wtoken.getHighestAnimLayer();
if (topOpeningApp == null || layer > topOpeningLayer) {
@@ -431,7 +428,7 @@
}
}
if (mService.mAppTransition.isNextAppTransitionThumbnailUp()) {
- createThumbnailAppAnimator(transit, wtoken, topOpeningLayer, topClosingLayer);
+ createThumbnailAppAnimator(transit, wtoken);
}
}
return topOpeningApp;
@@ -473,7 +470,7 @@
}
}
if (mService.mAppTransition.isNextAppTransitionThumbnailDown()) {
- createThumbnailAppAnimator(transit, wtoken, 0, layerAndToken.layer);
+ createThumbnailAppAnimator(transit, wtoken);
}
}
}
@@ -666,8 +663,7 @@
}
}
- private void createThumbnailAppAnimator(int transit, AppWindowToken appToken,
- int openingLayer, int closingLayer) {
+ private void createThumbnailAppAnimator(int transit, AppWindowToken appToken) {
AppWindowAnimator openingAppAnimator = (appToken == null) ? null : appToken.mAppAnimator;
if (openingAppAnimator == null || openingAppAnimator.animation == null) {
return;
@@ -724,7 +720,6 @@
anim = mService.mAppTransition.createThumbnailAspectScaleAnimationLocked(appRect,
insets, thumbnailHeader, taskId, displayConfig.uiMode,
displayConfig.orientation);
- openingAppAnimator.thumbnailForceAboveLayer = Math.max(openingLayer, closingLayer);
openingAppAnimator.deferThumbnailDestruction =
!mService.mAppTransition.isNextThumbnailTransitionScaleUp();
} else {
@@ -734,8 +729,8 @@
anim.restrictDuration(MAX_ANIMATION_DURATION);
anim.scaleCurrentDuration(mService.getTransitionAnimationScaleLocked());
+ openingAppAnimator.updateThumbnailLayer();
openingAppAnimator.thumbnail = surfaceControl;
- openingAppAnimator.thumbnailLayer = openingLayer;
openingAppAnimator.thumbnailAnimation = anim;
mService.mAppTransition.getNextAppTransitionStartRect(taskId, mTmpStartRect);
} catch (Surface.OutOfResourcesException e) {
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 9655637..36e9e7f 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -92,6 +92,7 @@
android.hardware.audio.common@2.0 \
android.hardware.broadcastradio@1.0 \
android.hardware.broadcastradio@1.1 \
+ android.hardware.broadcastradio@1.2 \
android.hardware.contexthub@1.0 \
android.hardware.gnss@1.0 \
android.hardware.ir@1.0 \
@@ -109,5 +110,5 @@
android.frameworks.sensorservice@1.0 \
LOCAL_STATIC_LIBRARIES += \
- android.hardware.broadcastradio@1.1-utils-lib \
+ android.hardware.broadcastradio@common-utils-lib \
libscrypt_static \
diff --git a/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp b/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
index b3817db..e1dbdeb 100644
--- a/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
+++ b/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
@@ -23,8 +23,9 @@
#include "convert.h"
#include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
-#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
+#include <android/hardware/broadcastradio/1.2/IBroadcastRadioFactory.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <broadcastradio-utils/Utils.h>
#include <core_jni_helpers.h>
#include <hidl/ServiceManagement.h>
#include <nativehelper/JNIHelp.h>
@@ -44,14 +45,16 @@
namespace V1_0 = hardware::broadcastradio::V1_0;
namespace V1_1 = hardware::broadcastradio::V1_1;
-
-using V1_0::Class;
-using V1_0::Result;
+namespace V1_2 = hardware::broadcastradio::V1_2;
+namespace utils = hardware::broadcastradio::utils;
using V1_0::BandConfig;
-using V1_0::ProgramInfo;
-using V1_0::MetaData;
+using V1_0::Class;
using V1_0::ITuner;
+using V1_0::MetaData;
+using V1_0::ProgramInfo;
+using V1_0::Result;
+using utils::HalRevision;
static mutex gContextMutex;
@@ -67,10 +70,15 @@
} Tuner;
} gjni;
+struct Module {
+ sp<V1_0::IBroadcastRadio> radioModule;
+ HalRevision halRev;
+};
+
struct ServiceContext {
ServiceContext() {}
- std::vector<sp<V1_0::IBroadcastRadio>> mModules;
+ std::vector<Module> mModules;
private:
DISALLOW_COPY_AND_ASSIGN(ServiceContext);
@@ -139,6 +147,17 @@
continue;
}
+ auto halRev = HalRevision::V1_0;
+ auto halMinor = 0;
+ if (V1_2::IBroadcastRadioFactory::castFrom(factory).withDefault(nullptr) != nullptr) {
+ halRev = HalRevision::V1_2;
+ halMinor = 2;
+ } else if (V1_1::IBroadcastRadioFactory::castFrom(factory).withDefault(nullptr)
+ != nullptr) {
+ halRev = HalRevision::V1_1;
+ halMinor = 1;
+ }
+
// Second level of scanning - that's unfortunate.
for (auto&& clazz : gAllClasses) {
sp<V1_0::IBroadcastRadio> module10 = nullptr;
@@ -155,9 +174,9 @@
if (module10 == nullptr) continue;
auto idx = ctx.mModules.size();
- ctx.mModules.push_back(module10);
- ALOGI("loaded broadcast radio module %zu: %s:%s",
- idx, serviceName.c_str(), V1_0::toString(clazz).c_str());
+ ctx.mModules.push_back({module10, halRev});
+ ALOGI("loaded broadcast radio module %zu: %s:%s (HAL 1.%d)",
+ idx, serviceName.c_str(), V1_0::toString(clazz).c_str(), halMinor);
JavaRef<jobject> jModule = nullptr;
Result halResult = Result::OK;
@@ -198,22 +217,15 @@
ALOGE("Invalid module ID: %d", moduleId);
return nullptr;
}
- auto module = ctx.mModules[moduleId];
- HalRevision halRev;
- if (V1_1::IBroadcastRadio::castFrom(module).withDefault(nullptr) != nullptr) {
- ALOGI("Opening tuner %d with broadcast radio HAL 1.1", moduleId);
- halRev = HalRevision::V1_1;
- } else {
- ALOGI("Opening tuner %d with broadcast radio HAL 1.0", moduleId);
- halRev = HalRevision::V1_0;
- }
+ ALOGI("Opening tuner %d", moduleId);
+ auto module = ctx.mModules[moduleId];
Region region;
BandConfig bandConfigHal = convert::BandConfigToHal(env, bandConfig, region);
auto tuner = make_javaref(env, env->NewObject(gjni.Tuner.clazz, gjni.Tuner.cstor,
- callback, halRev, region, withAudio, bandConfigHal.type));
+ callback, module.halRev, region, withAudio, bandConfigHal.type));
if (tuner == nullptr) {
ALOGE("Unable to create new tuner object.");
return nullptr;
@@ -223,7 +235,7 @@
Result halResult;
sp<ITuner> halTuner = nullptr;
- auto hidlResult = module->openTuner(bandConfigHal, withAudio, tunerCb,
+ auto hidlResult = module.radioModule->openTuner(bandConfigHal, withAudio, tunerCb,
[&](Result result, const sp<ITuner>& tuner) {
halResult = result;
halTuner = tuner;
@@ -235,7 +247,7 @@
return nullptr;
}
- Tuner::assignHalInterfaces(env, tuner, module, halTuner);
+ Tuner::assignHalInterfaces(env, tuner, module.radioModule, halTuner);
ALOGD("Opened tuner %p", halTuner.get());
return tuner.release();
}
diff --git a/services/core/jni/BroadcastRadio/Tuner.cpp b/services/core/jni/BroadcastRadio/Tuner.cpp
index e1ade4d..6403a5a 100644
--- a/services/core/jni/BroadcastRadio/Tuner.cpp
+++ b/services/core/jni/BroadcastRadio/Tuner.cpp
@@ -22,7 +22,7 @@
#include "convert.h"
#include "TunerCallback.h"
-#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
+#include <android/hardware/broadcastradio/1.2/IBroadcastRadioFactory.h>
#include <binder/IPCThreadState.h>
#include <broadcastradio-utils/Utils.h>
#include <core_jni_helpers.h>
@@ -44,13 +44,16 @@
namespace V1_0 = hardware::broadcastradio::V1_0;
namespace V1_1 = hardware::broadcastradio::V1_1;
+namespace V1_2 = hardware::broadcastradio::V1_2;
+namespace utils = hardware::broadcastradio::utils;
using V1_0::Band;
using V1_0::BandConfig;
using V1_0::MetaData;
using V1_0::Result;
-using V1_1::ITunerCallback;
+using V1_2::ITunerCallback;
using V1_1::ProgramListResult;
+using utils::HalRevision;
static mutex gContextMutex;
@@ -310,7 +313,7 @@
convert::ThrowIfFailed(env, halTuner11->tuneByProgramSelector(selector));
} else {
uint32_t channel, subChannel;
- if (!V1_1::utils::getLegacyChannel(selector, &channel, &subChannel)) {
+ if (!utils::getLegacyChannel(selector, &channel, &subChannel)) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"Can't tune to non-AM/FM channel with HAL<1.1");
return;
diff --git a/services/core/jni/BroadcastRadio/Tuner.h b/services/core/jni/BroadcastRadio/Tuner.h
index 818597b..48c3bc7 100644
--- a/services/core/jni/BroadcastRadio/Tuner.h
+++ b/services/core/jni/BroadcastRadio/Tuner.h
@@ -22,8 +22,8 @@
#include "JavaRef.h"
#include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
-#include <android/hardware/broadcastradio/1.1/ITuner.h>
-#include <android/hardware/broadcastradio/1.1/ITunerCallback.h>
+#include <android/hardware/broadcastradio/1.2/ITuner.h>
+#include <android/hardware/broadcastradio/1.2/ITunerCallback.h>
#include <jni.h>
#include <utils/StrongPointer.h>
@@ -39,7 +39,7 @@
sp<hardware::broadcastradio::V1_0::IBroadcastRadio> halModule,
sp<hardware::broadcastradio::V1_0::ITuner> halTuner);
-sp<hardware::broadcastradio::V1_1::ITunerCallback>
+sp<hardware::broadcastradio::V1_2::ITunerCallback>
getNativeCallback(JNIEnv *env, JavaRef<jobject> const &tuner);
Region getRegion(JNIEnv *env, jobject obj);
diff --git a/services/core/jni/BroadcastRadio/TunerCallback.cpp b/services/core/jni/BroadcastRadio/TunerCallback.cpp
index d53721f..ed7c9c4 100644
--- a/services/core/jni/BroadcastRadio/TunerCallback.cpp
+++ b/services/core/jni/BroadcastRadio/TunerCallback.cpp
@@ -40,15 +40,19 @@
namespace V1_0 = hardware::broadcastradio::V1_0;
namespace V1_1 = hardware::broadcastradio::V1_1;
+namespace V1_2 = hardware::broadcastradio::V1_2;
+namespace utils = hardware::broadcastradio::utils;
using V1_0::Band;
using V1_0::BandConfig;
using V1_0::MetaData;
using V1_0::Result;
-using V1_1::ITunerCallback;
using V1_1::ProgramInfo;
using V1_1::ProgramListResult;
using V1_1::ProgramSelector;
+using V1_1::VendorKeyValue;
+using V1_2::ITunerCallback;
+using utils::HalRevision;
static JavaVM *gvm = nullptr;
@@ -117,6 +121,7 @@
virtual Return<void> backgroundScanComplete(ProgramListResult result);
virtual Return<void> programListChanged();
virtual Return<void> currentProgramInfoChanged(const ProgramInfo& info);
+ virtual Return<void> parametersUpdated(const hidl_vec<VendorKeyValue>& parameters);
};
struct TunerCallbackContext {
@@ -203,7 +208,7 @@
return {};
}
- auto selector = V1_1::utils::make_selector(mBand, info.channel, info.subChannel);
+ auto selector = utils::make_selector(mBand, info.channel, info.subChannel);
return tuneComplete_1_1(result, selector);
}
@@ -338,6 +343,14 @@
return Return<void>();
}
+Return<void> NativeCallback::parametersUpdated(const hidl_vec<VendorKeyValue>& parameters) {
+ ALOGV("%s", __func__);
+
+ // TODO(b/65862441): pass this callback to the front-end
+
+ return {};
+}
+
static TunerCallbackContext& getNativeContext(jlong nativeContextHandle) {
auto nativeContext = reinterpret_cast<TunerCallbackContext*>(nativeContextHandle);
LOG_ALWAYS_FATAL_IF(nativeContext == nullptr, "Native context not initialized");
diff --git a/services/core/jni/BroadcastRadio/TunerCallback.h b/services/core/jni/BroadcastRadio/TunerCallback.h
index af12d21..7e776c2 100644
--- a/services/core/jni/BroadcastRadio/TunerCallback.h
+++ b/services/core/jni/BroadcastRadio/TunerCallback.h
@@ -21,7 +21,7 @@
#include "NativeCallbackThread.h"
#include "types.h"
-#include <android/hardware/broadcastradio/1.1/ITunerCallback.h>
+#include <android/hardware/broadcastradio/1.2/ITunerCallback.h>
#include <jni.h>
namespace android {
@@ -32,7 +32,7 @@
namespace BroadcastRadio {
namespace TunerCallback {
-sp<hardware::broadcastradio::V1_1::ITunerCallback>
+sp<hardware::broadcastradio::V1_2::ITunerCallback>
getNativeCallback(JNIEnv *env, jobject jTunerCallback);
} // namespace TunerCallback
diff --git a/services/core/jni/BroadcastRadio/convert.cpp b/services/core/jni/BroadcastRadio/convert.cpp
index ae278de..8dfa14f 100644
--- a/services/core/jni/BroadcastRadio/convert.cpp
+++ b/services/core/jni/BroadcastRadio/convert.cpp
@@ -31,7 +31,7 @@
namespace BroadcastRadio {
namespace convert {
-namespace utils = V1_1::utils;
+namespace utils = hardware::broadcastradio::utils;
using hardware::Return;
using hardware::hidl_vec;
diff --git a/services/core/jni/BroadcastRadio/regions.cpp b/services/core/jni/BroadcastRadio/regions.cpp
index b856419..b7fd0f3 100644
--- a/services/core/jni/BroadcastRadio/regions.cpp
+++ b/services/core/jni/BroadcastRadio/regions.cpp
@@ -27,7 +27,7 @@
namespace BroadcastRadio {
namespace regions {
-namespace utils = hardware::broadcastradio::V1_1::utils;
+namespace utils = hardware::broadcastradio::utils;
using hardware::hidl_vec;
diff --git a/services/core/jni/BroadcastRadio/types.h b/services/core/jni/BroadcastRadio/types.h
index f726af3..64a4f63 100644
--- a/services/core/jni/BroadcastRadio/types.h
+++ b/services/core/jni/BroadcastRadio/types.h
@@ -27,11 +27,6 @@
* frameworks/base/core/java/android/hardware/radio/RadioManager.java.
*/
-enum class HalRevision : jint {
- V1_0,
- V1_1,
-};
-
// Keep in sync with STATUS_* constants from RadioManager.java.
enum class Status : jint {
OK = 0,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7830623..c59f44e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -97,8 +97,8 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
diff --git a/services/net/java/android/net/util/NetworkConstants.java b/services/net/java/android/net/util/NetworkConstants.java
index 6065268..5a3a8be 100644
--- a/services/net/java/android/net/util/NetworkConstants.java
+++ b/services/net/java/android/net/util/NetworkConstants.java
@@ -107,6 +107,20 @@
public static final int RFC6177_MIN_PREFIX_LENGTH = 48;
/**
+ * ICMP common (v4/v6) constants.
+ *
+ * See also:
+ * - https://tools.ietf.org/html/rfc792
+ * - https://tools.ietf.org/html/rfc4443
+ */
+ public static final int ICMP_HEADER_TYPE_OFFSET = 0;
+ public static final int ICMP_HEADER_CODE_OFFSET = 1;
+ public static final int ICMP_HEADER_CHECKSUM_OFFSET = 2;
+ public static final int ICMP_ECHO_IDENTIFIER_OFFSET = 4;
+ public static final int ICMP_ECHO_SEQUENCE_NUMBER_OFFSET = 6;
+ public static final int ICMP_ECHO_DATA_OFFSET = 8;
+
+ /**
* ICMPv6 constants.
*
* See also:
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 2249ff0..df989f7 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -25,25 +25,13 @@
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.fail;
-import org.json.JSONArray;
-import org.json.JSONObject;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import com.android.internal.util.FastXmlSerializer;
-
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
-
import android.app.Notification;
-import android.app.NotificationChannelGroup;
-import android.content.Context;
import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
+import android.content.ContentProvider;
+import android.content.Context;
+import android.content.IContentProvider;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
@@ -52,14 +40,28 @@
import android.net.Uri;
import android.os.Build;
import android.os.UserHandle;
+import android.provider.Settings;
import android.provider.Settings.Secure;
import android.service.notification.StatusBarNotification;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.TestableContentResolver;
import android.util.ArrayMap;
import android.util.Xml;
+import com.android.internal.util.FastXmlSerializer;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
@@ -76,6 +78,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
@@ -95,10 +98,17 @@
private static final int UID2 = 1111;
private static final UserHandle USER2 = UserHandle.of(10);
private static final String TEST_CHANNEL_ID = "test_channel_id";
+ private static final String TEST_AUTHORITY = "test";
+ private static final Uri SOUND_URI =
+ Uri.parse("content://" + TEST_AUTHORITY + "/internal/audio/media/10");
+ private static final Uri CANONICAL_SOUND_URI =
+ Uri.parse("content://" + TEST_AUTHORITY
+ + "/internal/audio/media/10?title=Test&canonical=1");
@Mock NotificationUsageStats mUsageStats;
@Mock RankingHandler mHandler;
@Mock PackageManager mPm;
+ @Mock IContentProvider mTestIContentProvider;
@Mock Context mContext;
private Notification mNotiGroupGSortA;
@@ -134,9 +144,22 @@
when(mContext.getPackageManager()).thenReturn(mPm);
when(mContext.getApplicationInfo()).thenReturn(legacy);
// most tests assume badging is enabled
- Secure.putIntForUser(getContext().getContentResolver(),
+ TestableContentResolver contentResolver = getContext().getContentResolver();
+ contentResolver.setFallbackToExisting(false);
+ Secure.putIntForUser(contentResolver,
Secure.NOTIFICATION_BADGING, 1, UserHandle.getUserId(UID));
+ ContentProvider testContentProvider = mock(ContentProvider.class);
+ when(testContentProvider.getIContentProvider()).thenReturn(mTestIContentProvider);
+ contentResolver.addProvider(TEST_AUTHORITY, testContentProvider);
+
+ when(mTestIContentProvider.canonicalize(any(), eq(SOUND_URI)))
+ .thenReturn(CANONICAL_SOUND_URI);
+ when(mTestIContentProvider.canonicalize(any(), eq(CANONICAL_SOUND_URI)))
+ .thenReturn(CANONICAL_SOUND_URI);
+ when(mTestIContentProvider.uncanonicalize(any(), eq(CANONICAL_SOUND_URI)))
+ .thenReturn(SOUND_URI);
+
mHelper = new RankingHelper(getContext(), mPm, mHandler, mUsageStats,
new String[] {ImportanceExtractor.class.getName()});
@@ -214,9 +237,12 @@
}
private void loadStreamXml(ByteArrayOutputStream stream, boolean forRestore) throws Exception {
+ loadByteArrayXml(stream.toByteArray(), forRestore);
+ }
+
+ private void loadByteArrayXml(byte[] byteArray, boolean forRestore) throws Exception {
XmlPullParser parser = Xml.newPullParser();
- parser.setInput(new BufferedInputStream(new ByteArrayInputStream(stream.toByteArray())),
- null);
+ parser.setInput(new BufferedInputStream(new ByteArrayInputStream(byteArray)), null);
parser.nextTag();
mHelper.readXml(parser, forRestore);
}
@@ -377,7 +403,7 @@
NotificationChannel channel2 =
new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
channel2.setDescription("descriptions for all");
- channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
+ channel2.setSound(SOUND_URI, mAudioAttributes);
channel2.enableLights(true);
channel2.setBypassDnd(true);
channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
@@ -439,6 +465,109 @@
}
@Test
+ public void testBackupXml_backupCanonicalizedSoundUri() throws Exception {
+ NotificationChannel channel =
+ new NotificationChannel("id", "name", IMPORTANCE_LOW);
+ channel.setSound(SOUND_URI, mAudioAttributes);
+ mHelper.createNotificationChannel(PKG, UID, channel, true);
+
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId());
+
+ // Testing that in restore we are given the canonical version
+ loadStreamXml(baos, true);
+ verify(mTestIContentProvider).uncanonicalize(any(), eq(CANONICAL_SOUND_URI));
+ }
+
+ @Test
+ public void testRestoreXml_withExistentCanonicalizedSoundUri() throws Exception {
+ Uri localUri = Uri.parse("content://" + TEST_AUTHORITY + "/local/url");
+ Uri canonicalBasedOnLocal = localUri.buildUpon()
+ .appendQueryParameter("title", "Test")
+ .appendQueryParameter("canonical", "1")
+ .build();
+ when(mTestIContentProvider.canonicalize(any(), eq(CANONICAL_SOUND_URI)))
+ .thenReturn(canonicalBasedOnLocal);
+ when(mTestIContentProvider.uncanonicalize(any(), eq(CANONICAL_SOUND_URI)))
+ .thenReturn(localUri);
+ when(mTestIContentProvider.uncanonicalize(any(), eq(canonicalBasedOnLocal)))
+ .thenReturn(localUri);
+
+ NotificationChannel channel =
+ new NotificationChannel("id", "name", IMPORTANCE_LOW);
+ channel.setSound(SOUND_URI, mAudioAttributes);
+ mHelper.createNotificationChannel(PKG, UID, channel, true);
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId());
+
+ loadStreamXml(baos, true);
+
+ NotificationChannel actualChannel = mHelper.getNotificationChannel(
+ PKG, UID, channel.getId(), false);
+ assertEquals(localUri, actualChannel.getSound());
+ }
+
+ @Test
+ public void testRestoreXml_withNonExistentCanonicalizedSoundUri() throws Exception {
+ Thread.sleep(3000);
+ when(mTestIContentProvider.canonicalize(any(), eq(CANONICAL_SOUND_URI)))
+ .thenReturn(null);
+ when(mTestIContentProvider.uncanonicalize(any(), eq(CANONICAL_SOUND_URI)))
+ .thenReturn(null);
+
+ NotificationChannel channel =
+ new NotificationChannel("id", "name", IMPORTANCE_LOW);
+ channel.setSound(SOUND_URI, mAudioAttributes);
+ mHelper.createNotificationChannel(PKG, UID, channel, true);
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId());
+
+ loadStreamXml(baos, true);
+
+ NotificationChannel actualChannel = mHelper.getNotificationChannel(
+ PKG, UID, channel.getId(), false);
+ assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound());
+ }
+
+
+ /**
+ * Although we don't make backups with uncanonicalized uris anymore, we used to, so we have to
+ * handle its restore properly.
+ */
+ @Test
+ public void testRestoreXml_withUncanonicalizedNonLocalSoundUri() throws Exception {
+ // Not a local uncanonicalized uri, simulating that it fails to exist locally
+ when(mTestIContentProvider.canonicalize(any(), eq(SOUND_URI))).thenReturn(null);
+ String id = "id";
+ String backupWithUncanonicalizedSoundUri = "<ranking version=\"1\">\n"
+ + "<package name=\"com.android.server.notification\" show_badge=\"true\">\n"
+ + "<channel id=\"" + id + "\" name=\"name\" importance=\"2\" "
+ + "sound=\"" + SOUND_URI + "\" "
+ + "usage=\"6\" content_type=\"0\" flags=\"1\" show_badge=\"true\" />\n"
+ + "<channel id=\"miscellaneous\" name=\"Uncategorized\" usage=\"5\" "
+ + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n"
+ + "</package>\n"
+ + "</ranking>\n";
+
+ loadByteArrayXml(backupWithUncanonicalizedSoundUri.getBytes(), true);
+
+ NotificationChannel actualChannel = mHelper.getNotificationChannel(PKG, UID, id, false);
+ assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound());
+ }
+
+ @Test
+ public void testBackupRestoreXml_withNullSoundUri() throws Exception {
+ NotificationChannel channel =
+ new NotificationChannel("id", "name", IMPORTANCE_LOW);
+ channel.setSound(null, mAudioAttributes);
+ mHelper.createNotificationChannel(PKG, UID, channel, true);
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId());
+
+ loadStreamXml(baos, true);
+
+ NotificationChannel actualChannel = mHelper.getNotificationChannel(
+ PKG, UID, channel.getId(), false);
+ assertEquals(null, actualChannel.getSound());
+ }
+
+ @Test
public void testChannelXml_backup() throws Exception {
NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
new file mode 100644
index 0000000..855b82c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.am;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+import static com.android.server.am.ActivityManagerService.ANIMATE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.times;
+
+/**
+ * Tests for the {@link ActivityStack} class.
+ *
+ * Build/Install/Run:
+ * bit FrameworksServicesTests:com.android.server.am.ActivityStarterTests
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ActivityStarterTests extends ActivityTestsBase {
+ private static final ComponentName testActivityComponent =
+ ComponentName.unflattenFromString("com.foo/.BarActivity");
+
+ private ActivityManagerService mService;
+ private ActivityStarter mStarter;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mService = createActivityManagerService();
+ mStarter = new ActivityStarter(mService, mService.mStackSupervisor);
+ }
+
+ @Test
+ public void testUpdateLaunchBounds() throws Exception {
+ // When in a non-resizeable stack, the task bounds should be updated.
+ final TaskRecord task = createTask(mService.mStackSupervisor, testActivityComponent,
+ mService.mStackSupervisor.getDefaultDisplay().createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */));
+ final Rect bounds = new Rect(10, 10, 100, 100);
+
+ mStarter.updateBounds(task, bounds);
+ assertEquals(task.mBounds, bounds);
+ assertEquals(task.getStack().mBounds, null);
+
+ // When in a resizeable stack, the stack bounds should be updated as well.
+ final TaskRecord task2 = createTask(mService.mStackSupervisor, testActivityComponent,
+ mService.mStackSupervisor.getDefaultDisplay().createStack(
+ WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */));
+ assertTrue(task2.getStack() instanceof PinnedActivityStack);
+ mStarter.updateBounds(task2, bounds);
+
+ verify(mService, times(1)).resizeStack(eq(ActivityManager.StackId.PINNED_STACK_ID),
+ eq(bounds), anyBoolean(), anyBoolean(), anyBoolean(), anyInt());
+
+ // In the case of no animation, the stack and task bounds should be set immediately.
+ if (!ANIMATE) {
+ assertEquals(task2.getStack().mBounds, bounds);
+ assertEquals(task2.mBounds, bounds);
+ } else {
+ assertEquals(task2.mBounds, null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index b4bfa62..1f6dda1 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -22,6 +22,7 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.spy;
import org.mockito.invocation.InvocationOnMock;
@@ -38,8 +39,8 @@
import android.support.test.InstrumentationRegistry;
import com.android.server.AttributeCache;
import com.android.server.wm.AppWindowContainerController;
+import com.android.server.wm.PinnedStackWindowController;
import com.android.server.wm.StackWindowController;
-
import com.android.server.wm.TaskWindowContainerController;
import com.android.server.wm.WindowManagerService;
import com.android.server.wm.WindowTestUtils;
@@ -71,8 +72,8 @@
}
protected ActivityManagerService createActivityManagerService() {
- final ActivityManagerService service = new TestActivityManagerService(mContext);
- service.mWindowManager = WindowTestUtils.getMockWindowManagerService();
+ final ActivityManagerService service = spy(new TestActivityManagerService(mContext));
+ service.mWindowManager = prepareMockWindowManager();
return service;
}
@@ -237,6 +238,12 @@
Rect getDefaultPictureInPictureBounds(float aspectRatio) {
return new Rect(50, 50, 100, 100);
}
+
+ @Override
+ PinnedStackWindowController createStackWindowController(int displayId,
+ boolean onTop, Rect outBounds) {
+ return mock(PinnedStackWindowController.class);
+ }
};
} else {
return (T) new TestActivityStack(
@@ -246,7 +253,7 @@
}
private static WindowManagerService prepareMockWindowManager() {
- final WindowManagerService service = mock(WindowManagerService.class);
+ final WindowManagerService service = WindowTestUtils.getMockWindowManagerService();
doAnswer((InvocationOnMock invocationOnMock) -> {
final Runnable runnable = invocationOnMock.<Runnable>getArgument(0);
@@ -264,7 +271,7 @@
}
/**
- * Override of {@link ActivityStack} that tracks test metrics, such as the number of times a
+ * Overrided of {@link ActivityStack} that tracks test metrics, such as the number of times a
* method is called. Note that its functionality depends on the implementations of the
* construction arguments.
*/
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 3cd24b8..fd105bc 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -34,6 +34,7 @@
import static org.junit.Assert.fail;
import android.annotation.NonNull;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageParser;
import android.content.pm.PackageUserState;
@@ -51,6 +52,9 @@
import com.android.internal.os.AtomicFile;
import com.android.server.LocalServices;
+import com.android.server.pm.permission.PermissionManagerInternal;
+import com.android.server.pm.permission.PermissionManagerService;
+import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback;
import org.junit.Before;
import org.junit.Test;
@@ -79,8 +83,11 @@
throws ReflectiveOperationException, IllegalAccessException {
/* write out files and read */
writeOldFiles();
+ final Context context = InstrumentationRegistry.getContext();
+ final Object lock = new Object();
+ PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
Settings settings =
- new Settings(InstrumentationRegistry.getContext().getFilesDir(), new Object());
+ new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
verifyKeySetMetaData(settings);
}
@@ -91,8 +98,11 @@
throws ReflectiveOperationException, IllegalAccessException {
// write out files and read
writeOldFiles();
+ final Context context = InstrumentationRegistry.getContext();
+ final Object lock = new Object();
+ PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
Settings settings =
- new Settings(InstrumentationRegistry.getContext().getFilesDir(), new Object());
+ new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
// write out, read back in and verify the same
@@ -105,8 +115,11 @@
public void testSettingsReadOld() {
// Write the package files and make sure they're parsed properly the first time
writeOldFiles();
+ final Context context = InstrumentationRegistry.getContext();
+ final Object lock = new Object();
+ PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
Settings settings =
- new Settings(InstrumentationRegistry.getContext().getFilesDir(), new Object());
+ new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
assertThat(settings.getPackageLPr(PACKAGE_NAME_3), is(notNullValue()));
assertThat(settings.getPackageLPr(PACKAGE_NAME_1), is(notNullValue()));
@@ -125,13 +138,17 @@
public void testNewPackageRestrictionsFile() throws ReflectiveOperationException {
// Write the package files and make sure they're parsed properly the first time
writeOldFiles();
+ final Context context = InstrumentationRegistry.getContext();
+ final Object lock = new Object();
+ PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
Settings settings =
- new Settings(InstrumentationRegistry.getContext().getFilesDir(), new Object());
+ new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
settings.writeLPr();
// Create Settings again to make it read from the new files
- settings = new Settings(InstrumentationRegistry.getContext().getFilesDir(), new Object());
+ settings =
+ new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
PackageSetting ps = settings.getPackageLPr(PACKAGE_NAME_2);
@@ -143,8 +160,11 @@
public void testEnableDisable() {
// Write the package files and make sure they're parsed properly the first time
writeOldFiles();
+ final Context context = InstrumentationRegistry.getContext();
+ final Object lock = new Object();
+ PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
Settings settings =
- new Settings(InstrumentationRegistry.getContext().getFilesDir(), new Object());
+ new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
// Enable/Disable a package
@@ -334,7 +354,11 @@
/** Update package; changing shared user throws exception */
@Test
public void testUpdatePackageSetting03() {
- final Settings testSettings01 = new Settings(new Object() /*lock*/);
+ final Context context = InstrumentationRegistry.getContext();
+ final Object lock = new Object();
+ PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+ final Settings testSettings01 =
+ new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
final SharedUserSetting testUserSetting01 = createSharedUserSetting(
testSettings01, "TestUser", 10064, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/);
final PackageSetting testPkgSetting01 =
@@ -449,7 +473,11 @@
/** Create PackageSetting for a shared user */
@Test
public void testCreateNewSetting03() {
- final Settings testSettings01 = new Settings(new Object() /*lock*/);
+ final Context context = InstrumentationRegistry.getContext();
+ final Object lock = new Object();
+ PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+ final Settings testSettings01 =
+ new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
final SharedUserSetting testUserSetting01 = createSharedUserSetting(
testSettings01, "TestUser", 10064, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/);
final PackageSetting testPkgSetting01 = Settings.createNewSetting(
@@ -542,8 +570,11 @@
final PackageParser.Package pkg = new PackageParser.Package(PACKAGE_NAME);
pkg.applicationInfo.setCodePath(ps.codePathString);
pkg.applicationInfo.setResourcePath(ps.resourcePathString);
+ final Context context = InstrumentationRegistry.getContext();
+ final Object lock = new Object();
+ PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
final Settings settings =
- new Settings(InstrumentationRegistry.getContext().getFilesDir(), new Object());
+ new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
pkg.usesStaticLibraries = new ArrayList<>(
Arrays.asList("foo.bar1", "foo.bar2", "foo.bar3"));
pkg.usesStaticLibrariesVersions = new int[] {2, 4, 6};
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
new file mode 100644
index 0000000..b2446ba
--- /dev/null
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -0,0 +1,987 @@
+/**
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.android.server.usage;
+
+import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
+import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
+import static com.android.server.usage.UsageStatsService.MSG_REPORT_EVENT;
+
+import android.app.ActivityManager;
+import android.app.AppGlobals;
+import android.app.admin.DevicePolicyManager;
+import android.app.usage.UsageEvents;
+import android.app.usage.UsageStatsManagerInternal;
+import android.appwidget.AppWidgetManager;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ParceledListSlice;
+import android.database.ContentObserver;
+import android.hardware.display.DisplayManager;
+import android.net.NetworkScoreManager;
+import android.os.BatteryManager;
+import android.os.BatteryStats;
+import android.os.Handler;
+import android.os.IDeviceIdleController;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+import android.util.KeyValueListParser;
+import android.util.Slog;
+import android.util.SparseIntArray;
+import android.util.TimeUtils;
+import android.view.Display;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.os.SomeArgs;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.LocalServices;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Manages the standby state of an app, listening to various events.
+ */
+public class AppStandbyController {
+
+ private static final String TAG = "AppStandbyController";
+ private static final boolean DEBUG = false;
+
+ static final boolean COMPRESS_TIME = false;
+ private static final long ONE_MINUTE = 60 * 1000;
+
+ // To name the lock for stack traces
+ static class Lock {}
+
+ /** Lock to protect the app's standby state. Required for calls into AppIdleHistory */
+ private final Object mAppIdleLock = new Lock();
+
+ /** Keeps the history and state for each app. */
+ @GuardedBy("mAppIdleLock")
+ private AppIdleHistory mAppIdleHistory;
+
+ @GuardedBy("mAppIdleLock")
+ private ArrayList<UsageStatsManagerInternal.AppIdleStateChangeListener>
+ mPackageAccessListeners = new ArrayList<>();
+
+ /** Whether we've queried the list of carrier privileged apps. */
+ @GuardedBy("mAppIdleLock")
+ private boolean mHaveCarrierPrivilegedApps;
+
+ /** List of carrier-privileged apps that should be excluded from standby */
+ @GuardedBy("mAppIdleLock")
+ private List<String> mCarrierPrivilegedApps;
+
+ // Messages for the handler
+ static final int MSG_INFORM_LISTENERS = 3;
+ static final int MSG_FORCE_IDLE_STATE = 4;
+ static final int MSG_CHECK_IDLE_STATES = 5;
+ static final int MSG_CHECK_PAROLE_TIMEOUT = 6;
+ static final int MSG_PAROLE_END_TIMEOUT = 7;
+ static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
+ static final int MSG_PAROLE_STATE_CHANGED = 9;
+ static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
+
+ long mAppIdleScreenThresholdMillis;
+ long mCheckIdleIntervalMillis;
+ long mAppIdleWallclockThresholdMillis;
+ long mAppIdleParoleIntervalMillis;
+ long mAppIdleParoleDurationMillis;
+ boolean mAppIdleEnabled;
+ boolean mAppIdleTempParoled;
+ boolean mCharging;
+ private long mLastAppIdleParoledTime;
+ private boolean mSystemServicesReady = false;
+
+ private volatile boolean mPendingOneTimeCheckIdleStates;
+
+ private final Handler mHandler;
+ private final Context mContext;
+
+ private DisplayManager mDisplayManager;
+ private IDeviceIdleController mDeviceIdleController;
+ private AppWidgetManager mAppWidgetManager;
+ private IBatteryStats mBatteryStats;
+ private PowerManager mPowerManager;
+ private PackageManager mPackageManager;
+ private PackageManagerInternal mPackageManagerInternal;
+
+ AppStandbyController(Context context, Looper looper) {
+ mContext = context;
+ mHandler = new AppStandbyHandler(looper);
+ mPackageManager = mContext.getPackageManager();
+ mAppIdleEnabled = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_enableAutoPowerModes);
+ if (mAppIdleEnabled) {
+ IntentFilter deviceStates = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+ deviceStates.addAction(BatteryManager.ACTION_DISCHARGING);
+ deviceStates.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
+ mContext.registerReceiver(new DeviceStateReceiver(), deviceStates);
+ }
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory = new AppIdleHistory(SystemClock.elapsedRealtime());
+ }
+
+ IntentFilter packageFilter = new IntentFilter();
+ packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ packageFilter.addDataScheme("package");
+
+ mContext.registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL, packageFilter,
+ null, mHandler);
+ }
+
+ public void onBootPhase(int phase) {
+ if (phase == PHASE_SYSTEM_SERVICES_READY) {
+ // Observe changes to the threshold
+ SettingsObserver settingsObserver = new SettingsObserver(mHandler);
+ settingsObserver.registerObserver();
+ settingsObserver.updateSettings();
+
+ mAppWidgetManager = mContext.getSystemService(AppWidgetManager.class);
+ mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
+ ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
+ mBatteryStats = IBatteryStats.Stub.asInterface(
+ ServiceManager.getService(BatteryStats.SERVICE_NAME));
+ mDisplayManager = (DisplayManager) mContext.getSystemService(
+ Context.DISPLAY_SERVICE);
+ mPowerManager = mContext.getSystemService(PowerManager.class);
+ mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+
+ mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.updateDisplay(isDisplayOn(), SystemClock.elapsedRealtime());
+ }
+
+ if (mPendingOneTimeCheckIdleStates) {
+ postOneTimeCheckIdleStates();
+ }
+
+ mSystemServicesReady = true;
+ } else if (phase == PHASE_BOOT_COMPLETED) {
+ setChargingState(mContext.getSystemService(BatteryManager.class).isCharging());
+ }
+ }
+
+ void reportContentProviderUsage(String authority, String providerPkgName, int userId) {
+ // Get sync adapters for the authority
+ String[] packages = ContentResolver.getSyncAdapterPackagesForAuthorityAsUser(
+ authority, userId);
+ for (String packageName: packages) {
+ // Only force the sync adapters to active if the provider is not in the same package and
+ // the sync adapter is a system package.
+ try {
+ PackageInfo pi = mPackageManager.getPackageInfoAsUser(
+ packageName, PackageManager.MATCH_SYSTEM_ONLY, userId);
+ if (pi == null || pi.applicationInfo == null) {
+ continue;
+ }
+ if (!packageName.equals(providerPkgName)) {
+ setAppIdleAsync(packageName, false, userId);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // Shouldn't happen
+ }
+ }
+ }
+
+ void setChargingState(boolean charging) {
+ synchronized (mAppIdleLock) {
+ if (mCharging != charging) {
+ mCharging = charging;
+ postParoleStateChanged();
+ }
+ }
+ }
+
+ /** Paroled here means temporary pardon from being inactive */
+ void setAppIdleParoled(boolean paroled) {
+ synchronized (mAppIdleLock) {
+ final long now = System.currentTimeMillis();
+ if (mAppIdleTempParoled != paroled) {
+ mAppIdleTempParoled = paroled;
+ if (DEBUG) Slog.d(TAG, "Changing paroled to " + mAppIdleTempParoled);
+ if (paroled) {
+ postParoleEndTimeout();
+ } else {
+ mLastAppIdleParoledTime = now;
+ postNextParoleTimeout(now);
+ }
+ postParoleStateChanged();
+ }
+ }
+ }
+
+ boolean isParoledOrCharging() {
+ synchronized (mAppIdleLock) {
+ return mAppIdleTempParoled || mCharging;
+ }
+ }
+
+ private void postNextParoleTimeout(long now) {
+ if (DEBUG) Slog.d(TAG, "Posting MSG_CHECK_PAROLE_TIMEOUT");
+ mHandler.removeMessages(MSG_CHECK_PAROLE_TIMEOUT);
+ // Compute when the next parole needs to happen. We check more frequently than necessary
+ // since the message handler delays are based on elapsedRealTime and not wallclock time.
+ // The comparison is done in wallclock time.
+ long timeLeft = (mLastAppIdleParoledTime + mAppIdleParoleIntervalMillis) - now;
+ if (timeLeft < 0) {
+ timeLeft = 0;
+ }
+ mHandler.sendEmptyMessageDelayed(MSG_CHECK_PAROLE_TIMEOUT, timeLeft);
+ }
+
+ private void postParoleEndTimeout() {
+ if (DEBUG) Slog.d(TAG, "Posting MSG_PAROLE_END_TIMEOUT");
+ mHandler.removeMessages(MSG_PAROLE_END_TIMEOUT);
+ mHandler.sendEmptyMessageDelayed(MSG_PAROLE_END_TIMEOUT, mAppIdleParoleDurationMillis);
+ }
+
+ private void postParoleStateChanged() {
+ if (DEBUG) Slog.d(TAG, "Posting MSG_PAROLE_STATE_CHANGED");
+ mHandler.removeMessages(MSG_PAROLE_STATE_CHANGED);
+ mHandler.sendEmptyMessage(MSG_PAROLE_STATE_CHANGED);
+ }
+
+ void postCheckIdleStates(int userId) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
+ }
+
+ /**
+ * We send a different message to check idle states once, otherwise we would end up
+ * scheduling a series of repeating checkIdleStates each time we fired off one.
+ */
+ void postOneTimeCheckIdleStates() {
+ if (mDeviceIdleController == null) {
+ // Not booted yet; wait for it!
+ mPendingOneTimeCheckIdleStates = true;
+ } else {
+ mHandler.sendEmptyMessage(MSG_ONE_TIME_CHECK_IDLE_STATES);
+ mPendingOneTimeCheckIdleStates = false;
+ }
+ }
+
+ /**
+ * Check all running users' or specified user's apps to see if they enter an idle state.
+ * @return Returns whether checking should continue periodically.
+ */
+ boolean checkIdleStates(int checkUserId) {
+ if (!mAppIdleEnabled) {
+ return false;
+ }
+
+ final int[] runningUserIds;
+ try {
+ runningUserIds = ActivityManager.getService().getRunningUserIds();
+ if (checkUserId != UserHandle.USER_ALL
+ && !ArrayUtils.contains(runningUserIds, checkUserId)) {
+ return false;
+ }
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ for (int i = 0; i < runningUserIds.length; i++) {
+ final int userId = runningUserIds[i];
+ if (checkUserId != UserHandle.USER_ALL && checkUserId != userId) {
+ continue;
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "Checking idle state for user " + userId);
+ }
+ List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
+ PackageManager.MATCH_DISABLED_COMPONENTS,
+ userId);
+ final int packageCount = packages.size();
+ for (int p = 0; p < packageCount; p++) {
+ final PackageInfo pi = packages.get(p);
+ final String packageName = pi.packageName;
+ final boolean isIdle = isAppIdleFiltered(packageName,
+ UserHandle.getAppId(pi.applicationInfo.uid),
+ userId, elapsedRealtime);
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
+ userId, isIdle ? 1 : 0, packageName));
+ if (isIdle) {
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.setIdle(packageName, userId, elapsedRealtime);
+ }
+ }
+ }
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "checkIdleStates took "
+ + (SystemClock.elapsedRealtime() - elapsedRealtime));
+ }
+ return true;
+ }
+
+ /** Check if it's been a while since last parole and let idle apps do some work */
+ void checkParoleTimeout() {
+ boolean setParoled = false;
+ synchronized (mAppIdleLock) {
+ final long now = System.currentTimeMillis();
+ if (!mAppIdleTempParoled) {
+ final long timeSinceLastParole = now - mLastAppIdleParoledTime;
+ if (timeSinceLastParole > mAppIdleParoleIntervalMillis) {
+ if (DEBUG) Slog.d(TAG, "Crossed default parole interval");
+ setParoled = true;
+ } else {
+ if (DEBUG) Slog.d(TAG, "Not long enough to go to parole");
+ postNextParoleTimeout(now);
+ }
+ }
+ }
+ if (setParoled) {
+ setAppIdleParoled(true);
+ }
+ }
+
+ private void notifyBatteryStats(String packageName, int userId, boolean idle) {
+ try {
+ final int uid = mPackageManager.getPackageUidAsUser(packageName,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
+ if (idle) {
+ mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE,
+ packageName, uid);
+ } else {
+ mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_ACTIVE,
+ packageName, uid);
+ }
+ } catch (PackageManager.NameNotFoundException | RemoteException e) {
+ }
+ }
+
+ void onDeviceIdleModeChanged() {
+ final boolean deviceIdle = mPowerManager.isDeviceIdleMode();
+ if (DEBUG) Slog.i(TAG, "DeviceIdleMode changed to " + deviceIdle);
+ boolean paroled = false;
+ synchronized (mAppIdleLock) {
+ final long timeSinceLastParole = System.currentTimeMillis() - mLastAppIdleParoledTime;
+ if (!deviceIdle
+ && timeSinceLastParole >= mAppIdleParoleIntervalMillis) {
+ if (DEBUG) {
+ Slog.i(TAG, "Bringing idle apps out of inactive state due to deviceIdleMode=false");
+ }
+ paroled = true;
+ } else if (deviceIdle) {
+ if (DEBUG) Slog.i(TAG, "Device idle, back to prison");
+ paroled = false;
+ } else {
+ return;
+ }
+ }
+ setAppIdleParoled(paroled);
+ }
+
+ void reportEvent(UsageEvents.Event event, long elapsedRealtime, int userId) {
+ synchronized (mAppIdleLock) {
+ // TODO: Ideally this should call isAppIdleFiltered() to avoid calling back
+ // about apps that are on some kind of whitelist anyway.
+ final boolean previouslyIdle = mAppIdleHistory.isIdle(
+ event.mPackage, userId, elapsedRealtime);
+ // Inform listeners if necessary
+ if ((event.mEventType == UsageEvents.Event.MOVE_TO_FOREGROUND
+ || event.mEventType == UsageEvents.Event.MOVE_TO_BACKGROUND
+ || event.mEventType == UsageEvents.Event.SYSTEM_INTERACTION
+ || event.mEventType == UsageEvents.Event.USER_INTERACTION)) {
+ mAppIdleHistory.reportUsage(event.mPackage, userId, elapsedRealtime);
+ if (previouslyIdle) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
+ /* idle = */ 0, event.mPackage));
+ notifyBatteryStats(event.mPackage, userId, false);
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Forces the app's beginIdleTime and lastUsedTime to reflect idle or active. If idle,
+ * then it rolls back the beginIdleTime and lastUsedTime to a point in time that's behind
+ * the threshold for idle.
+ *
+ * This method is always called from the handler thread, so not much synchronization is
+ * required.
+ */
+ void forceIdleState(String packageName, int userId, boolean idle) {
+ final int appId = getAppId(packageName);
+ if (appId < 0) return;
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+
+ final boolean previouslyIdle = isAppIdleFiltered(packageName, appId,
+ userId, elapsedRealtime);
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.setIdle(packageName, userId, idle, elapsedRealtime);
+ }
+ final boolean stillIdle = isAppIdleFiltered(packageName, appId,
+ userId, elapsedRealtime);
+ // Inform listeners if necessary
+ if (previouslyIdle != stillIdle) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
+ /* idle = */ stillIdle ? 1 : 0, packageName));
+ if (!stillIdle) {
+ notifyBatteryStats(packageName, userId, idle);
+ }
+ }
+ }
+
+ public void onUserRemoved(int userId) {
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.onUserRemoved(userId);
+ }
+ }
+
+ private boolean isAppIdleUnfiltered(String packageName, int userId, long elapsedRealtime) {
+ synchronized (mAppIdleLock) {
+ return mAppIdleHistory.isIdle(packageName, userId, elapsedRealtime);
+ }
+ }
+
+ void addListener(UsageStatsManagerInternal.AppIdleStateChangeListener listener) {
+ synchronized (mAppIdleLock) {
+ if (!mPackageAccessListeners.contains(listener)) {
+ mPackageAccessListeners.add(listener);
+ }
+ }
+ }
+
+ void removeListener(UsageStatsManagerInternal.AppIdleStateChangeListener listener) {
+ synchronized (mAppIdleLock) {
+ mPackageAccessListeners.remove(listener);
+ }
+ }
+
+ int getAppId(String packageName) {
+ try {
+ ApplicationInfo ai = mPackageManager.getApplicationInfo(packageName,
+ PackageManager.MATCH_ANY_USER
+ | PackageManager.MATCH_DISABLED_COMPONENTS);
+ return ai.uid;
+ } catch (PackageManager.NameNotFoundException re) {
+ return -1;
+ }
+ }
+
+ boolean isAppIdleFilteredOrParoled(String packageName, int userId, long elapsedRealtime,
+ boolean shouldObfuscateInstantApps) {
+ if (isParoledOrCharging()) {
+ return false;
+ }
+ if (shouldObfuscateInstantApps &&
+ mPackageManagerInternal.isPackageEphemeral(userId, packageName)) {
+ return false;
+ }
+ return isAppIdleFiltered(packageName, getAppId(packageName), userId, elapsedRealtime);
+ }
+
+ /**
+ * Checks if an app has been idle for a while and filters out apps that are excluded.
+ * It returns false if the current system state allows all apps to be considered active.
+ * This happens if the device is plugged in or temporarily allowed to make exceptions.
+ * Called by interface impls.
+ */
+ boolean isAppIdleFiltered(String packageName, int appId, int userId,
+ long elapsedRealtime) {
+ if (packageName == null) return false;
+ // If not enabled at all, of course nobody is ever idle.
+ if (!mAppIdleEnabled) {
+ return false;
+ }
+ if (appId < Process.FIRST_APPLICATION_UID) {
+ // System uids never go idle.
+ return false;
+ }
+ if (packageName.equals("android")) {
+ // Nor does the framework (which should be redundant with the above, but for MR1 we will
+ // retain this for safety).
+ return false;
+ }
+ if (mSystemServicesReady) {
+ try {
+ // We allow all whitelisted apps, including those that don't want to be whitelisted
+ // for idle mode, because app idle (aka app standby) is really not as big an issue
+ // for controlling who participates vs. doze mode.
+ if (mDeviceIdleController.isPowerSaveWhitelistExceptIdleApp(packageName)) {
+ return false;
+ }
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+
+ if (isActiveDeviceAdmin(packageName, userId)) {
+ return false;
+ }
+
+ if (isActiveNetworkScorer(packageName)) {
+ return false;
+ }
+
+ if (mAppWidgetManager != null
+ && mAppWidgetManager.isBoundWidgetPackage(packageName, userId)) {
+ return false;
+ }
+
+ if (isDeviceProvisioningPackage(packageName)) {
+ return false;
+ }
+ }
+
+ if (!isAppIdleUnfiltered(packageName, userId, elapsedRealtime)) {
+ return false;
+ }
+
+ // Check this last, as it is the most expensive check
+ // TODO: Optimize this by fetching the carrier privileged apps ahead of time
+ if (isCarrierApp(packageName)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ int[] getIdleUidsForUser(int userId) {
+ if (!mAppIdleEnabled) {
+ return new int[0];
+ }
+
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+
+ List<ApplicationInfo> apps;
+ try {
+ ParceledListSlice<ApplicationInfo> slice = AppGlobals.getPackageManager()
+ .getInstalledApplications(/* flags= */ 0, userId);
+ if (slice == null) {
+ return new int[0];
+ }
+ apps = slice.getList();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ // State of each uid. Key is the uid. Value lower 16 bits is the number of apps
+ // associated with that uid, upper 16 bits is the number of those apps that is idle.
+ SparseIntArray uidStates = new SparseIntArray();
+
+ // Now resolve all app state. Iterating over all apps, keeping track of how many
+ // we find for each uid and how many of those are idle.
+ for (int i = apps.size() - 1; i >= 0; i--) {
+ ApplicationInfo ai = apps.get(i);
+
+ // Check whether this app is idle.
+ boolean idle = isAppIdleFiltered(ai.packageName, UserHandle.getAppId(ai.uid),
+ userId, elapsedRealtime);
+
+ int index = uidStates.indexOfKey(ai.uid);
+ if (index < 0) {
+ uidStates.put(ai.uid, 1 + (idle ? 1<<16 : 0));
+ } else {
+ int value = uidStates.valueAt(index);
+ uidStates.setValueAt(index, value + 1 + (idle ? 1<<16 : 0));
+ }
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "getIdleUids took " + (SystemClock.elapsedRealtime() - elapsedRealtime));
+ }
+ int numIdle = 0;
+ for (int i = uidStates.size() - 1; i >= 0; i--) {
+ int value = uidStates.valueAt(i);
+ if ((value&0x7fff) == (value>>16)) {
+ numIdle++;
+ }
+ }
+
+ int[] res = new int[numIdle];
+ numIdle = 0;
+ for (int i = uidStates.size() - 1; i >= 0; i--) {
+ int value = uidStates.valueAt(i);
+ if ((value&0x7fff) == (value>>16)) {
+ res[numIdle] = uidStates.keyAt(i);
+ numIdle++;
+ }
+ }
+
+ return res;
+ }
+
+ void setAppIdleAsync(String packageName, boolean idle, int userId) {
+ if (packageName == null) return;
+
+ mHandler.obtainMessage(MSG_FORCE_IDLE_STATE, userId, idle ? 1 : 0, packageName)
+ .sendToTarget();
+ }
+
+ private boolean isActiveDeviceAdmin(String packageName, int userId) {
+ DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
+ if (dpm == null) return false;
+ return dpm.packageHasActiveAdmins(packageName, userId);
+ }
+
+ /**
+ * Returns {@code true} if the supplied package is the device provisioning app. Otherwise,
+ * returns {@code false}.
+ */
+ private boolean isDeviceProvisioningPackage(String packageName) {
+ String deviceProvisioningPackage = mContext.getResources().getString(
+ com.android.internal.R.string.config_deviceProvisioningPackage);
+ return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName);
+ }
+
+ private boolean isCarrierApp(String packageName) {
+ synchronized (mAppIdleLock) {
+ if (!mHaveCarrierPrivilegedApps) {
+ fetchCarrierPrivilegedAppsLA();
+ }
+ if (mCarrierPrivilegedApps != null) {
+ return mCarrierPrivilegedApps.contains(packageName);
+ }
+ return false;
+ }
+ }
+
+ void clearCarrierPrivilegedApps() {
+ if (DEBUG) {
+ Slog.i(TAG, "Clearing carrier privileged apps list");
+ }
+ synchronized (mAppIdleLock) {
+ mHaveCarrierPrivilegedApps = false;
+ mCarrierPrivilegedApps = null; // Need to be refetched.
+ }
+ }
+
+ @GuardedBy("mAppIdleLock")
+ private void fetchCarrierPrivilegedAppsLA() {
+ TelephonyManager telephonyManager =
+ mContext.getSystemService(TelephonyManager.class);
+ mCarrierPrivilegedApps = telephonyManager.getPackagesWithCarrierPrivileges();
+ mHaveCarrierPrivilegedApps = true;
+ if (DEBUG) {
+ Slog.d(TAG, "apps with carrier privilege " + mCarrierPrivilegedApps);
+ }
+ }
+
+ private boolean isActiveNetworkScorer(String packageName) {
+ NetworkScoreManager nsm = (NetworkScoreManager) mContext.getSystemService(
+ Context.NETWORK_SCORE_SERVICE);
+ return packageName != null && packageName.equals(nsm.getActiveScorerPackage());
+ }
+
+ void informListeners(String packageName, int userId, boolean isIdle) {
+ for (UsageStatsManagerInternal.AppIdleStateChangeListener listener : mPackageAccessListeners) {
+ listener.onAppIdleStateChanged(packageName, userId, isIdle);
+ }
+ }
+
+ void informParoleStateChanged() {
+ final boolean paroled = isParoledOrCharging();
+ for (UsageStatsManagerInternal.AppIdleStateChangeListener listener : mPackageAccessListeners) {
+ listener.onParoleStateChanged(paroled);
+ }
+ }
+
+ void flushToDisk(int userId) {
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.writeAppIdleTimes(userId);
+ }
+ }
+
+ void flushDurationsToDisk() {
+ // Persist elapsed and screen on time. If this fails for whatever reason, the apps will be
+ // considered not-idle, which is the safest outcome in such an event.
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.writeAppIdleDurations();
+ }
+ }
+
+ boolean isDisplayOn() {
+ return mDisplayManager
+ .getDisplay(Display.DEFAULT_DISPLAY).getState() == Display.STATE_ON;
+ }
+
+ void clearAppIdleForPackage(String packageName, int userId) {
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.clearUsage(packageName, userId);
+ }
+ }
+
+ private class PackageReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (Intent.ACTION_PACKAGE_ADDED.equals(action)
+ || Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
+ clearCarrierPrivilegedApps();
+ }
+ if ((Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
+ Intent.ACTION_PACKAGE_ADDED.equals(action))
+ && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ clearAppIdleForPackage(intent.getData().getSchemeSpecificPart(),
+ getSendingUserId());
+ }
+ }
+ }
+
+ void initializeDefaultsForSystemApps(int userId) {
+ Slog.d(TAG, "Initializing defaults for system apps on user " + userId);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
+ PackageManager.MATCH_DISABLED_COMPONENTS,
+ userId);
+ final int packageCount = packages.size();
+ synchronized (mAppIdleLock) {
+ for (int i = 0; i < packageCount; i++) {
+ final PackageInfo pi = packages.get(i);
+ String packageName = pi.packageName;
+ if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) {
+ mAppIdleHistory.reportUsage(packageName, userId, elapsedRealtime);
+ }
+ }
+ }
+ }
+
+ void postReportContentProviderUsage(String name, String packageName, int userId) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = name;
+ args.arg2 = packageName;
+ args.arg3 = userId;
+ mHandler.obtainMessage(MSG_REPORT_CONTENT_PROVIDER_USAGE, args)
+ .sendToTarget();
+ }
+
+ void dumpHistory(IndentingPrintWriter idpw, int userId) {
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.dumpHistory(idpw, userId);
+ }
+ }
+
+ void dumpUser(IndentingPrintWriter idpw, int userId) {
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.dump(idpw, userId);
+ }
+ }
+
+ void dumpState(String[] args, PrintWriter pw) {
+ synchronized (mAppIdleLock) {
+ pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps
+ + "): " + mCarrierPrivilegedApps);
+ }
+
+ pw.println();
+ pw.println("Settings:");
+
+ pw.print(" mAppIdleDurationMillis=");
+ TimeUtils.formatDuration(mAppIdleScreenThresholdMillis, pw);
+ pw.println();
+
+ pw.print(" mAppIdleWallclockThresholdMillis=");
+ TimeUtils.formatDuration(mAppIdleWallclockThresholdMillis, pw);
+ pw.println();
+
+ pw.print(" mCheckIdleIntervalMillis=");
+ TimeUtils.formatDuration(mCheckIdleIntervalMillis, pw);
+ pw.println();
+
+ pw.print(" mAppIdleParoleIntervalMillis=");
+ TimeUtils.formatDuration(mAppIdleParoleIntervalMillis, pw);
+ pw.println();
+
+ pw.print(" mAppIdleParoleDurationMillis=");
+ TimeUtils.formatDuration(mAppIdleParoleDurationMillis, pw);
+ pw.println();
+
+ pw.println();
+ pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
+ pw.print(" mAppIdleTempParoled="); pw.print(mAppIdleTempParoled);
+ pw.print(" mCharging="); pw.print(mCharging);
+ pw.print(" mLastAppIdleParoledTime=");
+ TimeUtils.formatDuration(mLastAppIdleParoledTime, pw);
+ pw.println();
+ }
+
+ class AppStandbyHandler extends Handler {
+
+ AppStandbyHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_FORCE_IDLE_STATE:
+ forceIdleState((String) msg.obj, msg.arg1, msg.arg2 == 1);
+ break;
+
+ case MSG_CHECK_IDLE_STATES:
+ if (checkIdleStates(msg.arg1)) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(
+ MSG_CHECK_IDLE_STATES, msg.arg1, 0),
+ mCheckIdleIntervalMillis);
+ }
+ break;
+
+ case MSG_ONE_TIME_CHECK_IDLE_STATES:
+ mHandler.removeMessages(MSG_ONE_TIME_CHECK_IDLE_STATES);
+ checkIdleStates(UserHandle.USER_ALL);
+ break;
+
+ case MSG_CHECK_PAROLE_TIMEOUT:
+ checkParoleTimeout();
+ break;
+
+ case MSG_PAROLE_END_TIMEOUT:
+ if (DEBUG) Slog.d(TAG, "Ending parole");
+ setAppIdleParoled(false);
+ break;
+
+ case MSG_REPORT_CONTENT_PROVIDER_USAGE:
+ SomeArgs args = (SomeArgs) msg.obj;
+ reportContentProviderUsage((String) args.arg1, // authority name
+ (String) args.arg2, // package name
+ (int) args.arg3); // userId
+ args.recycle();
+ break;
+
+ case MSG_PAROLE_STATE_CHANGED:
+ if (DEBUG) Slog.d(TAG, "Parole state: " + mAppIdleTempParoled
+ + ", Charging state:" + mCharging);
+ informParoleStateChanged();
+ break;
+ default:
+ super.handleMessage(msg);
+ break;
+
+ }
+ }
+ };
+
+ private class DeviceStateReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
+ setChargingState(intent.getIntExtra("plugged", 0) != 0);
+ } else if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
+ onDeviceIdleModeChanged();
+ }
+ }
+ }
+
+ private final DisplayManager.DisplayListener mDisplayListener
+ = new DisplayManager.DisplayListener() {
+
+ @Override public void onDisplayAdded(int displayId) {
+ }
+
+ @Override public void onDisplayRemoved(int displayId) {
+ }
+
+ @Override public void onDisplayChanged(int displayId) {
+ if (displayId == Display.DEFAULT_DISPLAY) {
+ final boolean displayOn = isDisplayOn();
+ synchronized (mAppIdleLock) {
+ mAppIdleHistory.updateDisplay(displayOn, SystemClock.elapsedRealtime());
+ }
+ }
+ }
+ };
+
+ /**
+ * Observe settings changes for {@link Settings.Global#APP_IDLE_CONSTANTS}.
+ */
+ private class SettingsObserver extends ContentObserver {
+ /**
+ * This flag has been used to disable app idle on older builds with bug b/26355386.
+ */
+ @Deprecated
+ private static final String KEY_IDLE_DURATION_OLD = "idle_duration";
+
+ private static final String KEY_IDLE_DURATION = "idle_duration2";
+ private static final String KEY_WALLCLOCK_THRESHOLD = "wallclock_threshold";
+ private static final String KEY_PAROLE_INTERVAL = "parole_interval";
+ private static final String KEY_PAROLE_DURATION = "parole_duration";
+
+ private final KeyValueListParser mParser = new KeyValueListParser(',');
+
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ void registerObserver() {
+ mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.APP_IDLE_CONSTANTS), false, this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ updateSettings();
+ postOneTimeCheckIdleStates();
+ }
+
+ void updateSettings() {
+ synchronized (mAppIdleLock) {
+ // Look at global settings for this.
+ // TODO: Maybe apply different thresholds for different users.
+ try {
+ mParser.setString(Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.APP_IDLE_CONSTANTS));
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Bad value for app idle settings: " + e.getMessage());
+ // fallthrough, mParser is empty and all defaults will be returned.
+ }
+
+ // Default: 12 hours of screen-on time sans dream-time
+ mAppIdleScreenThresholdMillis = mParser.getLong(KEY_IDLE_DURATION,
+ COMPRESS_TIME ? ONE_MINUTE * 4 : 12 * 60 * ONE_MINUTE);
+
+ mAppIdleWallclockThresholdMillis = mParser.getLong(KEY_WALLCLOCK_THRESHOLD,
+ COMPRESS_TIME ? ONE_MINUTE * 8 : 2L * 24 * 60 * ONE_MINUTE); // 2 days
+
+ mCheckIdleIntervalMillis = Math.min(mAppIdleScreenThresholdMillis / 4,
+ COMPRESS_TIME ? ONE_MINUTE : 8 * 60 * ONE_MINUTE); // 8 hours
+
+ // Default: 24 hours between paroles
+ mAppIdleParoleIntervalMillis = mParser.getLong(KEY_PAROLE_INTERVAL,
+ COMPRESS_TIME ? ONE_MINUTE * 10 : 24 * 60 * ONE_MINUTE);
+
+ mAppIdleParoleDurationMillis = mParser.getLong(KEY_PAROLE_DURATION,
+ COMPRESS_TIME ? ONE_MINUTE : 10 * ONE_MINUTE); // 10 minutes
+ mAppIdleHistory.setThresholds(mAppIdleWallclockThresholdMillis,
+ mAppIdleScreenThresholdMillis);
+ }
+ }
+ }
+
+}
+
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 25e471c..afafea1 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -18,37 +18,24 @@
import android.Manifest;
import android.app.ActivityManager;
-import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.IUidObserver;
-import android.app.admin.DevicePolicyManager;
import android.app.usage.ConfigurationStats;
import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageEvents;
import android.app.usage.UsageEvents.Event;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManagerInternal;
-import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
-import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
-import android.database.ContentObserver;
-import android.hardware.display.DisplayManager;
-import android.net.NetworkScoreManager;
-import android.os.BatteryManager;
-import android.os.BatteryStats;
import android.os.Binder;
import android.os.Environment;
import android.os.FileUtils;
@@ -56,7 +43,6 @@
import android.os.IDeviceIdleController;
import android.os.Looper;
import android.os.Message;
-import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -64,21 +50,12 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
-import android.provider.Settings;
-import android.telephony.TelephonyManager;
import android.util.ArraySet;
-import android.util.KeyValueListParser;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
-import android.util.TimeUtils;
-import android.view.Display;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BackgroundThread;
-import com.android.internal.os.SomeArgs;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
@@ -88,7 +65,6 @@
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -107,7 +83,6 @@
static final boolean COMPRESS_TIME = false;
private static final long TEN_SECONDS = 10 * 1000;
- private static final long ONE_MINUTE = 60 * 1000;
private static final long TWENTY_MINUTES = 20 * 60 * 1000;
private static final long FLUSH_INTERVAL = COMPRESS_TIME ? TEN_SECONDS : TWENTY_MINUTES;
private static final long TIME_CHANGE_THRESHOLD_MILLIS = 2 * 1000; // Two seconds.
@@ -115,24 +90,10 @@
private static final boolean ENABLE_KERNEL_UPDATES = true;
private static final File KERNEL_COUNTER_FILE = new File("/proc/uid_procstat/set");
- long mAppIdleScreenThresholdMillis;
- long mCheckIdleIntervalMillis;
- long mAppIdleWallclockThresholdMillis;
- long mAppIdleParoleIntervalMillis;
- long mAppIdleParoleDurationMillis;
-
// Handler message types.
static final int MSG_REPORT_EVENT = 0;
static final int MSG_FLUSH_TO_DISK = 1;
static final int MSG_REMOVE_USER = 2;
- static final int MSG_INFORM_LISTENERS = 3;
- static final int MSG_FORCE_IDLE_STATE = 4;
- static final int MSG_CHECK_IDLE_STATES = 5;
- static final int MSG_CHECK_PAROLE_TIMEOUT = 6;
- static final int MSG_PAROLE_END_TIMEOUT = 7;
- static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
- static final int MSG_PAROLE_STATE_CHANGED = 9;
- static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
private final Object mLock = new Object();
Handler mHandler;
@@ -140,11 +101,7 @@
UserManager mUserManager;
PackageManager mPackageManager;
PackageManagerInternal mPackageManagerInternal;
- AppWidgetManager mAppWidgetManager;
IDeviceIdleController mDeviceIdleController;
- private DisplayManager mDisplayManager;
- private PowerManager mPowerManager;
- private IBatteryStats mBatteryStats;
private final SparseArray<UserUsageStatsService> mUserState = new SparseArray<>();
private final SparseIntArray mUidToKernelCounter = new SparseIntArray();
@@ -152,26 +109,7 @@
long mRealTimeSnapshot;
long mSystemTimeSnapshot;
- boolean mAppIdleEnabled;
- boolean mAppIdleTempParoled;
- boolean mCharging;
- private long mLastAppIdleParoledTime;
-
- private volatile boolean mPendingOneTimeCheckIdleStates;
- private boolean mSystemServicesReady = false;
-
- private final Object mAppIdleLock = new Object();
- @GuardedBy("mAppIdleLock")
- private AppIdleHistory mAppIdleHistory;
-
- @GuardedBy("mAppIdleLock")
- private ArrayList<UsageStatsManagerInternal.AppIdleStateChangeListener>
- mPackageAccessListeners = new ArrayList<>();
-
- @GuardedBy("mAppIdleLock")
- private boolean mHaveCarrierPrivilegedApps;
- @GuardedBy("mAppIdleLock")
- private List<String> mCarrierPrivilegedApps;
+ AppStandbyController mAppStandby;
public UsageStatsService(Context context) {
super(context);
@@ -185,6 +123,8 @@
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mHandler = new H(BackgroundThread.get().getLooper());
+ mAppStandby = new AppStandbyController(getContext(), BackgroundThread.get().getLooper());
+
File systemDataDir = new File(Environment.getDataDirectory(), "system");
mUsageStatsDir = new File(systemDataDir, "usagestats");
mUsageStatsDir.mkdirs();
@@ -198,30 +138,9 @@
getContext().registerReceiverAsUser(new UserActionsReceiver(), UserHandle.ALL, filter,
null, mHandler);
- IntentFilter packageFilter = new IntentFilter();
- packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- packageFilter.addDataScheme("package");
-
- getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL, packageFilter,
- null, mHandler);
-
- mAppIdleEnabled = getContext().getResources().getBoolean(
- com.android.internal.R.bool.config_enableAutoPowerModes);
- if (mAppIdleEnabled) {
- IntentFilter deviceStates = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
- deviceStates.addAction(BatteryManager.ACTION_DISCHARGING);
- deviceStates.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
- getContext().registerReceiver(new DeviceStateReceiver(), deviceStates);
- }
-
synchronized (mLock) {
cleanUpRemovedUsersLocked();
}
- synchronized (mAppIdleLock) {
- mAppIdleHistory = new AppIdleHistory(SystemClock.elapsedRealtime());
- }
mRealTimeSnapshot = SystemClock.elapsedRealtime();
mSystemTimeSnapshot = System.currentTimeMillis();
@@ -233,28 +152,10 @@
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_SYSTEM_SERVICES_READY) {
- // Observe changes to the threshold
- SettingsObserver settingsObserver = new SettingsObserver(mHandler);
- settingsObserver.registerObserver();
- settingsObserver.updateSettings();
+ mAppStandby.onBootPhase(phase);
- mAppWidgetManager = getContext().getSystemService(AppWidgetManager.class);
mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
- mBatteryStats = IBatteryStats.Stub.asInterface(
- ServiceManager.getService(BatteryStats.SERVICE_NAME));
- mDisplayManager = (DisplayManager) getContext().getSystemService(
- Context.DISPLAY_SERVICE);
- mPowerManager = getContext().getSystemService(PowerManager.class);
-
- mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
- synchronized (mAppIdleLock) {
- mAppIdleHistory.updateDisplay(isDisplayOn(), SystemClock.elapsedRealtime());
- }
-
- if (mPendingOneTimeCheckIdleStates) {
- postOneTimeCheckIdleStates();
- }
if (ENABLE_KERNEL_UPDATES && KERNEL_COUNTER_FILE.exists()) {
try {
@@ -268,18 +169,9 @@
} else {
Slog.w(TAG, "Missing procfs interface: " + KERNEL_COUNTER_FILE);
}
-
- mSystemServicesReady = true;
- } else if (phase == PHASE_BOOT_COMPLETED) {
- setChargingState(getContext().getSystemService(BatteryManager.class).isCharging());
}
}
- private boolean isDisplayOn() {
- return mDisplayManager
- .getDisplay(Display.DEFAULT_DISPLAY).getState() == Display.STATE_ON;
- }
-
private class UserActionsReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
@@ -291,60 +183,12 @@
}
} else if (Intent.ACTION_USER_STARTED.equals(action)) {
if (userId >=0) {
- postCheckIdleStates(userId);
+ mAppStandby.postCheckIdleStates(userId);
}
}
}
}
- private class PackageReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (Intent.ACTION_PACKAGE_ADDED.equals(action)
- || Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
- clearCarrierPrivilegedApps();
- }
- if ((Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
- Intent.ACTION_PACKAGE_ADDED.equals(action))
- && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
- clearAppIdleForPackage(intent.getData().getSchemeSpecificPart(),
- getSendingUserId());
- }
- }
- }
-
- private class DeviceStateReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
- setChargingState(intent.getIntExtra("plugged", 0) != 0);
- } else if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
- onDeviceIdleModeChanged();
- }
- }
- }
-
- private final DisplayManager.DisplayListener mDisplayListener
- = new DisplayManager.DisplayListener() {
-
- @Override public void onDisplayAdded(int displayId) {
- }
-
- @Override public void onDisplayRemoved(int displayId) {
- }
-
- @Override public void onDisplayChanged(int displayId) {
- if (displayId == Display.DEFAULT_DISPLAY) {
- final boolean displayOn = isDisplayOn();
- synchronized (UsageStatsService.this.mAppIdleLock) {
- mAppIdleHistory.updateDisplay(displayOn, SystemClock.elapsedRealtime());
- }
- }
- }
- };
-
private final IUidObserver mUidObserver = new IUidObserver.Stub() {
@Override
public void onUidStateChanged(int uid, int procState, long procStateSeq) {
@@ -388,42 +232,18 @@
@Override
public void onStatsReloaded() {
- postOneTimeCheckIdleStates();
+ mAppStandby.postOneTimeCheckIdleStates();
}
@Override
public void onNewUpdate(int userId) {
- initializeDefaultsForSystemApps(userId);
- }
-
- private void initializeDefaultsForSystemApps(int userId) {
- Slog.d(TAG, "Initializing defaults for system apps on user " + userId);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
- PackageManager.MATCH_DISABLED_COMPONENTS,
- userId);
- final int packageCount = packages.size();
- synchronized (mAppIdleLock) {
- for (int i = 0; i < packageCount; i++) {
- final PackageInfo pi = packages.get(i);
- String packageName = pi.packageName;
- if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) {
- mAppIdleHistory.reportUsage(packageName, userId, elapsedRealtime);
- }
- }
- }
+ mAppStandby.initializeDefaultsForSystemApps(userId);
}
private boolean shouldObfuscateInstantAppsForCaller(int callingUid, int userId) {
return !mPackageManagerInternal.canAccessInstantApps(callingUid, userId);
}
- void clearAppIdleForPackage(String packageName, int userId) {
- synchronized (mAppIdleLock) {
- mAppIdleHistory.clearUsage(packageName, userId);
- }
- }
-
private void cleanUpRemovedUsersLocked() {
final List<UserInfo> users = mUserManager.getUsers(true);
if (users == null || users.size() == 0) {
@@ -451,195 +271,6 @@
}
}
- void setChargingState(boolean charging) {
- synchronized (mAppIdleLock) {
- if (mCharging != charging) {
- mCharging = charging;
- postParoleStateChanged();
- }
- }
- }
-
- /** Paroled here means temporary pardon from being inactive */
- void setAppIdleParoled(boolean paroled) {
- synchronized (mAppIdleLock) {
- final long now = System.currentTimeMillis();
- if (mAppIdleTempParoled != paroled) {
- mAppIdleTempParoled = paroled;
- if (DEBUG) Slog.d(TAG, "Changing paroled to " + mAppIdleTempParoled);
- if (paroled) {
- postParoleEndTimeout();
- } else {
- mLastAppIdleParoledTime = now;
- postNextParoleTimeout(now);
- }
- postParoleStateChanged();
- }
- }
- }
-
- boolean isParoledOrCharging() {
- synchronized (mAppIdleLock) {
- return mAppIdleTempParoled || mCharging;
- }
- }
-
- private void postNextParoleTimeout(long now) {
- if (DEBUG) Slog.d(TAG, "Posting MSG_CHECK_PAROLE_TIMEOUT");
- mHandler.removeMessages(MSG_CHECK_PAROLE_TIMEOUT);
- // Compute when the next parole needs to happen. We check more frequently than necessary
- // since the message handler delays are based on elapsedRealTime and not wallclock time.
- // The comparison is done in wallclock time.
- long timeLeft = (mLastAppIdleParoledTime + mAppIdleParoleIntervalMillis) - now;
- if (timeLeft < 0) {
- timeLeft = 0;
- }
- mHandler.sendEmptyMessageDelayed(MSG_CHECK_PAROLE_TIMEOUT, timeLeft);
- }
-
- private void postParoleEndTimeout() {
- if (DEBUG) Slog.d(TAG, "Posting MSG_PAROLE_END_TIMEOUT");
- mHandler.removeMessages(MSG_PAROLE_END_TIMEOUT);
- mHandler.sendEmptyMessageDelayed(MSG_PAROLE_END_TIMEOUT, mAppIdleParoleDurationMillis);
- }
-
- private void postParoleStateChanged() {
- if (DEBUG) Slog.d(TAG, "Posting MSG_PAROLE_STATE_CHANGED");
- mHandler.removeMessages(MSG_PAROLE_STATE_CHANGED);
- mHandler.sendEmptyMessage(MSG_PAROLE_STATE_CHANGED);
- }
-
- void postCheckIdleStates(int userId) {
- mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
- }
-
- /**
- * We send a different message to check idle states once, otherwise we would end up
- * scheduling a series of repeating checkIdleStates each time we fired off one.
- */
- void postOneTimeCheckIdleStates() {
- if (mDeviceIdleController == null) {
- // Not booted yet; wait for it!
- mPendingOneTimeCheckIdleStates = true;
- } else {
- mHandler.sendEmptyMessage(MSG_ONE_TIME_CHECK_IDLE_STATES);
- mPendingOneTimeCheckIdleStates = false;
- }
- }
-
- /**
- * Check all running users' or specified user's apps to see if they enter an idle state.
- * @return Returns whether checking should continue periodically.
- */
- boolean checkIdleStates(int checkUserId) {
- if (!mAppIdleEnabled) {
- return false;
- }
-
- final int[] runningUserIds;
- try {
- runningUserIds = ActivityManager.getService().getRunningUserIds();
- if (checkUserId != UserHandle.USER_ALL
- && !ArrayUtils.contains(runningUserIds, checkUserId)) {
- return false;
- }
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
-
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- for (int i = 0; i < runningUserIds.length; i++) {
- final int userId = runningUserIds[i];
- if (checkUserId != UserHandle.USER_ALL && checkUserId != userId) {
- continue;
- }
- if (DEBUG) {
- Slog.d(TAG, "Checking idle state for user " + userId);
- }
- List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
- PackageManager.MATCH_DISABLED_COMPONENTS,
- userId);
- final int packageCount = packages.size();
- for (int p = 0; p < packageCount; p++) {
- final PackageInfo pi = packages.get(p);
- final String packageName = pi.packageName;
- final boolean isIdle = isAppIdleFiltered(packageName,
- UserHandle.getAppId(pi.applicationInfo.uid),
- userId, elapsedRealtime);
- mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
- userId, isIdle ? 1 : 0, packageName));
- if (isIdle) {
- synchronized (mAppIdleLock) {
- mAppIdleHistory.setIdle(packageName, userId, elapsedRealtime);
- }
- }
- }
- }
- if (DEBUG) {
- Slog.d(TAG, "checkIdleStates took "
- + (SystemClock.elapsedRealtime() - elapsedRealtime));
- }
- return true;
- }
-
- /** Check if it's been a while since last parole and let idle apps do some work */
- void checkParoleTimeout() {
- boolean setParoled = false;
- synchronized (mAppIdleLock) {
- final long now = System.currentTimeMillis();
- if (!mAppIdleTempParoled) {
- final long timeSinceLastParole = now - mLastAppIdleParoledTime;
- if (timeSinceLastParole > mAppIdleParoleIntervalMillis) {
- if (DEBUG) Slog.d(TAG, "Crossed default parole interval");
- setParoled = true;
- } else {
- if (DEBUG) Slog.d(TAG, "Not long enough to go to parole");
- postNextParoleTimeout(now);
- }
- }
- }
- if (setParoled) {
- setAppIdleParoled(true);
- }
- }
-
- private void notifyBatteryStats(String packageName, int userId, boolean idle) {
- try {
- final int uid = mPackageManager.getPackageUidAsUser(packageName,
- PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
- if (idle) {
- mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE,
- packageName, uid);
- } else {
- mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_ACTIVE,
- packageName, uid);
- }
- } catch (NameNotFoundException | RemoteException e) {
- }
- }
-
- void onDeviceIdleModeChanged() {
- final boolean deviceIdle = mPowerManager.isDeviceIdleMode();
- if (DEBUG) Slog.i(TAG, "DeviceIdleMode changed to " + deviceIdle);
- boolean paroled = false;
- synchronized (mAppIdleLock) {
- final long timeSinceLastParole = System.currentTimeMillis() - mLastAppIdleParoledTime;
- if (!deviceIdle
- && timeSinceLastParole >= mAppIdleParoleIntervalMillis) {
- if (DEBUG) {
- Slog.i(TAG, "Bringing idle apps out of inactive state due to deviceIdleMode=false");
- }
- paroled = true;
- } else if (deviceIdle) {
- if (DEBUG) Slog.i(TAG, "Device idle, back to prison");
- paroled = false;
- } else {
- return;
- }
- }
- setAppIdleParoled(paroled);
- }
-
private static void deleteRecursively(File f) {
File[] files = f.listFiles();
if (files != null) {
@@ -724,76 +355,7 @@
getUserDataAndInitializeIfNeededLocked(userId, timeNow);
service.reportEvent(event);
- synchronized (mAppIdleLock) {
- // TODO: Ideally this should call isAppIdleFiltered() to avoid calling back
- // about apps that are on some kind of whitelist anyway.
- final boolean previouslyIdle = mAppIdleHistory.isIdle(
- event.mPackage, userId, elapsedRealtime);
- // Inform listeners if necessary
- if ((event.mEventType == Event.MOVE_TO_FOREGROUND
- || event.mEventType == Event.MOVE_TO_BACKGROUND
- || event.mEventType == Event.SYSTEM_INTERACTION
- || event.mEventType == Event.USER_INTERACTION)) {
- mAppIdleHistory.reportUsage(event.mPackage, userId, elapsedRealtime);
- if (previouslyIdle) {
- mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
- /* idle = */ 0, event.mPackage));
- notifyBatteryStats(event.mPackage, userId, false);
- }
- }
- }
- }
- }
-
- void reportContentProviderUsage(String authority, String providerPkgName, int userId) {
- // Get sync adapters for the authority
- String[] packages = ContentResolver.getSyncAdapterPackagesForAuthorityAsUser(
- authority, userId);
- for (String packageName: packages) {
- // Only force the sync adapters to active if the provider is not in the same package and
- // the sync adapter is a system package.
- try {
- PackageInfo pi = mPackageManager.getPackageInfoAsUser(
- packageName, PackageManager.MATCH_SYSTEM_ONLY, userId);
- if (pi == null || pi.applicationInfo == null) {
- continue;
- }
- if (!packageName.equals(providerPkgName)) {
- setAppIdleAsync(packageName, false, userId);
- }
- } catch (NameNotFoundException e) {
- // Shouldn't happen
- }
- }
- }
-
- /**
- * Forces the app's beginIdleTime and lastUsedTime to reflect idle or active. If idle,
- * then it rolls back the beginIdleTime and lastUsedTime to a point in time that's behind
- * the threshold for idle.
- *
- * This method is always called from the handler thread, so not much synchronization is
- * required.
- */
- void forceIdleState(String packageName, int userId, boolean idle) {
- final int appId = getAppId(packageName);
- if (appId < 0) return;
- final long elapsedRealtime = SystemClock.elapsedRealtime();
-
- final boolean previouslyIdle = isAppIdleFiltered(packageName, appId,
- userId, elapsedRealtime);
- synchronized (mAppIdleLock) {
- mAppIdleHistory.setIdle(packageName, userId, idle, elapsedRealtime);
- }
- final boolean stillIdle = isAppIdleFiltered(packageName, appId,
- userId, elapsedRealtime);
- // Inform listeners if necessary
- if (previouslyIdle != stillIdle) {
- mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
- /* idle = */ stillIdle ? 1 : 0, packageName));
- if (!stillIdle) {
- notifyBatteryStats(packageName, userId, idle);
- }
+ mAppStandby.reportEvent(event, elapsedRealtime, userId);
}
}
@@ -813,9 +375,7 @@
synchronized (mLock) {
Slog.i(TAG, "Removing user " + userId + " and all data.");
mUserState.remove(userId);
- synchronized (mAppIdleLock) {
- mAppIdleHistory.onUserRemoved(userId);
- }
+ mAppStandby.onUserRemoved(userId);
cleanUpRemovedUsersLocked();
}
}
@@ -887,253 +447,6 @@
}
}
- private boolean isAppIdleUnfiltered(String packageName, int userId, long elapsedRealtime) {
- synchronized (mAppIdleLock) {
- return mAppIdleHistory.isIdle(packageName, userId, elapsedRealtime);
- }
- }
-
- void addListener(AppIdleStateChangeListener listener) {
- synchronized (mAppIdleLock) {
- if (!mPackageAccessListeners.contains(listener)) {
- mPackageAccessListeners.add(listener);
- }
- }
- }
-
- void removeListener(AppIdleStateChangeListener listener) {
- synchronized (mAppIdleLock) {
- mPackageAccessListeners.remove(listener);
- }
- }
-
- int getAppId(String packageName) {
- try {
- ApplicationInfo ai = mPackageManager.getApplicationInfo(packageName,
- PackageManager.MATCH_ANY_USER
- | PackageManager.MATCH_DISABLED_COMPONENTS);
- return ai.uid;
- } catch (NameNotFoundException re) {
- return -1;
- }
- }
-
- boolean isAppIdleFilteredOrParoled(String packageName, int userId, long elapsedRealtime,
- boolean shouldObfuscateInstantApps) {
- if (isParoledOrCharging()) {
- return false;
- }
- if (shouldObfuscateInstantApps &&
- mPackageManagerInternal.isPackageEphemeral(userId, packageName)) {
- return false;
- }
- return isAppIdleFiltered(packageName, getAppId(packageName), userId, elapsedRealtime);
- }
-
- /**
- * Checks if an app has been idle for a while and filters out apps that are excluded.
- * It returns false if the current system state allows all apps to be considered active.
- * This happens if the device is plugged in or temporarily allowed to make exceptions.
- * Called by interface impls.
- */
- private boolean isAppIdleFiltered(String packageName, int appId, int userId,
- long elapsedRealtime) {
- if (packageName == null) return false;
- // If not enabled at all, of course nobody is ever idle.
- if (!mAppIdleEnabled) {
- return false;
- }
- if (appId < Process.FIRST_APPLICATION_UID) {
- // System uids never go idle.
- return false;
- }
- if (packageName.equals("android")) {
- // Nor does the framework (which should be redundant with the above, but for MR1 we will
- // retain this for safety).
- return false;
- }
- if (mSystemServicesReady) {
- try {
- // We allow all whitelisted apps, including those that don't want to be whitelisted
- // for idle mode, because app idle (aka app standby) is really not as big an issue
- // for controlling who participates vs. doze mode.
- if (mDeviceIdleController.isPowerSaveWhitelistExceptIdleApp(packageName)) {
- return false;
- }
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
-
- if (isActiveDeviceAdmin(packageName, userId)) {
- return false;
- }
-
- if (isActiveNetworkScorer(packageName)) {
- return false;
- }
-
- if (mAppWidgetManager != null
- && mAppWidgetManager.isBoundWidgetPackage(packageName, userId)) {
- return false;
- }
-
- if (isDeviceProvisioningPackage(packageName)) {
- return false;
- }
- }
-
- if (!isAppIdleUnfiltered(packageName, userId, elapsedRealtime)) {
- return false;
- }
-
- // Check this last, as it is the most expensive check
- // TODO: Optimize this by fetching the carrier privileged apps ahead of time
- if (isCarrierApp(packageName)) {
- return false;
- }
-
- return true;
- }
-
- int[] getIdleUidsForUser(int userId) {
- if (!mAppIdleEnabled) {
- return new int[0];
- }
-
- final long elapsedRealtime = SystemClock.elapsedRealtime();
-
- List<ApplicationInfo> apps;
- try {
- ParceledListSlice<ApplicationInfo> slice = AppGlobals.getPackageManager()
- .getInstalledApplications(/* flags= */ 0, userId);
- if (slice == null) {
- return new int[0];
- }
- apps = slice.getList();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
-
- // State of each uid. Key is the uid. Value lower 16 bits is the number of apps
- // associated with that uid, upper 16 bits is the number of those apps that is idle.
- SparseIntArray uidStates = new SparseIntArray();
-
- // Now resolve all app state. Iterating over all apps, keeping track of how many
- // we find for each uid and how many of those are idle.
- for (int i = apps.size() - 1; i >= 0; i--) {
- ApplicationInfo ai = apps.get(i);
-
- // Check whether this app is idle.
- boolean idle = isAppIdleFiltered(ai.packageName, UserHandle.getAppId(ai.uid),
- userId, elapsedRealtime);
-
- int index = uidStates.indexOfKey(ai.uid);
- if (index < 0) {
- uidStates.put(ai.uid, 1 + (idle ? 1<<16 : 0));
- } else {
- int value = uidStates.valueAt(index);
- uidStates.setValueAt(index, value + 1 + (idle ? 1<<16 : 0));
- }
- }
- if (DEBUG) {
- Slog.d(TAG, "getIdleUids took " + (SystemClock.elapsedRealtime() - elapsedRealtime));
- }
- int numIdle = 0;
- for (int i = uidStates.size() - 1; i >= 0; i--) {
- int value = uidStates.valueAt(i);
- if ((value&0x7fff) == (value>>16)) {
- numIdle++;
- }
- }
-
- int[] res = new int[numIdle];
- numIdle = 0;
- for (int i = uidStates.size() - 1; i >= 0; i--) {
- int value = uidStates.valueAt(i);
- if ((value&0x7fff) == (value>>16)) {
- res[numIdle] = uidStates.keyAt(i);
- numIdle++;
- }
- }
-
- return res;
- }
-
- void setAppIdleAsync(String packageName, boolean idle, int userId) {
- if (packageName == null) return;
-
- mHandler.obtainMessage(MSG_FORCE_IDLE_STATE, userId, idle ? 1 : 0, packageName)
- .sendToTarget();
- }
-
- private boolean isActiveDeviceAdmin(String packageName, int userId) {
- DevicePolicyManager dpm = getContext().getSystemService(DevicePolicyManager.class);
- if (dpm == null) return false;
- return dpm.packageHasActiveAdmins(packageName, userId);
- }
-
- /**
- * Returns {@code true} if the supplied package is the device provisioning app. Otherwise,
- * returns {@code false}.
- */
- private boolean isDeviceProvisioningPackage(String packageName) {
- String deviceProvisioningPackage = getContext().getResources().getString(
- com.android.internal.R.string.config_deviceProvisioningPackage);
- return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName);
- }
-
- private boolean isCarrierApp(String packageName) {
- synchronized (mAppIdleLock) {
- if (!mHaveCarrierPrivilegedApps) {
- fetchCarrierPrivilegedAppsLA();
- }
- if (mCarrierPrivilegedApps != null) {
- return mCarrierPrivilegedApps.contains(packageName);
- }
- return false;
- }
- }
-
- void clearCarrierPrivilegedApps() {
- if (DEBUG) {
- Slog.i(TAG, "Clearing carrier privileged apps list");
- }
- synchronized (mAppIdleLock) {
- mHaveCarrierPrivilegedApps = false;
- mCarrierPrivilegedApps = null; // Need to be refetched.
- }
- }
-
- @GuardedBy("mAppIdleLock")
- private void fetchCarrierPrivilegedAppsLA() {
- TelephonyManager telephonyManager =
- getContext().getSystemService(TelephonyManager.class);
- mCarrierPrivilegedApps = telephonyManager.getPackagesWithCarrierPrivileges();
- mHaveCarrierPrivilegedApps = true;
- if (DEBUG) {
- Slog.d(TAG, "apps with carrier privilege " + mCarrierPrivilegedApps);
- }
- }
-
- private boolean isActiveNetworkScorer(String packageName) {
- NetworkScoreManager nsm = (NetworkScoreManager) getContext().getSystemService(
- Context.NETWORK_SCORE_SERVICE);
- return packageName != null && packageName.equals(nsm.getActiveScorerPackage());
- }
-
- void informListeners(String packageName, int userId, boolean isIdle) {
- for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
- listener.onAppIdleStateChanged(packageName, userId, isIdle);
- }
- }
-
- void informParoleStateChanged() {
- final boolean paroled = isParoledOrCharging();
- for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
- listener.onParoleStateChanged(paroled);
- }
- }
-
private static boolean validRange(long currentTime, long beginTime, long endTime) {
return beginTime <= currentTime && beginTime < endTime;
}
@@ -1143,15 +456,10 @@
for (int i = 0; i < userCount; i++) {
UserUsageStatsService service = mUserState.valueAt(i);
service.persistActiveStats();
- synchronized (mAppIdleLock) {
- mAppIdleHistory.writeAppIdleTimes(mUserState.keyAt(i));
- }
+ mAppStandby.flushToDisk(mUserState.keyAt(i));
}
- // Persist elapsed and screen on time. If this fails for whatever reason, the apps will be
- // considered not-idle, which is the safest outcome in such an event.
- synchronized (mAppIdleLock) {
- mAppIdleHistory.writeAppIdleDurations();
- }
+ mAppStandby.flushDurationsToDisk();
+
mHandler.removeMessages(MSG_FLUSH_TO_DISK);
}
@@ -1166,7 +474,8 @@
final int userCount = mUserState.size();
for (int i = 0; i < userCount; i++) {
- idpw.printPair("user", mUserState.keyAt(i));
+ int userId = mUserState.keyAt(i);
+ idpw.printPair("user", userId);
idpw.println();
idpw.increaseIndent();
if (argSet.contains("--checkin")) {
@@ -1176,57 +485,19 @@
idpw.println();
if (args.length > 0) {
if ("history".equals(args[0])) {
- synchronized (mAppIdleLock) {
- mAppIdleHistory.dumpHistory(idpw, mUserState.keyAt(i));
- }
+ mAppStandby.dumpHistory(idpw, userId);
} else if ("flush".equals(args[0])) {
- UsageStatsService.this.flushToDiskLocked();
+ flushToDiskLocked();
pw.println("Flushed stats to disk");
}
}
}
- synchronized (mAppIdleLock) {
- mAppIdleHistory.dump(idpw, mUserState.keyAt(i));
- }
+ mAppStandby.dumpUser(idpw, userId);
idpw.decreaseIndent();
}
pw.println();
- synchronized (mAppIdleLock) {
- pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps
- + "): " + mCarrierPrivilegedApps);
- }
-
- pw.println();
- pw.println("Settings:");
-
- pw.print(" mAppIdleDurationMillis=");
- TimeUtils.formatDuration(mAppIdleScreenThresholdMillis, pw);
- pw.println();
-
- pw.print(" mAppIdleWallclockThresholdMillis=");
- TimeUtils.formatDuration(mAppIdleWallclockThresholdMillis, pw);
- pw.println();
-
- pw.print(" mCheckIdleIntervalMillis=");
- TimeUtils.formatDuration(mCheckIdleIntervalMillis, pw);
- pw.println();
-
- pw.print(" mAppIdleParoleIntervalMillis=");
- TimeUtils.formatDuration(mAppIdleParoleIntervalMillis, pw);
- pw.println();
-
- pw.print(" mAppIdleParoleDurationMillis=");
- TimeUtils.formatDuration(mAppIdleParoleDurationMillis, pw);
- pw.println();
-
- pw.println();
- pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
- pw.print(" mAppIdleTempParoled="); pw.print(mAppIdleTempParoled);
- pw.print(" mCharging="); pw.print(mCharging);
- pw.print(" mLastAppIdleParoledTime=");
- TimeUtils.formatDuration(mLastAppIdleParoledTime, pw);
- pw.println();
+ mAppStandby.dumpState(args, pw);
}
}
@@ -1250,50 +521,6 @@
onUserRemoved(msg.arg1);
break;
- case MSG_INFORM_LISTENERS:
- informListeners((String) msg.obj, msg.arg1, msg.arg2 == 1);
- break;
-
- case MSG_FORCE_IDLE_STATE:
- forceIdleState((String) msg.obj, msg.arg1, msg.arg2 == 1);
- break;
-
- case MSG_CHECK_IDLE_STATES:
- if (checkIdleStates(msg.arg1)) {
- mHandler.sendMessageDelayed(mHandler.obtainMessage(
- MSG_CHECK_IDLE_STATES, msg.arg1, 0),
- mCheckIdleIntervalMillis);
- }
- break;
-
- case MSG_ONE_TIME_CHECK_IDLE_STATES:
- mHandler.removeMessages(MSG_ONE_TIME_CHECK_IDLE_STATES);
- checkIdleStates(UserHandle.USER_ALL);
- break;
-
- case MSG_CHECK_PAROLE_TIMEOUT:
- checkParoleTimeout();
- break;
-
- case MSG_PAROLE_END_TIMEOUT:
- if (DEBUG) Slog.d(TAG, "Ending parole");
- setAppIdleParoled(false);
- break;
-
- case MSG_REPORT_CONTENT_PROVIDER_USAGE:
- SomeArgs args = (SomeArgs) msg.obj;
- reportContentProviderUsage((String) args.arg1, // authority name
- (String) args.arg2, // package name
- (int) args.arg3); // userId
- args.recycle();
- break;
-
- case MSG_PAROLE_STATE_CHANGED:
- if (DEBUG) Slog.d(TAG, "Parole state: " + mAppIdleTempParoled
- + ", Charging state:" + mCharging);
- informParoleStateChanged();
- break;
-
default:
super.handleMessage(msg);
break;
@@ -1301,72 +528,6 @@
}
}
- /**
- * Observe settings changes for {@link Settings.Global#APP_IDLE_CONSTANTS}.
- */
- private class SettingsObserver extends ContentObserver {
- /**
- * This flag has been used to disable app idle on older builds with bug b/26355386.
- */
- @Deprecated
- private static final String KEY_IDLE_DURATION_OLD = "idle_duration";
-
- private static final String KEY_IDLE_DURATION = "idle_duration2";
- private static final String KEY_WALLCLOCK_THRESHOLD = "wallclock_threshold";
- private static final String KEY_PAROLE_INTERVAL = "parole_interval";
- private static final String KEY_PAROLE_DURATION = "parole_duration";
-
- private final KeyValueListParser mParser = new KeyValueListParser(',');
-
- SettingsObserver(Handler handler) {
- super(handler);
- }
-
- void registerObserver() {
- getContext().getContentResolver().registerContentObserver(Settings.Global.getUriFor(
- Settings.Global.APP_IDLE_CONSTANTS), false, this);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- updateSettings();
- postOneTimeCheckIdleStates();
- }
-
- void updateSettings() {
- synchronized (mAppIdleLock) {
- // Look at global settings for this.
- // TODO: Maybe apply different thresholds for different users.
- try {
- mParser.setString(Settings.Global.getString(getContext().getContentResolver(),
- Settings.Global.APP_IDLE_CONSTANTS));
- } catch (IllegalArgumentException e) {
- Slog.e(TAG, "Bad value for app idle settings: " + e.getMessage());
- // fallthrough, mParser is empty and all defaults will be returned.
- }
-
- // Default: 12 hours of screen-on time sans dream-time
- mAppIdleScreenThresholdMillis = mParser.getLong(KEY_IDLE_DURATION,
- COMPRESS_TIME ? ONE_MINUTE * 4 : 12 * 60 * ONE_MINUTE);
-
- mAppIdleWallclockThresholdMillis = mParser.getLong(KEY_WALLCLOCK_THRESHOLD,
- COMPRESS_TIME ? ONE_MINUTE * 8 : 2L * 24 * 60 * ONE_MINUTE); // 2 days
-
- mCheckIdleIntervalMillis = Math.min(mAppIdleScreenThresholdMillis / 4,
- COMPRESS_TIME ? ONE_MINUTE : 8 * 60 * ONE_MINUTE); // 8 hours
-
- // Default: 24 hours between paroles
- mAppIdleParoleIntervalMillis = mParser.getLong(KEY_PAROLE_INTERVAL,
- COMPRESS_TIME ? ONE_MINUTE * 10 : 24 * 60 * ONE_MINUTE);
-
- mAppIdleParoleDurationMillis = mParser.getLong(KEY_PAROLE_DURATION,
- COMPRESS_TIME ? ONE_MINUTE : 10 * ONE_MINUTE); // 10 minutes
- mAppIdleHistory.setThresholds(mAppIdleWallclockThresholdMillis,
- mAppIdleScreenThresholdMillis);
- }
- }
- }
-
private final class BinderService extends IUsageStatsManager.Stub {
private boolean hasPermission(String callingPackage) {
@@ -1462,7 +623,8 @@
Binder.getCallingUid(), userId);
final long token = Binder.clearCallingIdentity();
try {
- return UsageStatsService.this.isAppIdleFilteredOrParoled(packageName, userId,
+ return mAppStandby.isAppIdleFilteredOrParoled(
+ packageName, userId,
SystemClock.elapsedRealtime(), obfuscateInstantApps);
} finally {
Binder.restoreCallingIdentity(token);
@@ -1483,9 +645,9 @@
"No permission to change app idle state");
final long token = Binder.clearCallingIdentity();
try {
- final int appId = getAppId(packageName);
+ final int appId = mAppStandby.getAppId(packageName);
if (appId < 0) return;
- UsageStatsService.this.setAppIdleAsync(packageName, idle, userId);
+ mAppStandby.setAppIdleAsync(packageName, idle, userId);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1509,7 +671,7 @@
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_CARRIER_SERVICES,
"onCarrierPrivilegedAppsChanged can only be called by privileged apps.");
- UsageStatsService.this.clearCarrierPrivilegedApps();
+ mAppStandby.clearCarrierPrivilegedApps();
}
@Override
@@ -1624,28 +786,23 @@
@Override
public void reportContentProviderUsage(String name, String packageName, int userId) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = name;
- args.arg2 = packageName;
- args.arg3 = userId;
- mHandler.obtainMessage(MSG_REPORT_CONTENT_PROVIDER_USAGE, args)
- .sendToTarget();
+ mAppStandby.postReportContentProviderUsage(name, packageName, userId);
}
@Override
public boolean isAppIdle(String packageName, int uidForAppId, int userId) {
- return UsageStatsService.this.isAppIdleFiltered(packageName, uidForAppId, userId,
- SystemClock.elapsedRealtime());
+ return mAppStandby.isAppIdleFiltered(packageName, uidForAppId,
+ userId, SystemClock.elapsedRealtime());
}
@Override
public int[] getIdleUidsForUser(int userId) {
- return UsageStatsService.this.getIdleUidsForUser(userId);
+ return mAppStandby.getIdleUidsForUser(userId);
}
@Override
public boolean isAppIdleParoleOn() {
- return isParoledOrCharging();
+ return mAppStandby.isParoledOrCharging();
}
@Override
@@ -1658,20 +815,20 @@
@Override
public void addAppIdleStateChangeListener(AppIdleStateChangeListener listener) {
- UsageStatsService.this.addListener(listener);
+ mAppStandby.addListener(listener);
listener.onParoleStateChanged(isAppIdleParoleOn());
}
@Override
public void removeAppIdleStateChangeListener(
AppIdleStateChangeListener listener) {
- UsageStatsService.this.removeListener(listener);
+ mAppStandby.removeListener(listener);
}
@Override
public byte[] getBackupPayload(int user, String key) {
// Check to ensure that only user 0's data is b/r for now
- synchronized (UsageStatsService.this.mLock) {
+ synchronized (mLock) {
if (user == UserHandle.USER_SYSTEM) {
final UserUsageStatsService userStats =
getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked());
@@ -1684,7 +841,7 @@
@Override
public void applyRestoredPayload(int user, String key, byte[] payload) {
- synchronized (UsageStatsService.this.mLock) {
+ synchronized (mLock) {
if (user == UserHandle.USER_SYSTEM) {
final UserUsageStatsService userStats =
getUserDataAndInitializeIfNeededLocked(user, checkAndGetTimeLocked());
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 68c1d5f..acc27be 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -314,7 +314,11 @@
return null;
}
- mDevicesParser.scan();
+ if (!mDevicesParser.scan()) {
+ Slog.e(TAG, "Error parsing ALSA devices file.");
+ return null;
+ }
+
int device = mDevicesParser.getDefaultDeviceNum(card);
boolean hasPlayback = mDevicesParser.hasPlaybackDevices(card);
diff --git a/tests/net/java/com/android/internal/util/BitUtilsTest.java b/tests/net/java/com/android/internal/util/BitUtilsTest.java
index 0ad8a21..f4dc12a 100644
--- a/tests/net/java/com/android/internal/util/BitUtilsTest.java
+++ b/tests/net/java/com/android/internal/util/BitUtilsTest.java
@@ -56,6 +56,25 @@
}
@Test
+ public void testUnsignedShortComposition() {
+ byte b0 = 0;
+ byte b1 = 1;
+ byte b2 = 2;
+ byte b10 = 10;
+ byte b16 = 16;
+ byte b128 = -128;
+ byte b224 = -32;
+ byte b255 = -1;
+ assertEquals(0x0000, uint16(b0, b0));
+ assertEquals(0xffff, uint16(b255, b255));
+ assertEquals(0x0a01, uint16(b10, b1));
+ assertEquals(0x8002, uint16(b128, b2));
+ assertEquals(0x01ff, uint16(b1, b255));
+ assertEquals(0x80ff, uint16(b128, b255));
+ assertEquals(0xe010, uint16(b224, b16));
+ }
+
+ @Test
public void testUnsignedIntWideningConversions() {
assertEquals(0, uint32(0));
assertEquals(1, uint32(1));
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 7a8a4ee..ff51d51 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -83,9 +83,13 @@
"configuration/ConfigurationParser.cpp",
"filter/AbiFilter.cpp",
"filter/ConfigFilter.cpp",
- "flatten/Archive.cpp",
- "flatten/TableFlattener.cpp",
- "flatten/XmlFlattener.cpp",
+ "format/Archive.cpp",
+ "format/binary/BinaryResourceParser.cpp",
+ "format/binary/ResChunkPullParser.cpp",
+ "format/binary/TableFlattener.cpp",
+ "format/binary/XmlFlattener.cpp",
+ "format/proto/ProtoDeserialize.cpp",
+ "format/proto/ProtoSerialize.cpp",
"io/BigBufferStreams.cpp",
"io/File.cpp",
"io/FileInputStream.cpp",
@@ -106,13 +110,9 @@
"optimize/ResourceDeduper.cpp",
"optimize/VersionCollapser.cpp",
"process/SymbolTable.cpp",
- "proto/ProtoDeserialize.cpp",
- "proto/ProtoSerialize.cpp",
"split/TableSplitter.cpp",
"text/Unicode.cpp",
"text/Utf8Iterator.cpp",
- "unflatten/BinaryResourceParser.cpp",
- "unflatten/ResChunkPullParser.cpp",
"util/BigBuffer.cpp",
"util/Files.cpp",
"util/Util.cpp",
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index 6f2b865..c1815c8 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -18,9 +18,9 @@
#include "ResourceValues.h"
#include "ValueVisitor.h"
-#include "flatten/Archive.h"
-#include "flatten/TableFlattener.h"
-#include "flatten/XmlFlattener.h"
+#include "format/Archive.h"
+#include "format/binary/TableFlattener.h"
+#include "format/binary/XmlFlattener.h"
#include "io/BigBufferInputStream.h"
#include "io/Util.h"
#include "xml/XmlDom.h"
diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h
index d779b7e..d2dd5cf 100644
--- a/tools/aapt2/LoadedApk.h
+++ b/tools/aapt2/LoadedApk.h
@@ -21,27 +21,35 @@
#include "ResourceTable.h"
#include "filter/Filter.h"
-#include "flatten/Archive.h"
-#include "flatten/TableFlattener.h"
+#include "format/Archive.h"
+#include "format/binary/BinaryResourceParser.h"
+#include "format/binary/TableFlattener.h"
#include "io/ZipArchive.h"
-#include "unflatten/BinaryResourceParser.h"
#include "xml/XmlDom.h"
namespace aapt {
-/** Info about an APK loaded in memory. */
+// Info about an APK loaded in memory.
class LoadedApk {
public:
- LoadedApk(const Source& source, std::unique_ptr<io::IFileCollection> apk,
- std::unique_ptr<ResourceTable> table)
- : source_(source), apk_(std::move(apk)), table_(std::move(table)) {
+ LoadedApk(
+ const Source& source,
+ std::unique_ptr<io::IFileCollection> apk,
+ std::unique_ptr<ResourceTable> table)
+ : source_(source), apk_(std::move(apk)), table_(std::move(table)) {}
+ virtual ~LoadedApk() = default;
+
+ io::IFileCollection* GetFileCollection() {
+ return apk_.get();
}
- io::IFileCollection* GetFileCollection() { return apk_.get(); }
+ ResourceTable* GetResourceTable() {
+ return table_.get();
+ }
- ResourceTable* GetResourceTable() { return table_.get(); }
-
- const Source& GetSource() { return source_; }
+ const Source& GetSource() {
+ return source_;
+ }
/**
* Writes the APK on disk at the given path, while also removing the resource
@@ -70,11 +78,11 @@
const android::StringPiece& path);
private:
+ DISALLOW_COPY_AND_ASSIGN(LoadedApk);
+
Source source_;
std::unique_ptr<io::IFileCollection> apk_;
std::unique_ptr<ResourceTable> table_;
-
- DISALLOW_COPY_AND_ASSIGN(LoadedApk);
};
} // namespace aapt
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index f193fe0..6fac6e9 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -23,12 +23,12 @@
#include "NameMangler.h"
#include "SdkConstants.h"
-#include "flatten/ResourceTypeExtensions.h"
+#include "format/binary/ResourceTypeExtensions.h"
#include "util/Files.h"
#include "util/Util.h"
-using android::StringPiece;
-using android::StringPiece16;
+using ::android::StringPiece;
+using ::android::StringPiece16;
namespace aapt {
namespace ResourceUtils {
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index 0690dc1..a5e6aefd1 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -35,12 +35,12 @@
#include "compile/Png.h"
#include "compile/PseudolocaleGenerator.h"
#include "compile/XmlIdCollector.h"
-#include "flatten/Archive.h"
-#include "flatten/XmlFlattener.h"
+#include "format/Archive.h"
+#include "format/binary/XmlFlattener.h"
+#include "format/proto/ProtoSerialize.h"
#include "io/BigBufferOutputStream.h"
#include "io/FileInputStream.h"
#include "io/Util.h"
-#include "proto/ProtoSerialize.h"
#include "util/Files.h"
#include "util/Maybe.h"
#include "util/Util.h"
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index 0dedc91..44032f6 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -21,10 +21,10 @@
#include "Debug.h"
#include "Diagnostics.h"
#include "Flags.h"
+#include "format/binary/BinaryResourceParser.h"
+#include "format/proto/ProtoDeserialize.h"
#include "io/ZipArchive.h"
#include "process/IResourceTableConsumer.h"
-#include "proto/ProtoDeserialize.h"
-#include "unflatten/BinaryResourceParser.h"
#include "util/Files.h"
using ::android::StringPiece;
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index f72069c..88e0f69 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -38,9 +38,12 @@
#include "cmd/Util.h"
#include "compile/IdAssigner.h"
#include "filter/ConfigFilter.h"
-#include "flatten/Archive.h"
-#include "flatten/TableFlattener.h"
-#include "flatten/XmlFlattener.h"
+#include "format/Archive.h"
+#include "format/binary/BinaryResourceParser.h"
+#include "format/binary/TableFlattener.h"
+#include "format/binary/XmlFlattener.h"
+#include "format/proto/ProtoDeserialize.h"
+#include "format/proto/ProtoSerialize.h"
#include "io/BigBufferInputStream.h"
#include "io/FileInputStream.h"
#include "io/FileSystem.h"
@@ -58,10 +61,7 @@
#include "optimize/VersionCollapser.h"
#include "process/IResourceTableConsumer.h"
#include "process/SymbolTable.h"
-#include "proto/ProtoDeserialize.h"
-#include "proto/ProtoSerialize.h"
#include "split/TableSplitter.h"
-#include "unflatten/BinaryResourceParser.h"
#include "util/Files.h"
#include "xml/XmlDom.h"
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index 56b61d0..67ac67a 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -31,8 +31,8 @@
#include "cmd/Util.h"
#include "configuration/ConfigurationParser.h"
#include "filter/AbiFilter.h"
-#include "flatten/TableFlattener.h"
-#include "flatten/XmlFlattener.h"
+#include "format/binary/TableFlattener.h"
+#include "format/binary/XmlFlattener.h"
#include "io/BigBufferInputStream.h"
#include "io/Util.h"
#include "optimize/MultiApkGenerator.h"
diff --git a/tools/aapt2/compile/PngChunkFilter.cpp b/tools/aapt2/compile/PngChunkFilter.cpp
index 5af91fd..bc2e699 100644
--- a/tools/aapt2/compile/PngChunkFilter.cpp
+++ b/tools/aapt2/compile/PngChunkFilter.cpp
@@ -21,8 +21,8 @@
#include "io/Io.h"
-using android::StringPiece;
-using android::base::StringPrintf;
+using ::android::StringPiece;
+using ::android::base::StringPrintf;
namespace aapt {
diff --git a/tools/aapt2/flatten/Archive.cpp b/tools/aapt2/format/Archive.cpp
similarity index 95%
rename from tools/aapt2/flatten/Archive.cpp
rename to tools/aapt2/format/Archive.cpp
index 5f8bd06..d152a9c 100644
--- a/tools/aapt2/flatten/Archive.cpp
+++ b/tools/aapt2/format/Archive.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "flatten/Archive.h"
+#include "format/Archive.h"
#include <cstdio>
#include <memory>
@@ -106,9 +106,13 @@
return !in->HadError();
}
- bool HadError() const override { return !error_.empty(); }
+ bool HadError() const override {
+ return !error_.empty();
+ }
- std::string GetError() const override { return error_; }
+ std::string GetError() const override {
+ return error_;
+ }
private:
DISALLOW_COPY_AND_ASSIGN(DirectoryWriter);
@@ -221,9 +225,13 @@
}
}
- bool HadError() const override { return !error_.empty(); }
+ bool HadError() const override {
+ return !error_.empty();
+ }
- std::string GetError() const override { return error_; }
+ std::string GetError() const override {
+ return error_;
+ }
virtual ~ZipFileWriter() {
if (writer_) {
diff --git a/tools/aapt2/flatten/Archive.h b/tools/aapt2/format/Archive.h
similarity index 96%
rename from tools/aapt2/flatten/Archive.h
rename to tools/aapt2/format/Archive.h
index 4ee4ce7..4e8a39d 100644
--- a/tools/aapt2/flatten/Archive.h
+++ b/tools/aapt2/format/Archive.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef AAPT_FLATTEN_ARCHIVE_H
-#define AAPT_FLATTEN_ARCHIVE_H
+#ifndef AAPT_FORMAT_ARCHIVE_H
+#define AAPT_FORMAT_ARCHIVE_H
#include <fstream>
#include <memory>
@@ -78,4 +78,4 @@
} // namespace aapt
-#endif /* AAPT_FLATTEN_ARCHIVE_H */
+#endif /* AAPT_FORMAT_ARCHIVE_H */
diff --git a/tools/aapt2/unflatten/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
similarity index 76%
rename from tools/aapt2/unflatten/BinaryResourceParser.cpp
rename to tools/aapt2/format/binary/BinaryResourceParser.cpp
index b87278b..95eec4a 100644
--- a/tools/aapt2/unflatten/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "unflatten/BinaryResourceParser.h"
+#include "format/binary/BinaryResourceParser.h"
#include <algorithm>
#include <map>
@@ -31,15 +31,15 @@
#include "ResourceValues.h"
#include "Source.h"
#include "ValueVisitor.h"
-#include "unflatten/ResChunkPullParser.h"
+#include "format/binary/ResChunkPullParser.h"
#include "util/Util.h"
-namespace aapt {
-
using namespace android;
using ::android::base::StringPrintf;
+namespace aapt {
+
namespace {
// Visitor that converts a reference's resource ID to a resource name, given a mapping from
@@ -118,15 +118,11 @@
return true;
}
-/**
- * Parses the resource table, which contains all the packages, types, and
- * entries.
- */
+// Parses the resource table, which contains all the packages, types, and entries.
bool BinaryResourceParser::ParseTable(const ResChunk_header* chunk) {
const ResTable_header* table_header = ConvertTo<ResTable_header>(chunk);
if (!table_header) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt ResTable_header chunk");
+ context_->GetDiagnostics()->Error(DiagMessage(source_) << "corrupt ResTable_header chunk");
return false;
}
@@ -136,21 +132,20 @@
switch (util::DeviceToHost16(parser.chunk()->type)) {
case android::RES_STRING_POOL_TYPE:
if (value_pool_.getError() == NO_INIT) {
- status_t err = value_pool_.setTo(
- parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
+ status_t err =
+ value_pool_.setTo(parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
if (err != NO_ERROR) {
- context_->GetDiagnostics()->Error(
- DiagMessage(source_) << "corrupt string pool in ResTable: "
- << value_pool_.getError());
+ context_->GetDiagnostics()->Error(DiagMessage(source_)
+ << "corrupt string pool in ResTable: "
+ << value_pool_.getError());
return false;
}
// Reserve some space for the strings we are going to add.
- table_->string_pool.HintWillAdd(value_pool_.size(),
- value_pool_.styleCount());
+ table_->string_pool.HintWillAdd(value_pool_.size(), value_pool_.styleCount());
} else {
- context_->GetDiagnostics()->Warn(
- DiagMessage(source_) << "unexpected string pool in ResTable");
+ context_->GetDiagnostics()->Warn(DiagMessage(source_)
+ << "unexpected string pool in ResTable");
}
break;
@@ -169,8 +164,8 @@
}
if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
- context_->GetDiagnostics()->Error(
- DiagMessage(source_) << "corrupt resource table: " << parser.error());
+ context_->GetDiagnostics()->Error(DiagMessage(source_)
+ << "corrupt resource table: " << parser.error());
return false;
}
return true;
@@ -187,26 +182,25 @@
uint32_t package_id = util::DeviceToHost32(package_header->id);
if (package_id > std::numeric_limits<uint8_t>::max()) {
- context_->GetDiagnostics()->Error(
- DiagMessage(source_) << "package ID is too big (" << package_id << ")");
+ context_->GetDiagnostics()->Error(DiagMessage(source_)
+ << "package ID is too big (" << package_id << ")");
return false;
}
// Extract the package name.
- size_t len = strnlen16((const char16_t*)package_header->name,
- arraysize(package_header->name));
+ size_t len = strnlen16((const char16_t*)package_header->name, arraysize(package_header->name));
std::u16string package_name;
package_name.resize(len);
for (size_t i = 0; i < len; i++) {
package_name[i] = util::DeviceToHost16(package_header->name[i]);
}
- ResourceTablePackage* package = table_->CreatePackage(
- util::Utf16ToUtf8(package_name), static_cast<uint8_t>(package_id));
+ ResourceTablePackage* package =
+ table_->CreatePackage(util::Utf16ToUtf8(package_name), static_cast<uint8_t>(package_id));
if (!package) {
- context_->GetDiagnostics()->Error(
- DiagMessage(source_) << "incompatible package '" << package_name
- << "' with ID " << package_id);
+ context_->GetDiagnostics()->Error(DiagMessage(source_)
+ << "incompatible package '" << package_name << "' with ID "
+ << package_id);
return false;
}
@@ -221,23 +215,21 @@
switch (util::DeviceToHost16(parser.chunk()->type)) {
case android::RES_STRING_POOL_TYPE:
if (type_pool_.getError() == NO_INIT) {
- status_t err = type_pool_.setTo(
- parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
+ status_t err =
+ type_pool_.setTo(parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
if (err != NO_ERROR) {
context_->GetDiagnostics()->Error(DiagMessage(source_)
<< "corrupt type string pool in "
- << "ResTable_package: "
- << type_pool_.getError());
+ << "ResTable_package: " << type_pool_.getError());
return false;
}
} else if (key_pool_.getError() == NO_INIT) {
- status_t err = key_pool_.setTo(
- parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
+ status_t err =
+ key_pool_.setTo(parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
if (err != NO_ERROR) {
context_->GetDiagnostics()->Error(DiagMessage(source_)
<< "corrupt key string pool in "
- << "ResTable_package: "
- << key_pool_.getError());
+ << "ResTable_package: " << key_pool_.getError());
return false;
}
} else {
@@ -272,8 +264,8 @@
}
if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
- context_->GetDiagnostics()->Error(
- DiagMessage(source_) << "corrupt ResTable_package: " << parser.error());
+ context_->GetDiagnostics()->Error(DiagMessage(source_)
+ << "corrupt ResTable_package: " << parser.error());
return false;
}
@@ -286,22 +278,19 @@
bool BinaryResourceParser::ParseTypeSpec(const ResChunk_header* chunk) {
if (type_pool_.getError() != NO_ERROR) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "missing type string pool");
+ context_->GetDiagnostics()->Error(DiagMessage(source_) << "missing type string pool");
return false;
}
const ResTable_typeSpec* type_spec = ConvertTo<ResTable_typeSpec>(chunk);
if (!type_spec) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt ResTable_typeSpec chunk");
+ context_->GetDiagnostics()->Error(DiagMessage(source_) << "corrupt ResTable_typeSpec chunk");
return false;
}
if (type_spec->id == 0) {
context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "ResTable_typeSpec has invalid id: "
- << type_spec->id);
+ << "ResTable_typeSpec has invalid id: " << type_spec->id);
return false;
}
return true;
@@ -310,14 +299,12 @@
bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
const ResChunk_header* chunk) {
if (type_pool_.getError() != NO_ERROR) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "missing type string pool");
+ context_->GetDiagnostics()->Error(DiagMessage(source_) << "missing type string pool");
return false;
}
if (key_pool_.getError() != NO_ERROR) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "missing key string pool");
+ context_->GetDiagnostics()->Error(DiagMessage(source_) << "missing key string pool");
return false;
}
@@ -325,15 +312,13 @@
// a lot and has its own code to handle variable size.
const ResTable_type* type = ConvertTo<ResTable_type, kResTableTypeMinSize>(chunk);
if (!type) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt ResTable_type chunk");
+ context_->GetDiagnostics()->Error(DiagMessage(source_) << "corrupt ResTable_type chunk");
return false;
}
if (type->id == 0) {
context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "ResTable_type has invalid id: "
- << (int)type->id);
+ << "ResTable_type has invalid id: " << (int)type->id);
return false;
}
@@ -344,9 +329,9 @@
const ResourceType* parsed_type = ParseResourceType(type_str);
if (!parsed_type) {
- context_->GetDiagnostics()->Error(
- DiagMessage(source_) << "invalid type name '" << type_str
- << "' for type with ID " << (int)type->id);
+ context_->GetDiagnostics()->Error(DiagMessage(source_)
+ << "invalid type name '" << type_str << "' for type with ID "
+ << (int)type->id);
return false;
}
@@ -357,12 +342,10 @@
continue;
}
- const ResourceName name(
- package->name, *parsed_type,
- util::GetString(key_pool_, util::DeviceToHost32(entry->key.index)));
+ const ResourceName name(package->name, *parsed_type,
+ util::GetString(key_pool_, util::DeviceToHost32(entry->key.index)));
- const ResourceId res_id(package->id.value(), type->id,
- static_cast<uint16_t>(it.index()));
+ const ResourceId res_id(package->id.value(), type->id, static_cast<uint16_t>(it.index()));
std::unique_ptr<Value> resource_value;
if (entry->flags & ResTable_entry::FLAG_COMPLEX) {
@@ -377,10 +360,9 @@
}
if (!resource_value) {
- context_->GetDiagnostics()->Error(
- DiagMessage(source_) << "failed to parse value for resource " << name
- << " (" << res_id << ") with configuration '"
- << config << "'");
+ context_->GetDiagnostics()->Error(DiagMessage(source_)
+ << "failed to parse value for resource " << name << " ("
+ << res_id << ") with configuration '" << config << "'");
return false;
}
@@ -433,19 +415,19 @@
if (file_ref != nullptr) {
file_ref->file = files_->FindFile(*file_ref->path);
if (file_ref->file == nullptr) {
- context_->GetDiagnostics()->Warn(DiagMessage() << "resource " << name << " for config '"
- << config << "' is a file reference to '"
- << *file_ref->path
- << "' but no such path exists");
+ context_->GetDiagnostics()->Warn(DiagMessage()
+ << "resource " << name << " for config '" << config
+ << "' is a file reference to '" << *file_ref->path
+ << "' but no such path exists");
}
}
}
return item;
}
-std::unique_ptr<Value> BinaryResourceParser::ParseMapEntry(
- const ResourceNameRef& name, const ConfigDescription& config,
- const ResTable_map_entry* map) {
+std::unique_ptr<Value> BinaryResourceParser::ParseMapEntry(const ResourceNameRef& name,
+ const ConfigDescription& config,
+ const ResTable_map_entry* map) {
switch (name.type) {
case ResourceType::kStyle:
return ParseStyle(name, config, map);
@@ -470,9 +452,9 @@
return {};
}
-std::unique_ptr<Style> BinaryResourceParser::ParseStyle(
- const ResourceNameRef& name, const ConfigDescription& config,
- const ResTable_map_entry* map) {
+std::unique_ptr<Style> BinaryResourceParser::ParseStyle(const ResourceNameRef& name,
+ const ConfigDescription& config,
+ const ResTable_map_entry* map) {
std::unique_ptr<Style> style = util::make_unique<Style>();
if (util::DeviceToHost32(map->parent.ident) != 0) {
// The parent is a regular reference to a resource.
@@ -495,19 +477,16 @@
return style;
}
-std::unique_ptr<Attribute> BinaryResourceParser::ParseAttr(
- const ResourceNameRef& name, const ConfigDescription& config,
- const ResTable_map_entry* map) {
- const bool is_weak =
- (util::DeviceToHost16(map->flags) & ResTable_entry::FLAG_WEAK) != 0;
+std::unique_ptr<Attribute> BinaryResourceParser::ParseAttr(const ResourceNameRef& name,
+ const ConfigDescription& config,
+ const ResTable_map_entry* map) {
+ const bool is_weak = (util::DeviceToHost16(map->flags) & ResTable_entry::FLAG_WEAK) != 0;
std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(is_weak);
// First we must discover what type of attribute this is. Find the type mask.
- auto type_mask_iter =
- std::find_if(begin(map), end(map), [](const ResTable_map& entry) -> bool {
- return util::DeviceToHost32(entry.name.ident) ==
- ResTable_map::ATTR_TYPE;
- });
+ auto type_mask_iter = std::find_if(begin(map), end(map), [](const ResTable_map& entry) -> bool {
+ return util::DeviceToHost32(entry.name.ident) == ResTable_map::ATTR_TYPE;
+ });
if (type_mask_iter != end(map)) {
attr->type_mask = util::DeviceToHost32(type_mask_iter->value.data);
@@ -526,8 +505,7 @@
continue;
}
- if (attr->type_mask &
- (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) {
+ if (attr->type_mask & (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) {
Attribute::Symbol symbol;
symbol.value = util::DeviceToHost32(map_entry.value.data);
symbol.symbol = Reference(util::DeviceToHost32(map_entry.name.ident));
@@ -539,9 +517,9 @@
return attr;
}
-std::unique_ptr<Array> BinaryResourceParser::ParseArray(
- const ResourceNameRef& name, const ConfigDescription& config,
- const ResTable_map_entry* map) {
+std::unique_ptr<Array> BinaryResourceParser::ParseArray(const ResourceNameRef& name,
+ const ConfigDescription& config,
+ const ResTable_map_entry* map) {
std::unique_ptr<Array> array = util::make_unique<Array>();
for (const ResTable_map& map_entry : map) {
array->elements.push_back(ParseValue(name, config, map_entry.value));
@@ -549,9 +527,9 @@
return array;
}
-std::unique_ptr<Plural> BinaryResourceParser::ParsePlural(
- const ResourceNameRef& name, const ConfigDescription& config,
- const ResTable_map_entry* map) {
+std::unique_ptr<Plural> BinaryResourceParser::ParsePlural(const ResourceNameRef& name,
+ const ConfigDescription& config,
+ const ResTable_map_entry* map) {
std::unique_ptr<Plural> plural = util::make_unique<Plural>();
for (const ResTable_map& map_entry : map) {
std::unique_ptr<Item> item = ParseValue(name, config, map_entry.value);
diff --git a/tools/aapt2/unflatten/BinaryResourceParser.h b/tools/aapt2/format/binary/BinaryResourceParser.h
similarity index 73%
rename from tools/aapt2/unflatten/BinaryResourceParser.h
rename to tools/aapt2/format/binary/BinaryResourceParser.h
index c41ada0..dc9a384 100644
--- a/tools/aapt2/unflatten/BinaryResourceParser.h
+++ b/tools/aapt2/format/binary/BinaryResourceParser.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef AAPT_BINARY_RESOURCE_PARSER_H
-#define AAPT_BINARY_RESOURCE_PARSER_H
+#ifndef AAPT_FORMAT_BINARY_RESOURCEPARSER_H
+#define AAPT_FORMAT_BINARY_RESOURCEPARSER_H
#include <string>
@@ -32,25 +32,17 @@
struct SymbolTable_entry;
-/*
- * Parses a binary resource table (resources.arsc) and adds the entries
- * to a ResourceTable. This is different than the libandroidfw ResTable
- * in that it scans the table from top to bottom and doesn't require
- * support for random access. It is also able to parse non-runtime
- * chunks and types.
- */
+// Parses a binary resource table (resources.arsc) and adds the entries to a ResourceTable.
+// This is different than the libandroidfw ResTable in that it scans the table from top to bottom
+// and doesn't require support for random access.
class BinaryResourceParser {
public:
- /*
- * Creates a parser, which will read `len` bytes from `data`, and
- * add any resources parsed to `table`. `source` is for logging purposes.
- */
+ // Creates a parser, which will read `len` bytes from `data`, and add any resources parsed to
+ // `table`. `source` is for logging purposes.
BinaryResourceParser(IAaptContext* context, ResourceTable* table, const Source& source,
const void* data, size_t data_len, io::IFileCollection* files = nullptr);
- /*
- * Parses the binary resource table and returns true if successful.
- */
+ // Parses the binary resource table and returns true if successful.
bool Parse();
private:
@@ -59,31 +51,25 @@
bool ParseTable(const android::ResChunk_header* chunk);
bool ParsePackage(const android::ResChunk_header* chunk);
bool ParseTypeSpec(const android::ResChunk_header* chunk);
- bool ParseType(const ResourceTablePackage* package,
- const android::ResChunk_header* chunk);
+ bool ParseType(const ResourceTablePackage* package, const android::ResChunk_header* chunk);
bool ParseLibrary(const android::ResChunk_header* chunk);
std::unique_ptr<Item> ParseValue(const ResourceNameRef& name, const ConfigDescription& config,
const android::Res_value& value);
- std::unique_ptr<Value> ParseMapEntry(const ResourceNameRef& name,
- const ConfigDescription& config,
+ std::unique_ptr<Value> ParseMapEntry(const ResourceNameRef& name, const ConfigDescription& config,
const android::ResTable_map_entry* map);
- std::unique_ptr<Style> ParseStyle(const ResourceNameRef& name,
- const ConfigDescription& config,
+ std::unique_ptr<Style> ParseStyle(const ResourceNameRef& name, const ConfigDescription& config,
const android::ResTable_map_entry* map);
- std::unique_ptr<Attribute> ParseAttr(const ResourceNameRef& name,
- const ConfigDescription& config,
+ std::unique_ptr<Attribute> ParseAttr(const ResourceNameRef& name, const ConfigDescription& config,
const android::ResTable_map_entry* map);
- std::unique_ptr<Array> ParseArray(const ResourceNameRef& name,
- const ConfigDescription& config,
+ std::unique_ptr<Array> ParseArray(const ResourceNameRef& name, const ConfigDescription& config,
const android::ResTable_map_entry* map);
- std::unique_ptr<Plural> ParsePlural(const ResourceNameRef& name,
- const ConfigDescription& config,
+ std::unique_ptr<Plural> ParsePlural(const ResourceNameRef& name, const ConfigDescription& config,
const android::ResTable_map_entry* map);
/**
@@ -125,13 +111,10 @@
namespace android {
-/**
- * Iterator functionality for ResTable_map_entry.
- */
+// Iterator functionality for ResTable_map_entry.
inline const ResTable_map* begin(const ResTable_map_entry* map) {
- return (const ResTable_map*)((const uint8_t*)map +
- aapt::util::DeviceToHost32(map->size));
+ return (const ResTable_map*)((const uint8_t*)map + ::aapt::util::DeviceToHost32(map->size));
}
inline const ResTable_map* end(const ResTable_map_entry* map) {
@@ -140,4 +123,4 @@
} // namespace android
-#endif // AAPT_BINARY_RESOURCE_PARSER_H
+#endif // AAPT_FORMAT_BINARY_RESOURCEPARSER_H
diff --git a/tools/aapt2/flatten/ChunkWriter.h b/tools/aapt2/format/binary/ChunkWriter.h
similarity index 85%
rename from tools/aapt2/flatten/ChunkWriter.h
rename to tools/aapt2/format/binary/ChunkWriter.h
index 968d3ee..1892a29 100644
--- a/tools/aapt2/flatten/ChunkWriter.h
+++ b/tools/aapt2/format/binary/ChunkWriter.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef AAPT_FLATTEN_CHUNKWRITER_H
-#define AAPT_FLATTEN_CHUNKWRITER_H
+#ifndef AAPT_FORMAT_BINARY_CHUNKWRITER_H
+#define AAPT_FORMAT_BINARY_CHUNKWRITER_H
#include "android-base/macros.h"
#include "androidfw/ResourceTypes.h"
@@ -27,7 +27,8 @@
class ChunkWriter {
public:
- explicit inline ChunkWriter(BigBuffer* buffer) : buffer_(buffer) {}
+ explicit inline ChunkWriter(BigBuffer* buffer) : buffer_(buffer) {
+ }
ChunkWriter(ChunkWriter&&) = default;
ChunkWriter& operator=(ChunkWriter&&) = default;
@@ -46,11 +47,17 @@
return buffer_->NextBlock<T>(count);
}
- inline BigBuffer* buffer() { return buffer_; }
+ inline BigBuffer* buffer() {
+ return buffer_;
+ }
- inline android::ResChunk_header* chunk_header() { return header_; }
+ inline android::ResChunk_header* chunk_header() {
+ return header_;
+ }
- inline size_t size() { return buffer_->size() - start_size_; }
+ inline size_t size() {
+ return buffer_->size() - start_size_;
+ }
inline android::ResChunk_header* Finish() {
buffer_->Align4();
@@ -77,4 +84,4 @@
} // namespace aapt
-#endif /* AAPT_FLATTEN_CHUNKWRITER_H */
+#endif /* AAPT_FORMAT_BINARY_CHUNKWRITER_H */
diff --git a/tools/aapt2/unflatten/ResChunkPullParser.cpp b/tools/aapt2/format/binary/ResChunkPullParser.cpp
similarity index 92%
rename from tools/aapt2/unflatten/ResChunkPullParser.cpp
rename to tools/aapt2/format/binary/ResChunkPullParser.cpp
index 8d92bd9..fd6919d 100644
--- a/tools/aapt2/unflatten/ResChunkPullParser.cpp
+++ b/tools/aapt2/format/binary/ResChunkPullParser.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "unflatten/ResChunkPullParser.h"
+#include "format/binary/ResChunkPullParser.h"
#include <inttypes.h>
#include <cstddef>
@@ -44,9 +44,8 @@
if (event_ == Event::kStartDocument) {
current_chunk_ = data_;
} else {
- current_chunk_ =
- (const ResChunk_header*)(((const char*)current_chunk_) +
- util::DeviceToHost32(current_chunk_->size));
+ current_chunk_ = (const ResChunk_header*)(((const char*)current_chunk_) +
+ util::DeviceToHost32(current_chunk_->size));
}
const std::ptrdiff_t diff = (const char*)current_chunk_ - (const char*)data_;
diff --git a/tools/aapt2/unflatten/ResChunkPullParser.h b/tools/aapt2/format/binary/ResChunkPullParser.h
similarity index 64%
rename from tools/aapt2/unflatten/ResChunkPullParser.h
rename to tools/aapt2/format/binary/ResChunkPullParser.h
index 5827753..5ff1359 100644
--- a/tools/aapt2/unflatten/ResChunkPullParser.h
+++ b/tools/aapt2/format/binary/ResChunkPullParser.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef AAPT_RES_CHUNK_PULL_PARSER_H
-#define AAPT_RES_CHUNK_PULL_PARSER_H
+#ifndef AAPT_FORMAT_BINARY_RESCHUNKPULLPARSER_H
+#define AAPT_FORMAT_BINARY_RESCHUNKPULLPARSER_H
#include <string>
@@ -26,18 +26,13 @@
namespace aapt {
-/**
- * A pull parser, modeled after XmlPullParser, that reads
- * android::ResChunk_header structs from a block of data.
- *
- * An android::ResChunk_header specifies a type, headerSize,
- * and size. The pull parser will verify that the chunk's size
- * doesn't extend beyond the available data, and will iterate
- * over each chunk in the given block of data.
- *
- * Processing nested chunks is done by creating a new ResChunkPullParser
- * pointing to the data portion of a chunk.
- */
+// A pull parser, modeled after XmlPullParser, that reads android::ResChunk_header structs from a
+// block of data.
+// An android::ResChunk_header specifies a type, headerSize, and size. The pull parser will verify
+// that the chunk's size doesn't extend beyond the available data, and will iterate over each chunk
+// in the given block of data.
+// Processing nested chunks is done by creating a new ResChunkPullParser pointing to the data
+// portion of a chunk.
class ResChunkPullParser {
public:
enum class Event {
@@ -48,24 +43,18 @@
kChunk,
};
- /**
- * Returns false if the event is EndDocument or BadDocument.
- */
+ // Returns false if the event is EndDocument or BadDocument.
static bool IsGoodEvent(Event event);
- /**
- * Create a ResChunkPullParser to read android::ResChunk_headers
- * from the memory pointed to by data, of len bytes.
- */
+ // Create a ResChunkPullParser to read android::ResChunk_headers from the memory pointed to by
+ // data, of len bytes.
ResChunkPullParser(const void* data, size_t len);
Event event() const;
const std::string& error() const;
const android::ResChunk_header* chunk() const;
- /**
- * Move to the next android::ResChunk_header.
- */
+ // Move to the next android::ResChunk_header.
Event Next();
private:
@@ -86,15 +75,12 @@
return reinterpret_cast<const T*>(chunk);
}
-inline static const uint8_t* GetChunkData(
- const android::ResChunk_header* chunk) {
- return reinterpret_cast<const uint8_t*>(chunk) +
- util::DeviceToHost16(chunk->headerSize);
+inline static const uint8_t* GetChunkData(const android::ResChunk_header* chunk) {
+ return reinterpret_cast<const uint8_t*>(chunk) + util::DeviceToHost16(chunk->headerSize);
}
inline static uint32_t GetChunkDataLen(const android::ResChunk_header* chunk) {
- return util::DeviceToHost32(chunk->size) -
- util::DeviceToHost16(chunk->headerSize);
+ return util::DeviceToHost32(chunk->size) - util::DeviceToHost16(chunk->headerSize);
}
//
@@ -109,13 +95,16 @@
: event_(Event::kStartDocument),
data_(reinterpret_cast<const android::ResChunk_header*>(data)),
len_(len),
- current_chunk_(nullptr) {}
+ current_chunk_(nullptr) {
+}
inline ResChunkPullParser::Event ResChunkPullParser::event() const {
return event_;
}
-inline const std::string& ResChunkPullParser::error() const { return error_; }
+inline const std::string& ResChunkPullParser::error() const {
+ return error_;
+}
inline const android::ResChunk_header* ResChunkPullParser::chunk() const {
return current_chunk_;
@@ -123,4 +112,4 @@
} // namespace aapt
-#endif // AAPT_RES_CHUNK_PULL_PARSER_H
+#endif // AAPT_FORMAT_BINARY_RESCHUNKPULLPARSER_H
diff --git a/tools/aapt2/flatten/ResourceTypeExtensions.h b/tools/aapt2/format/binary/ResourceTypeExtensions.h
similarity index 75%
rename from tools/aapt2/flatten/ResourceTypeExtensions.h
rename to tools/aapt2/format/binary/ResourceTypeExtensions.h
index 6359b41..7f58df80 100644
--- a/tools/aapt2/flatten/ResourceTypeExtensions.h
+++ b/tools/aapt2/format/binary/ResourceTypeExtensions.h
@@ -14,18 +14,14 @@
* limitations under the License.
*/
-#ifndef AAPT_RESOURCE_TYPE_EXTENSIONS_H
-#define AAPT_RESOURCE_TYPE_EXTENSIONS_H
+#ifndef AAPT_FORMAT_BINARY_RESOURCETYPEEXTENSIONS_H
+#define AAPT_FORMAT_BINARY_RESOURCETYPEEXTENSIONS_H
#include "androidfw/ResourceTypes.h"
namespace aapt {
-/**
- * An alternative struct to use instead of ResTable_map_entry. This one is a
- * standard_layout
- * struct.
- */
+// An alternative struct to use instead of ResTable_map_entry. This one is a standard_layout struct.
struct ResTable_entry_ext {
android::ResTable_entry entry;
android::ResTable_ref parent;
@@ -34,4 +30,4 @@
} // namespace aapt
-#endif // AAPT_RESOURCE_TYPE_EXTENSIONS_H
+#endif // AAPT_FORMAT_BINARY_RESOURCETYPEEXTENSIONS_H
diff --git a/tools/aapt2/flatten/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
similarity index 93%
rename from tools/aapt2/flatten/TableFlattener.cpp
rename to tools/aapt2/format/binary/TableFlattener.cpp
index 097727c..57565a5 100644
--- a/tools/aapt2/flatten/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "flatten/TableFlattener.h"
+#include "format/binary/TableFlattener.h"
#include <algorithm>
#include <numeric>
@@ -28,8 +28,8 @@
#include "ResourceValues.h"
#include "SdkConstants.h"
#include "ValueVisitor.h"
-#include "flatten/ChunkWriter.h"
-#include "flatten/ResourceTypeExtensions.h"
+#include "format/binary/ChunkWriter.h"
+#include "format/binary/ResourceTypeExtensions.h"
#include "util/BigBuffer.h"
using namespace android;
@@ -81,7 +81,8 @@
using ValueVisitor::Visit;
MapFlattenVisitor(ResTable_entry_ext* out_entry, BigBuffer* buffer)
- : out_entry_(out_entry), buffer_(buffer) {}
+ : out_entry_(out_entry), buffer_(buffer) {
+ }
void Visit(Attribute* attr) override {
{
@@ -92,15 +93,13 @@
if (attr->min_int != std::numeric_limits<int32_t>::min()) {
Reference key = Reference(ResourceId(ResTable_map::ATTR_MIN));
- BinaryPrimitive val(Res_value::TYPE_INT_DEC,
- static_cast<uint32_t>(attr->min_int));
+ BinaryPrimitive val(Res_value::TYPE_INT_DEC, static_cast<uint32_t>(attr->min_int));
FlattenEntry(&key, &val);
}
if (attr->max_int != std::numeric_limits<int32_t>::max()) {
Reference key = Reference(ResourceId(ResTable_map::ATTR_MAX));
- BinaryPrimitive val(Res_value::TYPE_INT_DEC,
- static_cast<uint32_t>(attr->max_int));
+ BinaryPrimitive val(Res_value::TYPE_INT_DEC, static_cast<uint32_t>(attr->max_int));
FlattenEntry(&key, &val);
}
@@ -188,7 +187,9 @@
* Call this after visiting a Value. This will finish any work that
* needs to be done to prepare the entry.
*/
- void Finish() { out_entry_->count = util::HostToDevice32(entry_count_); }
+ void Finish() {
+ out_entry_->count = util::HostToDevice32(entry_count_);
+ }
private:
DISALLOW_COPY_AND_ASSIGN(MapFlattenVisitor);
@@ -223,7 +224,8 @@
diag_(context->GetDiagnostics()),
package_(package),
shared_libs_(shared_libs),
- use_sparse_entries_(use_sparse_entries) {}
+ use_sparse_entries_(use_sparse_entries) {
+ }
bool FlattenPackage(BigBuffer* buffer) {
ChunkWriter pkg_writer(buffer);
@@ -271,9 +273,9 @@
template <typename T, bool IsItem>
T* WriteEntry(FlatEntry* entry, BigBuffer* buffer) {
- static_assert(std::is_same<ResTable_entry, T>::value ||
- std::is_same<ResTable_entry_ext, T>::value,
- "T must be ResTable_entry or ResTable_entry_ext");
+ static_assert(
+ std::is_same<ResTable_entry, T>::value || std::is_same<ResTable_entry_ext, T>::value,
+ "T must be ResTable_entry or ResTable_entry_ext");
T* result = buffer->NextBlock<T>();
ResTable_entry* out_entry = (ResTable_entry*)result;
@@ -302,8 +304,7 @@
CHECK(item->Flatten(outValue)) << "flatten failed";
outValue->size = util::HostToDevice16(sizeof(*outValue));
} else {
- ResTable_entry_ext* out_entry =
- WriteEntry<ResTable_entry_ext, false>(entry, buffer);
+ ResTable_entry_ext* out_entry = WriteEntry<ResTable_entry_ext, false>(entry, buffer);
MapFlattenVisitor visitor(out_entry, buffer);
entry->value->Accept(&visitor);
visitor.Finish();
@@ -318,8 +319,7 @@
CHECK(num_total_entries <= std::numeric_limits<uint16_t>::max());
ChunkWriter type_writer(buffer);
- ResTable_type* type_header =
- type_writer.StartChunk<ResTable_type>(RES_TABLE_TYPE_TYPE);
+ ResTable_type* type_header = type_writer.StartChunk<ResTable_type>(RES_TABLE_TYPE_TYPE);
type_header->id = type->id.value();
type_header->config = config;
type_header->config.swapHtoD();
@@ -395,8 +395,7 @@
sorted_types.push_back(type.get());
}
- std::sort(sorted_types.begin(), sorted_types.end(),
- cmp_ids<ResourceTableType>);
+ std::sort(sorted_types.begin(), sorted_types.end(), cmp_ids<ResourceTableType>);
return sorted_types;
}
@@ -411,13 +410,11 @@
return sorted_entries;
}
- bool FlattenTypeSpec(ResourceTableType* type,
- std::vector<ResourceEntry*>* sorted_entries,
+ bool FlattenTypeSpec(ResourceTableType* type, std::vector<ResourceEntry*>* sorted_entries,
BigBuffer* buffer) {
ChunkWriter type_spec_writer(buffer);
ResTable_typeSpec* spec_header =
- type_spec_writer.StartChunk<ResTable_typeSpec>(
- RES_TABLE_TYPE_SPEC_TYPE);
+ type_spec_writer.StartChunk<ResTable_typeSpec>(RES_TABLE_TYPE_SPEC_TYPE);
spec_header->id = type->id.value();
if (sorted_entries->empty()) {
@@ -443,8 +440,7 @@
// Populate the config masks for this entry.
if (entry->symbol_status.state == SymbolState::kPublic) {
- config_masks[entry->id.value()] |=
- util::HostToDevice32(ResTable_typeSpec::SPEC_PUBLIC);
+ config_masks[entry->id.value()] |= util::HostToDevice32(ResTable_typeSpec::SPEC_PUBLIC);
}
const size_t config_count = entry->values.size();
diff --git a/tools/aapt2/flatten/TableFlattener.h b/tools/aapt2/format/binary/TableFlattener.h
similarity index 89%
rename from tools/aapt2/flatten/TableFlattener.h
rename to tools/aapt2/format/binary/TableFlattener.h
index 223aef8..88cbddf 100644
--- a/tools/aapt2/flatten/TableFlattener.h
+++ b/tools/aapt2/format/binary/TableFlattener.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef AAPT_FLATTEN_TABLEFLATTENER_H
-#define AAPT_FLATTEN_TABLEFLATTENER_H
+#ifndef AAPT_FORMAT_BINARY_TABLEFLATTENER_H
+#define AAPT_FORMAT_BINARY_TABLEFLATTENER_H
#include "android-base/macros.h"
@@ -40,7 +40,8 @@
class TableFlattener : public IResourceTableConsumer {
public:
explicit TableFlattener(const TableFlattenerOptions& options, BigBuffer* buffer)
- : options_(options), buffer_(buffer) {}
+ : options_(options), buffer_(buffer) {
+ }
bool Consume(IAaptContext* context, ResourceTable* table) override;
@@ -53,4 +54,4 @@
} // namespace aapt
-#endif /* AAPT_FLATTEN_TABLEFLATTENER_H */
+#endif /* AAPT_FORMAT_BINARY_TABLEFLATTENER_H */
diff --git a/tools/aapt2/flatten/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
similarity index 83%
rename from tools/aapt2/flatten/TableFlattener_test.cpp
rename to tools/aapt2/format/binary/TableFlattener_test.cpp
index 4fdb2ec..6d75973 100644
--- a/tools/aapt2/flatten/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#include "flatten/TableFlattener.h"
+#include "format/binary/TableFlattener.h"
#include "android-base/stringprintf.h"
#include "ResourceUtils.h"
#include "SdkConstants.h"
+#include "format/binary/BinaryResourceParser.h"
#include "test/Test.h"
-#include "unflatten/BinaryResourceParser.h"
#include "util/Util.h"
using namespace android;
@@ -34,10 +34,8 @@
class TableFlattenerTest : public ::testing::Test {
public:
void SetUp() override {
- context_ = test::ContextBuilder()
- .SetCompilationPackage("com.app.test")
- .SetPackageId(0x7f)
- .Build();
+ context_ =
+ test::ContextBuilder().SetCompilationPackage("com.app.test").SetPackageId(0x7f).Build();
}
::testing::AssertionResult Flatten(IAaptContext* context, const TableFlattenerOptions& options,
@@ -80,12 +78,10 @@
return ::testing::AssertionSuccess();
}
- ::testing::AssertionResult Exists(ResTable* table,
- const StringPiece& expected_name,
+ ::testing::AssertionResult Exists(ResTable* table, const StringPiece& expected_name,
const ResourceId& expected_id,
const ConfigDescription& expected_config,
- const uint8_t expected_data_type,
- const uint32_t expected_data,
+ const uint8_t expected_data_type, const uint32_t expected_data,
const uint32_t expected_spec_flags) {
const ResourceName expected_res_name = test::ParseNameOrDie(expected_name);
@@ -94,28 +90,26 @@
ResTable_config config;
Res_value val;
uint32_t spec_flags;
- if (table->getResource(expected_id.id, &val, false, 0, &spec_flags,
- &config) < 0) {
+ if (table->getResource(expected_id.id, &val, false, 0, &spec_flags, &config) < 0) {
return ::testing::AssertionFailure() << "could not find resource with";
}
if (expected_data_type != val.dataType) {
return ::testing::AssertionFailure()
<< "expected data type " << std::hex << (int)expected_data_type
- << " but got data type " << (int)val.dataType << std::dec
- << " instead";
+ << " but got data type " << (int)val.dataType << std::dec << " instead";
}
if (expected_data != val.data) {
return ::testing::AssertionFailure()
- << "expected data " << std::hex << expected_data
- << " but got data " << val.data << std::dec << " instead";
+ << "expected data " << std::hex << expected_data << " but got data " << val.data
+ << std::dec << " instead";
}
if (expected_spec_flags != spec_flags) {
return ::testing::AssertionFailure()
- << "expected specFlags " << std::hex << expected_spec_flags
- << " but got specFlags " << spec_flags << std::dec << " instead";
+ << "expected specFlags " << std::hex << expected_spec_flags << " but got specFlags "
+ << spec_flags << std::dec << " instead";
}
ResTable::resource_name actual_name;
@@ -127,16 +121,14 @@
if (!resName) {
return ::testing::AssertionFailure()
<< "expected name '" << expected_res_name << "' but got '"
- << StringPiece16(actual_name.package, actual_name.packageLen)
- << ":" << StringPiece16(actual_name.type, actual_name.typeLen)
- << "/" << StringPiece16(actual_name.name, actual_name.nameLen)
- << "'";
+ << StringPiece16(actual_name.package, actual_name.packageLen) << ":"
+ << StringPiece16(actual_name.type, actual_name.typeLen) << "/"
+ << StringPiece16(actual_name.name, actual_name.nameLen) << "'";
}
if (expected_config != config) {
- return ::testing::AssertionFailure() << "expected config '"
- << expected_config << "' but got '"
- << ConfigDescription(config) << "'";
+ return ::testing::AssertionFailure() << "expected config '" << expected_config
+ << "' but got '" << ConfigDescription(config) << "'";
}
return ::testing::AssertionSuccess();
}
@@ -152,57 +144,46 @@
.AddSimple("com.app.test:id/one", ResourceId(0x7f020000))
.AddSimple("com.app.test:id/two", ResourceId(0x7f020001))
.AddValue("com.app.test:id/three", ResourceId(0x7f020002),
- test::BuildReference("com.app.test:id/one",
- ResourceId(0x7f020000)))
+ test::BuildReference("com.app.test:id/one", ResourceId(0x7f020000)))
.AddValue("com.app.test:integer/one", ResourceId(0x7f030000),
- util::make_unique<BinaryPrimitive>(
- uint8_t(Res_value::TYPE_INT_DEC), 1u))
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 1u))
.AddValue("com.app.test:integer/one", test::ParseConfigOrDie("v1"),
ResourceId(0x7f030000),
- util::make_unique<BinaryPrimitive>(
- uint8_t(Res_value::TYPE_INT_DEC), 2u))
+ util::make_unique<BinaryPrimitive>(uint8_t(Res_value::TYPE_INT_DEC), 2u))
.AddString("com.app.test:string/test", ResourceId(0x7f040000), "foo")
- .AddString("com.app.test:layout/bar", ResourceId(0x7f050000),
- "res/layout/bar.xml")
+ .AddString("com.app.test:layout/bar", ResourceId(0x7f050000), "res/layout/bar.xml")
.Build();
ResTable res_table;
ASSERT_TRUE(Flatten(context_.get(), {}, table.get(), &res_table));
- EXPECT_TRUE(Exists(&res_table, "com.app.test:id/one", ResourceId(0x7f020000),
- {}, Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:id/one", ResourceId(0x7f020000), {},
+ Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
- EXPECT_TRUE(Exists(&res_table, "com.app.test:id/two", ResourceId(0x7f020001),
- {}, Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:id/two", ResourceId(0x7f020001), {},
+ Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
- EXPECT_TRUE(Exists(&res_table, "com.app.test:id/three",
- ResourceId(0x7f020002), {}, Res_value::TYPE_REFERENCE,
- 0x7f020000u, 0u));
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:id/three", ResourceId(0x7f020002), {},
+ Res_value::TYPE_REFERENCE, 0x7f020000u, 0u));
- EXPECT_TRUE(Exists(&res_table, "com.app.test:integer/one",
- ResourceId(0x7f030000), {}, Res_value::TYPE_INT_DEC, 1u,
- ResTable_config::CONFIG_VERSION));
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:integer/one", ResourceId(0x7f030000), {},
+ Res_value::TYPE_INT_DEC, 1u, ResTable_config::CONFIG_VERSION));
- EXPECT_TRUE(Exists(&res_table, "com.app.test:integer/one",
- ResourceId(0x7f030000), test::ParseConfigOrDie("v1"),
- Res_value::TYPE_INT_DEC, 2u,
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:integer/one", ResourceId(0x7f030000),
+ test::ParseConfigOrDie("v1"), Res_value::TYPE_INT_DEC, 2u,
ResTable_config::CONFIG_VERSION));
std::u16string foo_str = u"foo";
- ssize_t idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(),
- foo_str.size());
+ ssize_t idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size());
ASSERT_GE(idx, 0);
- EXPECT_TRUE(Exists(&res_table, "com.app.test:string/test",
- ResourceId(0x7f040000), {}, Res_value::TYPE_STRING,
- (uint32_t)idx, 0u));
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:string/test", ResourceId(0x7f040000), {},
+ Res_value::TYPE_STRING, (uint32_t)idx, 0u));
std::u16string bar_path = u"res/layout/bar.xml";
- idx = res_table.getTableStringBlock(0)->indexOfString(bar_path.data(),
- bar_path.size());
+ idx = res_table.getTableStringBlock(0)->indexOfString(bar_path.data(), bar_path.size());
ASSERT_GE(idx, 0);
- EXPECT_TRUE(Exists(&res_table, "com.app.test:layout/bar",
- ResourceId(0x7f050000), {}, Res_value::TYPE_STRING,
- (uint32_t)idx, 0u));
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:layout/bar", ResourceId(0x7f050000), {},
+ Res_value::TYPE_STRING, (uint32_t)idx, 0u));
}
TEST_F(TableFlattenerTest, FlattenEntriesWithGapsInIds) {
@@ -216,11 +197,10 @@
ResTable res_table;
ASSERT_TRUE(Flatten(context_.get(), {}, table.get(), &res_table));
- EXPECT_TRUE(Exists(&res_table, "com.app.test:id/one", ResourceId(0x7f020001),
- {}, Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
- EXPECT_TRUE(Exists(&res_table, "com.app.test:id/three",
- ResourceId(0x7f020003), {}, Res_value::TYPE_INT_BOOLEAN,
- 0u, 0u));
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:id/one", ResourceId(0x7f020001), {},
+ Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
+ EXPECT_TRUE(Exists(&res_table, "com.app.test:id/three", ResourceId(0x7f020003), {},
+ Res_value::TYPE_INT_BOOLEAN, 0u, 0u));
}
TEST_F(TableFlattenerTest, FlattenMinMaxAttributes) {
@@ -231,8 +211,7 @@
std::unique_ptr<ResourceTable> table =
test::ResourceTableBuilder()
.SetPackageId("android", 0x01)
- .AddValue("android:attr/foo", ResourceId(0x01010000),
- util::make_unique<Attribute>(attr))
+ .AddValue("android:attr/foo", ResourceId(0x01010000), util::make_unique<Attribute>(attr))
.Build();
ResourceTable result;
@@ -308,9 +287,12 @@
ASSERT_THAT(value, NotNull());
EXPECT_EQ(0u, value->value.data);
- ASSERT_THAT(test::GetValueForConfig<BinaryPrimitive>(&sparse_table, "android:string/foo_1", sparse_config), IsNull());
+ ASSERT_THAT(test::GetValueForConfig<BinaryPrimitive>(&sparse_table, "android:string/foo_1",
+ sparse_config),
+ IsNull());
- value = test::GetValueForConfig<BinaryPrimitive>(&sparse_table, "android:string/foo_4", sparse_config);
+ value = test::GetValueForConfig<BinaryPrimitive>(&sparse_table, "android:string/foo_4",
+ sparse_config);
ASSERT_THAT(value, NotNull());
EXPECT_EQ(4u, value->value.data);
}
diff --git a/tools/aapt2/flatten/XmlFlattener.cpp b/tools/aapt2/format/binary/XmlFlattener.cpp
similarity index 93%
rename from tools/aapt2/flatten/XmlFlattener.cpp
rename to tools/aapt2/format/binary/XmlFlattener.cpp
index b3b308a..f8f09ab 100644
--- a/tools/aapt2/flatten/XmlFlattener.cpp
+++ b/tools/aapt2/format/binary/XmlFlattener.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "flatten/XmlFlattener.h"
+#include "format/binary/XmlFlattener.h"
#include <algorithm>
#include <map>
@@ -26,8 +26,8 @@
#include "utils/misc.h"
#include "SdkConstants.h"
-#include "flatten/ChunkWriter.h"
-#include "flatten/ResourceTypeExtensions.h"
+#include "format/binary/ChunkWriter.h"
+#include "format/binary/ResourceTypeExtensions.h"
#include "xml/XmlDom.h"
using namespace android;
@@ -71,7 +71,8 @@
std::vector<StringFlattenDest> string_refs;
XmlFlattenerVisitor(BigBuffer* buffer, XmlFlattenerOptions options)
- : buffer_(buffer), options_(options) {}
+ : buffer_(buffer), options_(options) {
+ }
void Visit(xml::Text* node) override {
if (util::TrimWhitespace(node->text).empty()) {
@@ -152,15 +153,14 @@
private:
DISALLOW_COPY_AND_ASSIGN(XmlFlattenerVisitor);
- void AddString(const StringPiece& str, uint32_t priority,
- android::ResStringPool_ref* dest,
+ void AddString(const StringPiece& str, uint32_t priority, android::ResStringPool_ref* dest,
bool treat_empty_string_as_null = false) {
if (str.empty() && treat_empty_string_as_null) {
// Some parts of the runtime treat null differently than empty string.
dest->index = util::DeviceToHost32(-1);
} else {
- string_refs.push_back(StringFlattenDest{
- pool.MakeRef(str, StringPool::Context(priority)), dest});
+ string_refs.push_back(
+ StringFlattenDest{pool.MakeRef(str, StringPool::Context(priority)), dest});
}
}
@@ -208,8 +208,7 @@
uint16_t attribute_index = 1;
for (const xml::Attribute* xml_attr : filtered_attrs_) {
// Assign the indices for specific attributes.
- if (xml_attr->compiled_attribute &&
- xml_attr->compiled_attribute.value().id &&
+ if (xml_attr->compiled_attribute && xml_attr->compiled_attribute.value().id &&
xml_attr->compiled_attribute.value().id.value() == kIdAttr) {
flat_elem->idIndex = util::HostToDevice16(attribute_index);
} else if (xml_attr->namespace_uri.empty()) {
@@ -241,9 +240,8 @@
// Lookup the StringPool for this package and make the reference there.
const xml::AaptAttribute& aapt_attr = xml_attr->compiled_attribute.value();
- StringPool::Ref name_ref =
- package_pools[aapt_attr.id.value().package_id()].MakeRef(
- xml_attr->name, StringPool::Context(aapt_attr.id.value().id));
+ StringPool::Ref name_ref = package_pools[aapt_attr.id.value().package_id()].MakeRef(
+ xml_attr->name, StringPool::Context(aapt_attr.id.value().id));
// Add it to the list of strings to flatten.
AddString(name_ref, &flat_attr->name);
@@ -272,7 +270,7 @@
flat_attr->typedValue.dataType = android::Res_value::TYPE_STRING;
AddString(str_builder.ToString(), kLowPriority,
- (ResStringPool_ref*) &flat_attr->typedValue.data);
+ (ResStringPool_ref*)&flat_attr->typedValue.data);
}
flat_attr->typedValue.size = util::HostToDevice16(sizeof(flat_attr->typedValue));
diff --git a/tools/aapt2/flatten/XmlFlattener.h b/tools/aapt2/format/binary/XmlFlattener.h
similarity index 83%
rename from tools/aapt2/flatten/XmlFlattener.h
rename to tools/aapt2/format/binary/XmlFlattener.h
index 87557f2..6a48835 100644
--- a/tools/aapt2/flatten/XmlFlattener.h
+++ b/tools/aapt2/format/binary/XmlFlattener.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef AAPT_FLATTEN_XMLFLATTENER_H
-#define AAPT_FLATTEN_XMLFLATTENER_H
+#ifndef AAPT_FORMAT_BINARY_XMLFLATTENER_H
+#define AAPT_FORMAT_BINARY_XMLFLATTENER_H
#include "android-base/macros.h"
@@ -26,16 +26,15 @@
namespace aapt {
struct XmlFlattenerOptions {
- /**
- * Keep attribute raw string values along with typed values.
- */
+ // Keep attribute raw string values along with typed values.
bool keep_raw_values = false;
};
class XmlFlattener : public IXmlResourceConsumer {
public:
XmlFlattener(BigBuffer* buffer, XmlFlattenerOptions options)
- : buffer_(buffer), options_(options) {}
+ : buffer_(buffer), options_(options) {
+ }
bool Consume(IAaptContext* context, xml::XmlResource* resource) override;
@@ -50,4 +49,4 @@
} // namespace aapt
-#endif /* AAPT_FLATTEN_XMLFLATTENER_H */
+#endif /* AAPT_FORMAT_BINARY_XMLFLATTENER_H */
diff --git a/tools/aapt2/flatten/XmlFlattener_test.cpp b/tools/aapt2/format/binary/XmlFlattener_test.cpp
similarity index 98%
rename from tools/aapt2/flatten/XmlFlattener_test.cpp
rename to tools/aapt2/format/binary/XmlFlattener_test.cpp
index a57e317..0450f6c 100644
--- a/tools/aapt2/flatten/XmlFlattener_test.cpp
+++ b/tools/aapt2/format/binary/XmlFlattener_test.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "flatten/XmlFlattener.h"
+#include "format/binary/XmlFlattener.h"
#include "androidfw/ResourceTypes.h"
@@ -55,8 +55,7 @@
.Build();
}
- ::testing::AssertionResult Flatten(xml::XmlResource* doc,
- android::ResXMLTree* out_tree,
+ ::testing::AssertionResult Flatten(xml::XmlResource* doc, android::ResXMLTree* out_tree,
const XmlFlattenerOptions& options = {}) {
using namespace android; // For NO_ERROR on windows because it is a macro.
diff --git a/tools/aapt2/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
similarity index 98%
rename from tools/aapt2/proto/ProtoDeserialize.cpp
rename to tools/aapt2/format/proto/ProtoDeserialize.cpp
index dc13881..c14f09a 100644
--- a/tools/aapt2/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "proto/ProtoDeserialize.h"
+#include "format/proto/ProtoDeserialize.h"
#include "android-base/logging.h"
#include "android-base/macros.h"
@@ -699,11 +699,11 @@
} break;
default:
- LOG(FATAL) << "unknown compound value: " << (int) pb_compound_value.value_case();
+ LOG(FATAL) << "unknown compound value: " << (int)pb_compound_value.value_case();
break;
}
} else {
- LOG(FATAL) << "unknown value: " << (int) pb_value.value_case();
+ LOG(FATAL) << "unknown value: " << (int)pb_value.value_case();
return {};
}
@@ -764,7 +764,7 @@
} break;
default:
- LOG(FATAL) << "unknown item: " << (int) pb_item.value_case();
+ LOG(FATAL) << "unknown item: " << (int)pb_item.value_case();
break;
}
return {};
@@ -840,7 +840,7 @@
} break;
default:
- LOG(FATAL) << "unknown XmlNode " << (int) pb_child.node_case();
+ LOG(FATAL) << "unknown XmlNode " << (int)pb_child.node_case();
break;
}
}
diff --git a/tools/aapt2/proto/ProtoDeserialize.h b/tools/aapt2/format/proto/ProtoDeserialize.h
similarity index 95%
rename from tools/aapt2/proto/ProtoDeserialize.h
rename to tools/aapt2/format/proto/ProtoDeserialize.h
index 3d76ea4..c8a7199 100644
--- a/tools/aapt2/proto/ProtoDeserialize.h
+++ b/tools/aapt2/format/proto/ProtoDeserialize.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef AAPT_PROTO_PROTODESERIALIZE_H
-#define AAPT_PROTO_PROTODESERIALIZE_H
+#ifndef AAPT_FORMAT_PROTO_PROTODESERIALIZE_H
+#define AAPT_FORMAT_PROTO_PROTODESERIALIZE_H
#include "android-base/macros.h"
#include "androidfw/ResourceTypes.h"
@@ -75,4 +75,4 @@
} // namespace aapt
-#endif /* AAPT_PROTO_PROTODESERIALIZE_H */
+#endif /* AAPT_FORMAT_PROTO_PROTODESERIALIZE_H */
diff --git a/tools/aapt2/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
similarity index 99%
rename from tools/aapt2/proto/ProtoSerialize.cpp
rename to tools/aapt2/format/proto/ProtoSerialize.cpp
index d36d668..c0d3614 100644
--- a/tools/aapt2/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "proto/ProtoSerialize.h"
+#include "format/proto/ProtoSerialize.h"
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
diff --git a/tools/aapt2/proto/ProtoSerialize.h b/tools/aapt2/format/proto/ProtoSerialize.h
similarity index 95%
rename from tools/aapt2/proto/ProtoSerialize.h
rename to tools/aapt2/format/proto/ProtoSerialize.h
index 4bf7e1c..1694b16 100644
--- a/tools/aapt2/proto/ProtoSerialize.h
+++ b/tools/aapt2/format/proto/ProtoSerialize.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef AAPT_FLATTEN_TABLEPROTOSERIALIZER_H
-#define AAPT_FLATTEN_TABLEPROTOSERIALIZER_H
+#ifndef AAPT_FORMAT_PROTO_PROTOSERIALIZE_H
+#define AAPT_FORMAT_PROTO_PROTOSERIALIZE_H
#include "android-base/macros.h"
#include "google/protobuf/io/coded_stream.h"
@@ -86,4 +86,4 @@
} // namespace aapt
-#endif /* AAPT_FLATTEN_TABLEPROTOSERIALIZER_H */
+#endif /* AAPT_FORMAT_PROTO_PROTOSERIALIZE_H */
diff --git a/tools/aapt2/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
similarity index 99%
rename from tools/aapt2/proto/ProtoSerialize_test.cpp
rename to tools/aapt2/format/proto/ProtoSerialize_test.cpp
index b263aff..2154d5a 100644
--- a/tools/aapt2/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-#include "proto/ProtoSerialize.h"
+#include "format/proto/ProtoSerialize.h"
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
#include "ResourceUtils.h"
-#include "proto/ProtoDeserialize.h"
+#include "format/proto/ProtoDeserialize.h"
#include "test/Test.h"
using ::android::StringPiece;
diff --git a/tools/aapt2/io/Util.h b/tools/aapt2/io/Util.h
index ec1ddb8..02ee876 100644
--- a/tools/aapt2/io/Util.h
+++ b/tools/aapt2/io/Util.h
@@ -21,7 +21,7 @@
#include "google/protobuf/message_lite.h"
-#include "flatten/Archive.h"
+#include "format/Archive.h"
#include "io/File.h"
#include "io/Io.h"
#include "process/IResourceTableConsumer.h"
diff --git a/tools/aapt2/optimize/MultiApkGenerator.cpp b/tools/aapt2/optimize/MultiApkGenerator.cpp
index 8e4b82c..6803088 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator.cpp
@@ -27,8 +27,8 @@
#include "configuration/ConfigurationParser.h"
#include "filter/AbiFilter.h"
#include "filter/Filter.h"
-#include "flatten/Archive.h"
-#include "flatten/XmlFlattener.h"
+#include "format/Archive.h"
+#include "format/binary/XmlFlattener.h"
#include "optimize/VersionCollapser.h"
#include "process/IResourceTableConsumer.h"
#include "split/TableSplitter.h"
diff --git a/tools/aapt2/optimize/MultiApkGenerator_test.cpp b/tools/aapt2/optimize/MultiApkGenerator_test.cpp
index e8e6adc..c8f3524 100644
--- a/tools/aapt2/optimize/MultiApkGenerator_test.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator_test.cpp
@@ -25,8 +25,8 @@
#include "ResourceTable.h"
#include "configuration/ConfigurationParser.h"
#include "filter/Filter.h"
-#include "flatten/Archive.h"
-#include "flatten/TableFlattener.h"
+#include "format/Archive.h"
+#include "format/binary/TableFlattener.h"
#include "process/IResourceTableConsumer.h"
#include "test/Context.h"
#include "test/Test.h"
diff --git a/tools/aapt2/xml/XmlDom_test.cpp b/tools/aapt2/xml/XmlDom_test.cpp
index 6b97ae6..4ba0443 100644
--- a/tools/aapt2/xml/XmlDom_test.cpp
+++ b/tools/aapt2/xml/XmlDom_test.cpp
@@ -18,7 +18,7 @@
#include <string>
-#include "flatten/XmlFlattener.h"
+#include "format/binary/XmlFlattener.h"
#include "io/StringInputStream.h"
#include "test/Test.h"
diff --git a/tools/incident_report/generic_message.h b/tools/incident_report/generic_message.h
index df3f7b2..7c4ad34 100644
--- a/tools/incident_report/generic_message.h
+++ b/tools/incident_report/generic_message.h
@@ -25,7 +25,7 @@
/**
* Class to represent a protobuf Message, where we don't actually
* know what any of the fields are, just their type codes. In other
- * words, this loslessly stores a parsed protobuf object without
+ * words, this losslessly stores a parsed protobuf object without
* having the .proto file that generated it.
*/
class GenericMessage
diff --git a/tools/incident_report/main.cpp b/tools/incident_report/main.cpp
index 250d118..d4ad340 100644
--- a/tools/incident_report/main.cpp
+++ b/tools/incident_report/main.cpp
@@ -138,7 +138,6 @@
static void
print_value(Out* out, FieldDescriptor const* field, GenericMessage::Node const& node)
{
- uint32_t val32;
FieldDescriptor::Type type = field->type();
switch (node.type) {
@@ -160,23 +159,25 @@
break;
case GenericMessage::TYPE_VALUE64:
switch (type) {
- case FieldDescriptor::TYPE_FIXED64:
- case FieldDescriptor::TYPE_SFIXED64:
case FieldDescriptor::TYPE_DOUBLE:
out->printf("%f", *(double*)&node.value64);
break;
+ // Int32s here were added with addInt64 from a WIRETYPE_VARINT,
+ // even if the definition is for a 32 bit int.
case FieldDescriptor::TYPE_SINT32:
case FieldDescriptor::TYPE_INT32:
- val32 = (uint32_t)node.value32;
- out->printf("%d", val32);
+ out->printf("%d", node.value64);
break;
case FieldDescriptor::TYPE_INT64:
- case FieldDescriptor::TYPE_UINT32:
- val32 = (uint32_t)node.value32;
- out->printf("%u", val32);
- break;
- case FieldDescriptor::TYPE_UINT64:
case FieldDescriptor::TYPE_SINT64:
+ case FieldDescriptor::TYPE_SFIXED64:
+ out->printf("%lld", node.value64);
+ break;
+ case FieldDescriptor::TYPE_UINT32:
+ case FieldDescriptor::TYPE_UINT64:
+ case FieldDescriptor::TYPE_FIXED64:
+ out->printf("%u", node.value64);
+ break;
case FieldDescriptor::TYPE_BOOL:
if (node.value64) {
out->printf("true");
@@ -185,11 +186,15 @@
}
break;
case FieldDescriptor::TYPE_ENUM:
- out->printf("%s", field->enum_type()->FindValueByNumber((int)node.value64)
+ if (field->enum_type()->FindValueByNumber((int)node.value64) == NULL) {
+ out->printf("%lld", (int) node.value64);
+ } else {
+ out->printf("%s", field->enum_type()->FindValueByNumber((int)node.value64)
->name().c_str());
+ }
break;
default:
- out->printf("(unexpected value64 %ld (0x%x))", node.value64, node.value64);
+ out->printf("(unexpected value64 %lld (0x%x))", node.value64, node.value64);
break;
}
break;
@@ -224,22 +229,13 @@
out->printf("%s=", field->name().c_str());
if (repeated) {
if (it.first != it.second) {
- out->printf("[");
- if (type == FieldDescriptor::TYPE_MESSAGE
- || type == FieldDescriptor::TYPE_STRING
- || type == FieldDescriptor::TYPE_BYTES) {
- out->printf("\n");
- }
+ out->printf("[\n");
out->indent();
for (GenericMessage::const_iterator_pair it = message->find(fieldId);
it.first != it.second; it.first++) {
print_value(out, field, it.first->second);
- if (type == FieldDescriptor::TYPE_MESSAGE
- || type == FieldDescriptor::TYPE_STRING
- || type == FieldDescriptor::TYPE_BYTES) {
- out->printf("\n");
- }
+ out->printf("\n");
}
out->dedent();
@@ -335,7 +331,7 @@
}
id = field->number();
}
-
+
int pfd[2];
if (pipe(pfd) != 0) {
fprintf(stderr, "pipe failed: %s\n", strerror(errno));
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index a145327..6438631 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -790,6 +790,28 @@
/**
* @hide
+ * Returns true if this WiFi config is for an open network.
+ */
+ public boolean isOpenNetwork() {
+ final int cardinality = allowedKeyManagement.cardinality();
+ final boolean hasNoKeyMgmt = cardinality == 0
+ || (cardinality == 1 && allowedKeyManagement.get(KeyMgmt.NONE));
+
+ boolean hasNoWepKeys = true;
+ if (wepKeys != null) {
+ for (int i = 0; i < wepKeys.length; i++) {
+ if (wepKeys[i] != null) {
+ hasNoWepKeys = false;
+ break;
+ }
+ }
+ }
+
+ return hasNoKeyMgmt && hasNoWepKeys;
+ }
+
+ /**
+ * @hide
* Setting this value will force scan results associated with this configuration to
* be included in the bucket of networks that are externally scored.
* If not set, associated scan results will be treated as legacy saved networks and
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java
index 357f76e..9f73622 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java
@@ -20,7 +20,6 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.NetworkSpecifier;
-import android.net.wifi.RttManager;
import android.util.Log;
import dalvik.system.CloseGuard;
@@ -224,37 +223,6 @@
}
/**
- * Start a ranging operation with the specified peers. The peer IDs are obtained from an
- * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
- * byte[], java.util.List)} or
- * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
- * byte[])} operation - can
- * only range devices which are part of an ongoing discovery session.
- *
- * @param params RTT parameters - each corresponding to a specific peer ID (the array sizes
- * must be identical). The
- * {@link android.net.wifi.RttManager.RttParams#bssid} member must be set to
- * a peer ID - not to a MAC address.
- * @param listener The listener to receive the results of the ranging session.
- * @hide
- * [TODO: b/28847998 - track RTT API & visilibity]
- */
- public void startRanging(RttManager.RttParams[] params, RttManager.RttListener listener) {
- if (mTerminated) {
- Log.w(TAG, "startRanging: called on terminated session");
- return;
- }
-
- WifiAwareManager mgr = mMgr.get();
- if (mgr == null) {
- Log.w(TAG, "startRanging: called post GC on WifiAwareManager");
- return;
- }
-
- mgr.startRanging(mClientId, mSessionId, params, listener);
- }
-
- /**
* Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for
* an unencrypted WiFi Aware connection (link) to the specified peer. The
* {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
diff --git a/wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl b/wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl
index 30dd64d..b646567 100644
--- a/wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl
+++ b/wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl
@@ -17,7 +17,6 @@
package android.net.wifi.aware;
import android.net.wifi.aware.ConfigRequest;
-import android.net.wifi.RttManager;
/**
* Callback interface that WifiAwareManager implements
@@ -29,8 +28,4 @@
void onConnectSuccess(int clientId);
void onConnectFail(int reason);
void onIdentityChanged(in byte[] mac);
-
- void onRangingSuccess(int rangingId, in RttManager.ParcelableRttResults results);
- void onRangingFailure(int rangingId, int reason, in String description);
- void onRangingAborted(int rangingId);
}
diff --git a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
index 0f4910f..f33424b 100644
--- a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
+++ b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
@@ -24,7 +24,6 @@
import android.net.wifi.aware.PublishConfig;
import android.net.wifi.aware.SubscribeConfig;
import android.net.wifi.aware.Characteristics;
-import android.net.wifi.RttManager;
/**
* Interface that WifiAwareService implements
@@ -53,5 +52,4 @@
void sendMessage(int clientId, int discoverySessionId, int peerId, in byte[] message,
int messageId, int retryCount);
void terminateSession(int clientId, int discoverySessionId);
- int startRanging(int clientId, int discoverySessionId, in RttManager.ParcelableRttParams parms);
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index df0d9d2..ed6804d 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -26,7 +26,6 @@
import android.net.ConnectivityManager;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
-import android.net.wifi.RttManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -35,9 +34,6 @@
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.GuardedBy;
import libcore.util.HexEncoding;
@@ -45,7 +41,6 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.nio.BufferOverflowException;
-import java.util.Arrays;
import java.util.List;
/**
@@ -172,9 +167,6 @@
private final Object mLock = new Object(); // lock access to the following vars
- @GuardedBy("mLock")
- private SparseArray<RttManager.RttListener> mRangingListeners = new SparseArray<>();
-
/** @hide */
public WifiAwareManager(Context context, IWifiAwareManager service) {
mContext = context;
@@ -401,27 +393,6 @@
}
/** @hide */
- public void startRanging(int clientId, int sessionId, RttManager.RttParams[] params,
- RttManager.RttListener listener) {
- if (VDBG) {
- Log.v(TAG, "startRanging: clientId=" + clientId + ", sessionId=" + sessionId + ", "
- + "params=" + Arrays.toString(params) + ", listener=" + listener);
- }
-
- int rangingKey = 0;
- try {
- rangingKey = mService.startRanging(clientId, sessionId,
- new RttManager.ParcelableRttParams(params));
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
-
- synchronized (mLock) {
- mRangingListeners.put(rangingKey, listener);
- }
- }
-
- /** @hide */
public NetworkSpecifier createNetworkSpecifier(int clientId, int role, int sessionId,
PeerHandle peerHandle, @Nullable byte[] pmk, @Nullable String passphrase) {
if (VDBG) {
@@ -500,29 +471,12 @@
private static final int CALLBACK_CONNECT_SUCCESS = 0;
private static final int CALLBACK_CONNECT_FAIL = 1;
private static final int CALLBACK_IDENTITY_CHANGED = 2;
- private static final int CALLBACK_RANGING_SUCCESS = 3;
- private static final int CALLBACK_RANGING_FAILURE = 4;
- private static final int CALLBACK_RANGING_ABORTED = 5;
private final Handler mHandler;
private final WeakReference<WifiAwareManager> mAwareManager;
private final Binder mBinder;
private final Looper mLooper;
- RttManager.RttListener getAndRemoveRangingListener(int rangingId) {
- WifiAwareManager mgr = mAwareManager.get();
- if (mgr == null) {
- Log.w(TAG, "getAndRemoveRangingListener: called post GC");
- return null;
- }
-
- synchronized (mgr.mLock) {
- RttManager.RttListener listener = mgr.mRangingListeners.get(rangingId);
- mgr.mRangingListeners.delete(rangingId);
- return listener;
- }
- }
-
/**
* Constructs a {@link AttachCallback} using the specified looper.
* All callbacks will delivered on the thread of the specified looper.
@@ -567,37 +521,6 @@
identityChangedListener.onIdentityChanged((byte[]) msg.obj);
}
break;
- case CALLBACK_RANGING_SUCCESS: {
- RttManager.RttListener listener = getAndRemoveRangingListener(msg.arg1);
- if (listener == null) {
- Log.e(TAG, "CALLBACK_RANGING_SUCCESS rangingId=" + msg.arg1
- + ": no listener registered (anymore)");
- } else {
- listener.onSuccess(
- ((RttManager.ParcelableRttResults) msg.obj).mResults);
- }
- break;
- }
- case CALLBACK_RANGING_FAILURE: {
- RttManager.RttListener listener = getAndRemoveRangingListener(msg.arg1);
- if (listener == null) {
- Log.e(TAG, "CALLBACK_RANGING_SUCCESS rangingId=" + msg.arg1
- + ": no listener registered (anymore)");
- } else {
- listener.onFailure(msg.arg2, (String) msg.obj);
- }
- break;
- }
- case CALLBACK_RANGING_ABORTED: {
- RttManager.RttListener listener = getAndRemoveRangingListener(msg.arg1);
- if (listener == null) {
- Log.e(TAG, "CALLBACK_RANGING_SUCCESS rangingId=" + msg.arg1
- + ": no listener registered (anymore)");
- } else {
- listener.onAborted();
- }
- break;
- }
}
}
};
@@ -629,43 +552,6 @@
msg.obj = mac;
mHandler.sendMessage(msg);
}
-
- @Override
- public void onRangingSuccess(int rangingId, RttManager.ParcelableRttResults results) {
- if (VDBG) {
- Log.v(TAG, "onRangingSuccess: rangingId=" + rangingId + ", results=" + results);
- }
-
- Message msg = mHandler.obtainMessage(CALLBACK_RANGING_SUCCESS);
- msg.arg1 = rangingId;
- msg.obj = results;
- mHandler.sendMessage(msg);
- }
-
- @Override
- public void onRangingFailure(int rangingId, int reason, String description) {
- if (VDBG) {
- Log.v(TAG, "onRangingSuccess: rangingId=" + rangingId + ", reason=" + reason
- + ", description=" + description);
- }
-
- Message msg = mHandler.obtainMessage(CALLBACK_RANGING_FAILURE);
- msg.arg1 = rangingId;
- msg.arg2 = reason;
- msg.obj = description;
- mHandler.sendMessage(msg);
-
- }
-
- @Override
- public void onRangingAborted(int rangingId) {
- if (VDBG) Log.v(TAG, "onRangingAborted: rangingId=" + rangingId);
-
- Message msg = mHandler.obtainMessage(CALLBACK_RANGING_ABORTED);
- msg.arg1 = rangingId;
- mHandler.sendMessage(msg);
-
- }
}
private static class WifiAwareDiscoverySessionCallbackProxy extends
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 632cfaf..622dce6 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -18,6 +18,8 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
import android.os.Parcel;
import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
@@ -98,4 +100,73 @@
assertEquals(networkSelectionStatus.isNotRecommended(), copy.isNotRecommended());
}
+
+ @Test
+ public void testIsOpenNetwork_IsOpen_NullWepKeys() {
+ WifiConfiguration config = new WifiConfiguration();
+ config.allowedKeyManagement.clear();
+ config.wepKeys = null;
+
+ assertTrue(config.isOpenNetwork());
+ }
+
+ @Test
+ public void testIsOpenNetwork_IsOpen_ZeroLengthWepKeysArray() {
+ WifiConfiguration config = new WifiConfiguration();
+ config.allowedKeyManagement.clear();
+ config.wepKeys = new String[0];
+
+ assertTrue(config.isOpenNetwork());
+ }
+
+ @Test
+ public void testIsOpenNetwork_IsOpen_NullWepKeysArray() {
+ WifiConfiguration config = new WifiConfiguration();
+ config.allowedKeyManagement.clear();
+ config.wepKeys = new String[1];
+
+ assertTrue(config.isOpenNetwork());
+ }
+
+ @Test
+ public void testIsOpenNetwork_NotOpen_HasWepKeys() {
+ WifiConfiguration config = new WifiConfiguration();
+ config.allowedKeyManagement.clear();
+ config.wepKeys = new String[] {"test"};
+
+ assertFalse(config.isOpenNetwork());
+ }
+
+ @Test
+ public void testIsOpenNetwork_NotOpen_HasNullWepKeyFollowedByNonNullKey() {
+ WifiConfiguration config = new WifiConfiguration();
+ config.allowedKeyManagement.clear();
+ config.wepKeys = new String[] {null, null, "test"};
+
+ assertFalse(config.isOpenNetwork());
+ }
+
+ @Test
+ public void testIsOpenNetwork_NotOpen_HasAuthType() {
+ for (int keyMgmt = 0; keyMgmt < WifiConfiguration.KeyMgmt.strings.length; keyMgmt++) {
+ if (keyMgmt == WifiConfiguration.KeyMgmt.NONE) continue;
+ WifiConfiguration config = new WifiConfiguration();
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(keyMgmt);
+ config.wepKeys = null;
+
+ assertFalse("Open network reported when key mgmt was set to "
+ + WifiConfiguration.KeyMgmt.strings[keyMgmt], config.isOpenNetwork());
+ }
+ }
+
+ @Test
+ public void testIsOpenNetwork_NotOpen_HasAuthTypeNoneAndMore() {
+ WifiConfiguration config = new WifiConfiguration();
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+ config.wepKeys = null;
+
+ assertFalse(config.isOpenNetwork());
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index d9433c5..1aeeee3 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -845,88 +845,6 @@
}
/*
- * Ranging tests
- */
-
- /**
- * Validate ranging + success flow: (1) connect, (2) create a (publish) session, (3) start
- * ranging, (4) ranging success callback, (5) ranging aborted callback ignored (since
- * listener removed).
- */
- @Test
- public void testRangingCallbacks() throws Exception {
- final int clientId = 4565;
- final int sessionId = 123;
- final int rangingId = 3482;
- final ConfigRequest configRequest = new ConfigRequest.Builder().build();
- final PublishConfig publishConfig = new PublishConfig.Builder().build();
- final RttManager.RttParams rttParams = new RttManager.RttParams();
- rttParams.deviceType = RttManager.RTT_PEER_NAN;
- rttParams.bssid = Integer.toString(1234);
- final RttManager.RttResult rttResults = new RttManager.RttResult();
- rttResults.distance = 10;
-
- when(mockAwareService.startRanging(anyInt(), anyInt(), any())).thenReturn(rangingId);
-
- InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
- mockPublishSession, mockRttListener);
- ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
- WifiAwareSession.class);
- ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor
- .forClass(IWifiAwareEventCallback.class);
- ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
- .forClass(IWifiAwareDiscoverySessionCallback.class);
- ArgumentCaptor<PublishDiscoverySession> publishSession = ArgumentCaptor
- .forClass(PublishDiscoverySession.class);
- ArgumentCaptor<RttManager.ParcelableRttParams> rttParamCaptor = ArgumentCaptor
- .forClass(RttManager.ParcelableRttParams.class);
- ArgumentCaptor<RttManager.RttResult[]> rttResultsCaptor = ArgumentCaptor
- .forClass(RttManager.RttResult[].class);
-
- // (1) connect successfully
- mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
- inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
- eq(configRequest), eq(false));
- clientProxyCallback.getValue().onConnectSuccess(clientId);
- mMockLooper.dispatchAll();
- inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
- WifiAwareSession session = sessionCaptor.getValue();
-
- // (2) publish successfully
- session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
- inOrder.verify(mockAwareService).publish(eq(clientId), eq(publishConfig),
- sessionProxyCallback.capture());
- sessionProxyCallback.getValue().onSessionStarted(sessionId);
- mMockLooper.dispatchAll();
- inOrder.verify(mockSessionCallback).onPublishStarted(publishSession.capture());
-
- // (3) start ranging
- publishSession.getValue().startRanging(new RttManager.RttParams[]{rttParams},
- mockRttListener);
- inOrder.verify(mockAwareService).startRanging(eq(clientId), eq(sessionId),
- rttParamCaptor.capture());
- collector.checkThat("RttParams.deviceType", rttParams.deviceType,
- equalTo(rttParamCaptor.getValue().mParams[0].deviceType));
- collector.checkThat("RttParams.bssid", rttParams.bssid,
- equalTo(rttParamCaptor.getValue().mParams[0].bssid));
-
- // (4) ranging success callback
- clientProxyCallback.getValue().onRangingSuccess(rangingId,
- new RttManager.ParcelableRttResults(new RttManager.RttResult[] { rttResults }));
- mMockLooper.dispatchAll();
- inOrder.verify(mockRttListener).onSuccess(rttResultsCaptor.capture());
- collector.checkThat("RttResult.distance", rttResults.distance,
- equalTo(rttResultsCaptor.getValue()[0].distance));
-
- // (5) ranging aborted callback (should be ignored since listener cleared on first callback)
- clientProxyCallback.getValue().onRangingAborted(rangingId);
- mMockLooper.dispatchAll();
-
- verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService,
- mockPublishSession, mockRttListener);
- }
-
- /*
* Data-path tests
*/