Merge "AudioService: Make suspended apps lose audio focus"
diff --git a/Android.bp b/Android.bp
index 072007b..1ee7405 100644
--- a/Android.bp
+++ b/Android.bp
@@ -773,7 +773,7 @@
"android.hardware.vibrator-V1.2-java",
"android.hardware.vibrator-V1.3-java",
"android.hardware.wifi-V1.0-java-constants",
- "networkstack-aidl-interfaces-java",
+ "networkstack-aidl-framework-java",
"netd_aidl_parcelables-java",
"devicepolicyprotosnano",
],
@@ -896,7 +896,6 @@
"core/java/android/net/DhcpResultsParcelable.aidl",
"core/java/android/net/INetworkMonitor.aidl",
"core/java/android/net/INetworkMonitorCallbacks.aidl",
- "core/java/android/net/IIpMemoryStore.aidl",
"core/java/android/net/INetworkStackConnector.aidl",
"core/java/android/net/INetworkStackStatusCallback.aidl",
"core/java/android/net/InitialConfigurationParcelable.aidl",
@@ -915,6 +914,16 @@
"core/java/android/net/dhcp/IDhcpServerCallbacks.aidl",
"core/java/android/net/ip/IIpClient.aidl",
"core/java/android/net/ip/IIpClientCallbacks.aidl",
+ ],
+ api_dir: "aidl/networkstack",
+}
+
+aidl_interface {
+ name: "networkstack-aidl-framework",
+ local_include_dir: "core/java",
+ srcs: [
+ "core/java/android/net/TcpKeepalivePacketDataParcelable.aidl",
+ "core/java/android/net/IIpMemoryStore.aidl",
"core/java/android/net/ipmemorystore/**/*.aidl",
],
api_dir: "aidl/networkstack",
diff --git a/api/current.txt b/api/current.txt
index af8f53f..9cd33e6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2222,6 +2222,7 @@
field public static final int TextAppearance_WindowTitle = 16973907; // 0x1030053
field public static final int Theme = 16973829; // 0x1030005
field public static final int ThemeOverlay = 16974407; // 0x1030247
+ field public static final int ThemeOverlay_DeviceDefault_Accent_DayNight = 16974564; // 0x10302e4
field public static final int ThemeOverlay_Material = 16974408; // 0x1030248
field public static final int ThemeOverlay_Material_ActionBar = 16974409; // 0x1030249
field public static final int ThemeOverlay_Material_Dark = 16974411; // 0x103024b
@@ -2233,6 +2234,7 @@
field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
field public static final int Theme_Black_NoTitleBar_Fullscreen = 16973834; // 0x103000a
field public static final int Theme_DeviceDefault = 16974120; // 0x1030128
+ field public static final int Theme_DeviceDefault_DayNight = 16974563; // 0x10302e3
field public static final int Theme_DeviceDefault_Dialog = 16974126; // 0x103012e
field public static final int Theme_DeviceDefault_DialogWhenLarge = 16974134; // 0x1030136
field public static final int Theme_DeviceDefault_DialogWhenLarge_NoActionBar = 16974135; // 0x1030137
diff --git a/api/test-current.txt b/api/test-current.txt
index fecb07a..d91ad44 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -516,13 +516,20 @@
method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
method @Nullable public abstract String[] getNamesForUids(int[]);
method public abstract String getPermissionControllerPackageName();
+ method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS"}) public abstract int getPermissionFlags(String, String, @NonNull android.os.UserHandle);
method @NonNull public abstract String getServicesSystemSharedLibraryPackageName();
method @NonNull public abstract String getSharedSystemSharedLibraryPackageName();
method public String getWellbeingPackageName();
method @RequiresPermission("android.permission.GRANT_RUNTIME_PERMISSIONS") public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
+ method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS"}) public abstract void updatePermissionFlags(String, String, int, int, @NonNull android.os.UserHandle);
field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption";
+ field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40
+ field public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 8; // 0x8
+ field public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 128; // 0x80
+ field public static final int FLAG_PERMISSION_USER_FIXED = 2; // 0x2
+ field public static final int FLAG_PERMISSION_USER_SET = 1; // 0x1
field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
field public static final int MATCH_KNOWN_PACKAGES = 4202496; // 0x402000
field public static final String SYSTEM_SHARED_LIBRARY_SERVICES = "android.ext.services";
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 57c32c7..2632294d 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -303,6 +303,7 @@
DangerousPermissionState dangerous_permission_state = 10050;
TrainInfo train_info = 10051;
TimeZoneDataInfo time_zone_data_info = 10052;
+ SDCardInfo sdcard_info = 10053;
}
// DO NOT USE field numbers above 100,000 in AOSP.
@@ -3231,6 +3232,28 @@
optional int32 cycle_count = 1;
}
+/**
+ * Logs that an SD card is mounted and information about it, its type (public or private) and the
+ * size in bytes.
+ * Pulled from:
+ * StatsCompanionService
+ */
+
+message SDCardInfo {
+
+ enum Type {
+ UNKNOWN = 0;
+ TYPE_PUBLIC = 1;
+ TYPE_PRIVATE = 2;
+ OTHERS = 3;
+ }
+
+ // Type of the SD card: TYPE_PUBLIC if portable and TYPE_PRIVATE if internal.
+ optional Type type = 1;
+ // Total size of the sd card in bytes.
+ optional int64 size_bytes = 2;
+}
+
/*
* Logs when a connection becomes available and lost.
* Logged in StatsCompanionService.java
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index d70c851..1513834 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -237,6 +237,9 @@
// TimeZoneDataInfo.
{android::util::TIME_ZONE_DATA_INFO,
{.puller = new StatsCompanionServicePuller(android::util::TIME_ZONE_DATA_INFO)}},
+ // SDCardInfo
+ {android::util::SDCARD_INFO,
+ {.puller = new StatsCompanionServicePuller(android::util::SDCARD_INFO)}},
};
StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 5f778da..e55c964 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -71,6 +71,7 @@
import android.os.Looper;
import android.os.Parcelable;
import android.os.PersistableBundle;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.StrictMode;
@@ -2297,7 +2298,7 @@
public final void requestShowKeyboardShortcuts() {
Intent intent = new Intent(Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS);
intent.setPackage(KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME);
- sendBroadcastAsUser(intent, UserHandle.SYSTEM);
+ sendBroadcastAsUser(intent, Process.myUserHandle());
}
/**
@@ -2306,7 +2307,7 @@
public final void dismissKeyboardShortcutsHelper() {
Intent intent = new Intent(Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS);
intent.setPackage(KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME);
- sendBroadcastAsUser(intent, UserHandle.SYSTEM);
+ sendBroadcastAsUser(intent, Process.myUserHandle());
}
@Override
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 87bf5ed..f116e13 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -27,6 +27,7 @@
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
+import android.content.pm.ServiceInfo.ForegroundServiceType;
import android.content.res.Configuration;
import android.os.Build;
import android.os.IBinder;
@@ -735,7 +736,7 @@
* @see {@link android.content.pm.ServiceInfo} for the set of FOREGROUND_SERVICE_TYPE flags.
*/
public final void startForeground(int id, @NonNull Notification notification,
- int foregroundServiceType) {
+ @ForegroundServiceType int foregroundServiceType) {
try {
mActivityManager.setServiceForeground(
new ComponentName(this, mClassName), mToken, id,
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index b9f56b1..c12a92f 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -1129,7 +1129,11 @@
IBinder b = ServiceManager
.getService(Context.CONTENT_CAPTURE_MANAGER_SERVICE);
IContentCaptureManager service = IContentCaptureManager.Stub.asInterface(b);
- return new ContentCaptureManager(outerContext, service);
+ if (service != null) {
+ // When feature is disabled, we return a null manager to apps so the
+ // performance impact is practically zero
+ return new ContentCaptureManager(outerContext, service);
+ }
}
return null;
}});
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 94a2a3e..97efa01 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -465,8 +465,6 @@
mActivities.put(instanceId, eventType);
break;
case ACTIVITY_STOPPED:
- mActivities.put(instanceId, eventType);
- break;
case ACTIVITY_DESTROYED:
// remove activity from the map.
mActivities.delete(instanceId);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 36ffb0e..14e7725 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -295,8 +295,6 @@
void restoreDefaultApps(in byte[] backup, int userId);
byte[] getIntentFilterVerificationBackup(int userId);
void restoreIntentFilterVerification(in byte[] backup, int userId);
- byte[] getPermissionGrantBackup(int userId);
- void restorePermissionGrants(in byte[] backup, int userId);
/**
* Report the set of 'Home' activity candidates, plus (if any) which of them
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 3ea78df..0041921 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2943,6 +2943,7 @@
* @hide
*/
@SystemApi
+ @TestApi
public static final int FLAG_PERMISSION_USER_SET = 1 << 0;
/**
@@ -2953,6 +2954,7 @@
* @hide
*/
@SystemApi
+ @TestApi
public static final int FLAG_PERMISSION_USER_FIXED = 1 << 1;
/**
@@ -2976,6 +2978,7 @@
* @hide
*/
@SystemApi
+ @TestApi
public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 1 << 3;
/**
@@ -3005,6 +3008,7 @@
* @hide
*/
@SystemApi
+ @TestApi
public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 1 << 6;
/**
@@ -3014,6 +3018,7 @@
*
* @hide
*/
+ @TestApi
public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 1 << 7;
/**
@@ -3795,6 +3800,7 @@
* @hide
*/
@SystemApi
+ @TestApi
@RequiresPermission(anyOf = {
android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
@@ -3815,6 +3821,7 @@
* @hide
*/
@SystemApi
+ @TestApi
@RequiresPermission(anyOf = {
android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 60475de..4a2f800 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -151,6 +151,7 @@
* @hide
*/
@IntDef(flag = true, prefix = { "FOREGROUND_SERVICE_TYPE_" }, value = {
+ FOREGROUND_SERVICE_TYPE_MANIFEST,
FOREGROUND_SERVICE_TYPE_NONE,
FOREGROUND_SERVICE_TYPE_DATA_SYNC,
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK,
@@ -180,10 +181,10 @@
}
/**
- * Return the current foreground service type.
- * @return the current foreground service type.
+ * Return foreground service type specified in the manifest..
+ * @return foreground service type specified in the manifest.
*/
- public int getForegroundServiceType() {
+ public @ForegroundServiceType int getForegroundServiceType() {
return mForegroundServiceType;
}
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 89967c3..addfe3d 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -624,7 +624,7 @@
*
* <p>Needs to be called when canceling this task as it might be hung.
*/
- void interruptRead() {
+ void interruptWrite() {
IoUtils.closeQuietly(mLocalPipe);
}
@@ -806,18 +806,19 @@
@Override
public void run(@NonNull IPermissionController service) {
+ mBackupSender.execute(mBackup);
+
ParcelFileDescriptor remotePipe = mBackupSender.getRemotePipe();
try {
service.restoreRuntimePermissionBackup(mUser, remotePipe);
} catch (RemoteException e) {
Log.e(TAG, "Error sending runtime permission backup", e);
mBackupSender.cancel(false);
+ mBackupSender.interruptWrite();
} finally {
// Remote pipe end is duped by binder call. Local copy is not needed anymore
IoUtils.closeQuietly(remotePipe);
}
-
- mBackupSender.execute(mBackup);
}
}
diff --git a/core/java/android/permission/PermissionManagerInternal.java b/core/java/android/permission/PermissionManagerInternal.java
new file mode 100644
index 0000000..92dbab33
--- /dev/null
+++ b/core/java/android/permission/PermissionManagerInternal.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 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.permission;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.UserHandle;
+
+/**
+ * Internal interfaces to be used by other components within the system server.
+ *
+ * <p>Only for use within the system server.
+ *
+ * @hide
+ */
+public abstract class PermissionManagerInternal {
+ /**
+ * Get the state of the runtime permissions as xml file.
+ *
+ * @param user The user the data should be extracted for
+ *
+ * @return The state as a xml file
+ */
+ public abstract @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user);
+
+ /**
+ * Restore a permission state previously backed up via {@link #backupRuntimePermissions}.
+ *
+ * <p>If not all state can be restored, the un-restoreable state will be delayed and can be
+ * re-tried via {@link #restoreDelayedRuntimePermissions}.
+ *
+ * @param backup The state as an xml file
+ * @param user The user the data should be restored for
+ */
+ public abstract void restoreRuntimePermissions(@NonNull byte[] backup,
+ @NonNull UserHandle user);
+
+ /**
+ * Try to apply permission backup of a package that was previously not applied.
+ *
+ * @param packageName The package that is newly installed
+ * @param user The user the package is installed for
+ *
+ * @see #restoreRuntimePermissions
+ */
+ public abstract void restoreDelayedRuntimePermissions(@NonNull String packageName,
+ @NonNull UserHandle user);
+}
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 634443d..0157d26 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -39,15 +39,8 @@
import java.io.PrintWriter;
-/*
- * NOTE: all methods in this class should return right away, or do the real work in a handler
- * thread.
- *
- * Hence, the only field that must be thread-safe is mEnabled, which is called at the beginning
- * of every method.
- */
/**
- * TODO(b/123577059): add javadocs / implement
+ * TODO(b/123577059): add javadocs / mention it can be null
*/
@SystemService(Context.CONTENT_CAPTURE_MANAGER_SERVICE)
public final class ContentCaptureManager {
@@ -90,7 +83,7 @@
@NonNull
private final Context mContext;
- @Nullable
+ @NonNull
private final IContentCaptureManager mService;
// Flags used for starting session.
@@ -107,11 +100,11 @@
/** @hide */
public ContentCaptureManager(@NonNull Context context,
- @Nullable IContentCaptureManager service) {
- mContext = Preconditions.checkNotNull(context, "context cannot be null");
+ @NonNull IContentCaptureManager service) {
if (VERBOSE) Log.v(TAG, "Constructor for " + context.getPackageName());
+ mContext = Preconditions.checkNotNull(context, "context cannot be null");
+ mService = Preconditions.checkNotNull(service, "service cannot be null");
- mService = service;
// TODO(b/119220549): we might not even need a handler, as the IPCs are oneway. But if we
// do, then we should optimize it to run the tests after the Choreographer finishes the most
// important steps of the frame.
@@ -199,8 +192,6 @@
* </ul>
*/
public boolean isContentCaptureEnabled() {
- if (mService == null) return false;
-
final MainContentCaptureSession mainSession;
synchronized (mLock) {
mainSession = mMainSession;
@@ -242,8 +233,6 @@
@SystemApi
@TestApi
public boolean isContentCaptureFeatureEnabled() {
- if (mService == null) return false;
-
final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
final int resultCode;
try {
@@ -314,22 +303,21 @@
/** @hide */
public void dump(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.println("ContentCaptureManager");
+ final String prefix2 = prefix + " ";
synchronized (mLock) {
- pw.print(prefix); pw.println("ContentCaptureManager");
- pw.print(prefix); pw.print("isContentCaptureEnabled(): ");
+ pw.print(prefix2); pw.print("isContentCaptureEnabled(): ");
pw.println(isContentCaptureEnabled());
- pw.print(prefix); pw.print("Context: "); pw.println(mContext);
- pw.print(prefix); pw.print("User: "); pw.println(mContext.getUserId());
- if (mService != null) {
- pw.print(prefix); pw.print("Service: "); pw.println(mService);
- }
- pw.print(prefix); pw.print("Flags: "); pw.println(mFlags);
+ pw.print(prefix2); pw.print("Context: "); pw.println(mContext);
+ pw.print(prefix2); pw.print("User: "); pw.println(mContext.getUserId());
+ pw.print(prefix2); pw.print("Service: "); pw.println(mService);
+ pw.print(prefix2); pw.print("Flags: "); pw.println(mFlags);
if (mMainSession != null) {
- final String prefix2 = prefix + " ";
- pw.print(prefix); pw.println("Main session:");
- mMainSession.dump(prefix2, pw);
+ final String prefix3 = prefix2 + " ";
+ pw.print(prefix2); pw.println("Main session:");
+ mMainSession.dump(prefix3, pw);
} else {
- pw.print(prefix); pw.println("No sessions");
+ pw.print(prefix2); pw.println("No sessions");
}
}
}
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index d949f45..f0f2c49 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -105,14 +105,14 @@
* Interface to the system_server binder object - it's only used to start the session (and
* notify when the session is finished).
*/
- @Nullable // TODO(b/122959591): shoul never be null, we should make main session null instead
+ @NonNull
private final IContentCaptureManager mSystemServerInterface;
/**
* Direct interface to the service binder object - it's used to send the events, including the
* last ones (when the session is finished)
*/
- @Nullable
+ @NonNull
private IContentCaptureDirectManager mDirectServiceInterface;
@Nullable
private DeathRecipient mDirectServiceVulture;
@@ -140,7 +140,7 @@
/** @hide */
protected MainContentCaptureSession(@NonNull Context context,
@NonNull ContentCaptureManager manager, @NonNull Handler handler,
- @Nullable IContentCaptureManager systemServerInterface) {
+ @NonNull IContentCaptureManager systemServerInterface) {
mContext = context;
mManager = manager;
mHandler = handler;
@@ -193,8 +193,6 @@
}
try {
- if (mSystemServerInterface == null) return;
-
mSystemServerInterface.startSession(mApplicationToken, component, mId, flags,
new IResultReceiver.Stub() {
@Override
@@ -507,8 +505,6 @@
}
try {
- if (mSystemServerInterface == null) return;
-
mSystemServerInterface.finishSession(mId);
} catch (RemoteException e) {
Log.e(TAG, "Error destroying system-service session " + mId + " for "
@@ -628,12 +624,11 @@
@Override
void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+ super.dump(prefix, pw);
+
pw.print(prefix); pw.print("mContext: "); pw.println(mContext);
pw.print(prefix); pw.print("user: "); pw.println(mContext.getUserId());
- if (mSystemServerInterface != null) {
- pw.print(prefix); pw.print("mSystemServerInterface: ");
- pw.println(mSystemServerInterface);
- }
+ pw.print(prefix); pw.print("mSystemServerInterface: ");
if (mDirectServiceInterface != null) {
pw.print(prefix); pw.print("mDirectServiceInterface: ");
pw.println(mDirectServiceInterface);
@@ -667,8 +662,6 @@
}
pw.print(prefix); pw.println("flush history:");
mFlushHistory.reverseDump(/* fd= */ null, pw, /* args= */ null); pw.println();
-
- super.dump(prefix, pw);
}
/**
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index eef40e1..d037337 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -95,7 +95,7 @@
public static final int LENGTH_LONG = 1;
final Context mContext;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
final TN mTN;
@UnsupportedAppUsage
int mDuration;
@@ -354,7 +354,7 @@
}
private static class TN extends ITransientNotification.Stub {
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
private static final int SHOW = 0;
@@ -362,18 +362,18 @@
private static final int CANCEL = 2;
final Handler mHandler;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
int mGravity;
int mX;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
int mY;
float mHorizontalMargin;
float mVerticalMargin;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
View mView;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
View mNextView;
int mDuration;
diff --git a/core/java/com/android/server/backup/PermissionBackupHelper.java b/core/java/com/android/server/backup/PermissionBackupHelper.java
index c0ba181..c7c423b 100644
--- a/core/java/com/android/server/backup/PermissionBackupHelper.java
+++ b/core/java/com/android/server/backup/PermissionBackupHelper.java
@@ -16,11 +16,14 @@
package com.android.server.backup;
-import android.app.AppGlobals;
+import android.annotation.NonNull;
import android.app.backup.BlobBackupHelper;
-import android.content.pm.IPackageManager;
+import android.os.UserHandle;
+import android.permission.PermissionManagerInternal;
import android.util.Slog;
+import com.android.server.LocalServices;
+
public class PermissionBackupHelper extends BlobBackupHelper {
private static final String TAG = "PermissionBackup";
private static final boolean DEBUG = false;
@@ -31,24 +34,26 @@
// key under which the permission-grant state blob is committed to backup
private static final String KEY_PERMISSIONS = "permissions";
- private final int mUserId;
+ private final @NonNull UserHandle mUser;
+
+ private final @NonNull PermissionManagerInternal mPermissionManager;
public PermissionBackupHelper(int userId) {
super(STATE_VERSION, KEY_PERMISSIONS);
- mUserId = userId;
+ mUser = UserHandle.of(userId);
+ mPermissionManager = LocalServices.getService(PermissionManagerInternal.class);
}
@Override
protected byte[] getBackupPayload(String key) {
- IPackageManager pm = AppGlobals.getPackageManager();
if (DEBUG) {
Slog.d(TAG, "Handling backup of " + key);
}
try {
switch (key) {
case KEY_PERMISSIONS:
- return pm.getPermissionGrantBackup(mUserId);
+ return mPermissionManager.backupRuntimePermissions(mUser);
default:
Slog.w(TAG, "Unexpected backup key " + key);
@@ -61,14 +66,13 @@
@Override
protected void applyRestoredPayload(String key, byte[] payload) {
- IPackageManager pm = AppGlobals.getPackageManager();
if (DEBUG) {
Slog.d(TAG, "Handling restore of " + key);
}
try {
switch (key) {
case KEY_PERMISSIONS:
- pm.restorePermissionGrants(payload, mUserId);
+ mPermissionManager.restoreRuntimePermissions(payload, mUser);
break;
default:
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index af0b7c3..7406136 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -230,6 +230,7 @@
],
static_libs: [
+ "libasync_safe",
"libgif",
"libseccomp_policy",
"libgrallocusage",
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index a2ed7d3..bd998999 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -1918,7 +1918,6 @@
for (jint i = 0; i < nb; i++) {
deviceTypesVector.push_back((audio_devices_t) typesPtr[i]);
}
- env->ReleaseIntArrayElements(deviceTypes, typesPtr, 0);
// check each address is a string and add device type/address to list for device affinity
Vector<AudioDeviceTypeAddr> deviceVector;
@@ -1932,6 +1931,7 @@
AudioDeviceTypeAddr dev = AudioDeviceTypeAddr(typesPtr[i], address);
deviceVector.add(dev);
}
+ env->ReleaseIntArrayElements(deviceTypes, typesPtr, 0);
status_t status = AudioSystem::setUidDeviceAffinities((uid_t) uid, deviceVector);
return (jint) nativeToJavaStatus(status);
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index b36c85d..7b4e4ea 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -25,6 +25,8 @@
#define LOG_TAG "Zygote"
+#include <async_safe/log.h>
+
// sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc
#include <sys/mount.h>
#include <linux/fs.h>
@@ -303,27 +305,23 @@
int saved_errno = errno;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
- // Log process-death status that we care about. In general it is
- // not safe to call LOG(...) from a signal handler because of
- // possible reentrancy. However, we know a priori that the
- // current implementation of LOG() is safe to call from a SIGCHLD
- // handler in the zygote process. If the LOG() implementation
- // changes its locking strategy or its use of syscalls within the
- // lazy-init critical section, its use here may become unsafe.
+ // Log process-death status that we care about.
if (WIFEXITED(status)) {
- ALOGI("Process %d exited cleanly (%d)", pid, WEXITSTATUS(status));
+ async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG,
+ "Process %d exited cleanly (%d)", pid, WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
- ALOGI("Process %d exited due to signal (%d)", pid, WTERMSIG(status));
- if (WCOREDUMP(status)) {
- ALOGI("Process %d dumped core.", pid);
- }
+ async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG,
+ "Process %d exited due to signal %d (%s)%s", pid,
+ WTERMSIG(status), strsignal(WTERMSIG(status)),
+ WCOREDUMP(status) ? "; core dumped" : "");
}
// If the just-crashed process is the system_server, bring down zygote
// so that it is restarted by init and system server will be restarted
// from there.
if (pid == gSystemServerPid) {
- ALOGE("Exit zygote because system server (%d) has terminated", pid);
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Exit zygote because system server (pid %d) has terminated", pid);
kill(getpid(), SIGKILL);
}
@@ -336,14 +334,17 @@
// Note that we shouldn't consider ECHILD an error because
// the secondary zygote might have no children left to wait for.
if (pid < 0 && errno != ECHILD) {
- ALOGW("Zygote SIGCHLD error in waitpid: %s", strerror(errno));
+ async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG,
+ "Zygote SIGCHLD error in waitpid: %s", strerror(errno));
}
if (blastulas_removed > 0) {
if (write(gBlastulaPoolEventFD, &blastulas_removed, sizeof(blastulas_removed)) == -1) {
// If this write fails something went terribly wrong. We will now kill
// the zygote and let the system bring it back up.
- ALOGE("Zygote failed to write to blastula pool event FD: %s", strerror(errno));
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Zygote failed to write to blastula pool event FD: %s",
+ strerror(errno));
kill(getpid(), SIGKILL);
}
}
@@ -612,7 +613,7 @@
}
}
-static void CreatePkgSandbox(uid_t uid, const std::string& package_name, fail_fn_t fail_fn) {
+static void CreatePkgSandboxTarget(uid_t uid, const std::string& package_name, fail_fn_t fail_fn) {
// Create /mnt/user/0/package/<package-name>
userid_t user_id = multiuser_get_user_id(uid);
std::string pkg_sandbox_dir = StringPrintf("/mnt/user/%d", user_id);
@@ -622,7 +623,7 @@
CreateDir(pkg_sandbox_dir, 0700, AID_ROOT, AID_ROOT, fail_fn);
StringAppendF(&pkg_sandbox_dir, "/%s", package_name.c_str());
- CreateDir(pkg_sandbox_dir, 0700, AID_ROOT, AID_ROOT, fail_fn);
+ CreateDir(pkg_sandbox_dir, 0755, uid, uid, fail_fn);
}
static void BindMount(const std::string& sourceDir, const std::string& targetDir,
@@ -642,29 +643,98 @@
fail_fn_t fail_fn) {
std::string mntSourceDir = StringPrintf("%s/Android/%s/%s",
mntSourceRoot.c_str(), dirName, packageName.c_str());
- CreateDir(mntSourceDir, 0755, uid, uid, fail_fn);
std::string mntTargetDir = StringPrintf("%s/Android/%s/%s",
mntTargetRoot.c_str(), dirName, packageName.c_str());
- CreateDir(mntTargetDir, 0755, uid, uid, fail_fn);
BindMount(mntSourceDir, mntTargetDir, fail_fn);
}
-
-static void createPkgSpecificDirRoots(const std::string& parentDir,
- bool createSandbox,
- mode_t mode, uid_t uid, gid_t gid,
- fail_fn_t fail_fn) {
- std::string androidDir = StringPrintf("%s/Android", parentDir.c_str());
- CreateDir(androidDir, mode, uid, gid, fail_fn);
- std::vector<std::string> dirs = {"data", "media", "obb"};
- if (createSandbox) {
- dirs.push_back("sandbox");
+static void CreateSubDirs(int dirfd, const std::string& parentDirPath,
+ const std::vector<std::string>& subDirs,
+ fail_fn_t fail_fn) {
+ for (auto& dirName : subDirs) {
+ struct stat sb;
+ if (TEMP_FAILURE_RETRY(fstatat(dirfd, dirName.c_str(), &sb, 0)) == 0) {
+ if (S_ISDIR(sb.st_mode)) {
+ continue;
+ } else if (TEMP_FAILURE_RETRY(unlinkat(dirfd, dirName.c_str(), 0)) == -1) {
+ fail_fn(CREATE_ERROR("Failed to unlinkat on %s/%s: %s",
+ parentDirPath.c_str(), dirName.c_str(), strerror(errno)));
+ }
+ } else if (errno != ENOENT) {
+ fail_fn(CREATE_ERROR("Failed to fstatat on %s/%s: %s",
+ parentDirPath.c_str(), dirName.c_str(), strerror(errno)));
+ }
+ if (TEMP_FAILURE_RETRY(mkdirat(dirfd, dirName.c_str(), 0700)) == -1) {
+ fail_fn(CREATE_ERROR("Failed to mkdirat on %s/%s: %s",
+ parentDirPath.c_str(), dirName.c_str(), strerror(errno)));
+ }
}
- for (auto& dir : dirs) {
- std::string path = StringPrintf("%s/%s", androidDir.c_str(), dir.c_str());
- CreateDir(path, mode, uid, gid, fail_fn);
+}
+
+static void EnsurePkgSpecificDirs(const std::string& path,
+ const std::vector<std::string>& packageNames,
+ bool createSandboxDir,
+ fail_fn_t fail_fn) {
+ std::string androidDir = StringPrintf("%s/Android", path.c_str());
+ android::base::unique_fd androidFd(
+ open(androidDir.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
+ if (androidFd.get() < 0) {
+ if (errno == ENOENT || errno == ENOTDIR) {
+ if (errno == ENOTDIR && TEMP_FAILURE_RETRY(unlink(androidDir.c_str())) == -1) {
+ fail_fn(CREATE_ERROR("Failed to unlink %s: %s",
+ androidDir.c_str(), strerror(errno)));
+ }
+ if (TEMP_FAILURE_RETRY(mkdir(androidDir.c_str(), 0700)) == -1) {
+ fail_fn(CREATE_ERROR("Failed to mkdir %s: %s",
+ androidDir.c_str(), strerror(errno)));
+ }
+ androidFd.reset(open(androidDir.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
+ }
+
+ if (androidFd.get() < 0) {
+ fail_fn(CREATE_ERROR("Failed to open %s: %s", androidDir.c_str(), strerror(errno)));
+ }
+ }
+
+ std::vector<std::string> dataMediaObbDirs = {"data", "media", "obb"};
+ if (createSandboxDir) {
+ dataMediaObbDirs.push_back("sandbox");
+ }
+ CreateSubDirs(androidFd.get(), androidDir, dataMediaObbDirs, fail_fn);
+ if (createSandboxDir) {
+ dataMediaObbDirs.pop_back();
+ }
+ for (auto& dirName : dataMediaObbDirs) {
+ std::string dataDir = StringPrintf("%s/%s", androidDir.c_str(), dirName.c_str());
+ android::base::unique_fd dataFd(
+ openat(androidFd, dirName.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
+ if (dataFd.get() < 0) {
+ fail_fn(CREATE_ERROR("Failed to openat %s/%s: %s",
+ androidDir.c_str(), dirName.c_str(), strerror(errno)));
+ }
+ CreateSubDirs(dataFd.get(), dataDir, packageNames, fail_fn);
+ }
+}
+
+static void CreatePkgSandboxSource(const std::string& sandboxSource, fail_fn_t fail_fn) {
+
+ struct stat sb;
+ if (TEMP_FAILURE_RETRY(stat(sandboxSource.c_str(), &sb)) == 0) {
+ if (S_ISDIR(sb.st_mode)) {
+ return;
+ } else if (TEMP_FAILURE_RETRY(unlink(sandboxSource.c_str())) == -1) {
+ fail_fn(CREATE_ERROR("Failed to unlink %s: %s",
+ sandboxSource.c_str(), strerror(errno)));
+ }
+ } else if (errno != ENOENT) {
+ fail_fn(CREATE_ERROR("Failed to stat %s: %s",
+ sandboxSource.c_str(), strerror(errno)));
+ }
+ if (TEMP_FAILURE_RETRY(mkdir(sandboxSource.c_str(), 0700)) == -1) {
+ fail_fn(CREATE_ERROR("Failed to mkdir %s: %s",
+ sandboxSource.c_str(), strerror(errno)));
}
}
@@ -680,21 +750,21 @@
StringAppendF(&mntTarget, "/%d", userId);
}
- if (TEMP_FAILURE_RETRY(access(mntSource.c_str(), F_OK)) < 0) {
+ if (TEMP_FAILURE_RETRY(access(mntSource.c_str(), F_OK)) == -1) {
ALOGE("Can't access %s: %s", mntSource.c_str(), strerror(errno));
continue;
}
- // Create /mnt/runtime/write/emulated/0/Android/{data,media,obb,sandbox}
- createPkgSpecificDirRoots(mntSource, true, 0700, AID_ROOT, AID_ROOT, fail_fn);
+ // Ensure /mnt/runtime/write/emulated/0/Android/{data,media,obb}
+ EnsurePkgSpecificDirs(mntSource, packageNames, true, fail_fn);
std::string sandboxSource = StringPrintf("%s/Android/sandbox/%s",
mntSource.c_str(), sandboxId.c_str());
- CreateDir(sandboxSource, 0755, uid, uid, fail_fn);
+ CreatePkgSandboxSource(sandboxSource, fail_fn);
BindMount(sandboxSource, mntTarget, fail_fn);
- // Create /storage/emulated/0/Android/{data,media,obb}
- createPkgSpecificDirRoots(mntTarget, false, 0755, uid, uid, fail_fn);
+ // Ensure /storage/emulated/0/Android/{data,media,obb}
+ EnsurePkgSpecificDirs(mntTarget, packageNames, false, fail_fn);
for (auto& package : packageNames) {
MountPkgSpecificDir(mntSource, mntTarget, package, uid, "data", fail_fn);
MountPkgSpecificDir(mntSource, mntTarget, package, uid, "media", fail_fn);
@@ -775,15 +845,14 @@
userid_t user_id = multiuser_get_user_id(uid);
std::string pkgSandboxDir =
StringPrintf("/mnt/user/%d/package/%s", user_id, package_name.c_str());
- struct stat sb;
bool sandboxAlreadyCreated = true;
- if (TEMP_FAILURE_RETRY(lstat(pkgSandboxDir.c_str(), &sb)) == -1) {
+ if (TEMP_FAILURE_RETRY(access(pkgSandboxDir.c_str(), F_OK)) == -1) {
if (errno == ENOENT) {
ALOGD("Sandbox not yet created for %s", pkgSandboxDir.c_str());
sandboxAlreadyCreated = false;
- CreatePkgSandbox(uid, package_name, fail_fn);
+ CreatePkgSandboxTarget(uid, package_name, fail_fn);
} else {
- fail_fn(CREATE_ERROR("Failed to lstat %s: %s",
+ fail_fn(CREATE_ERROR("Failed to access %s: %s",
pkgSandboxDir.c_str(), strerror(errno)));
}
}
@@ -794,7 +863,7 @@
pkgSandboxDir.c_str(), strerror(errno)));
}
- if (access("/storage/obb_mount", F_OK) == 0) {
+ if (TEMP_FAILURE_RETRY(access("/storage/obb_mount", F_OK)) == 0) {
if (mount_mode != MOUNT_EXTERNAL_INSTALLER) {
remove("/storage/obb_mount");
}
diff --git a/core/res/res/values-night/themes_device_defaults.xml b/core/res/res/values-night/themes_device_defaults.xml
index 949c12e..0721f6f 100644
--- a/core/res/res/values-night/themes_device_defaults.xml
+++ b/core/res/res/values-night/themes_device_defaults.xml
@@ -65,4 +65,7 @@
<style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.DeviceDefault.Dialog.Alert" />
<style name="Theme.DeviceDefault.DayNight" parent="Theme.DeviceDefault" />
+
+ <style name="ThemeOverlay.DeviceDefault.Accent.DayNight"
+ parent="@style/ThemeOverlay.DeviceDefault.Accent" />
</resources>
\ No newline at end of file
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 5e65605..3580dd4 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2951,6 +2951,8 @@
<public-group type="style" first-id="0x010302e2">
<!-- @hide @SystemApi -->
<public name="Theme.DeviceDefault.DocumentsUI" />
+ <public name="Theme.DeviceDefault.DayNight" />
+ <public name="ThemeOverlay.DeviceDefault.Accent.DayNight" />
</public-group>
<public-group type="id" first-id="0x01020046">
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 1603508..194c86c 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -1652,6 +1652,7 @@
<style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar" />
+ <!-- DeviceDefault theme for day/night activities. -->
<style name="Theme.DeviceDefault.DayNight" parent="Theme.DeviceDefault.Light" />
<!-- Theme used for the intent picker activity. -->
@@ -1697,6 +1698,10 @@
<item name="colorAccent">@color/accent_device_default_light</item>
</style>
+ <!-- Theme overlay that replaces colorAccent with the colorAccent from {@link #Theme_DeviceDefault_DayNight}. -->
+ <style name="ThemeOverlay.DeviceDefault.Accent.DayNight"
+ parent="@style/ThemeOverlay.DeviceDefault.Accent.Light" />
+
<style name="ThemeOverlay.DeviceDefault.Dark.ActionBar.Accent" parent="ThemeOverlay.Material.Dark.ActionBar">
<item name="colorAccent">@color/accent_device_default_dark</item>
</style>
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index aa29174..3dc884e 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -17,7 +17,6 @@
package android.security.keystore;
import android.security.Credentials;
-import android.security.GateKeeper;
import android.security.KeyStore;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
@@ -204,7 +203,12 @@
}
}
}
-
+ if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_3DES) {
+ if (mKeySizeBits != 168) {
+ throw new InvalidAlgorithmParameterException(
+ "3DES key size must be 168 bits.");
+ }
+ }
if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
if (mKeySizeBits < 64) {
throw new InvalidAlgorithmParameterException(
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 742813e..875b90b 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1647,6 +1647,10 @@
// The overlay must reside of the product partition or must have existed on the product
// partition before an upgrade to overlay these resources.
POLICY_PRODUCT_PARTITION = 0x00000008,
+
+ // The overlay must be signed with the same signature as the actor of the target resource,
+ // which can be separate or the same as the target package with the resource.
+ POLICY_SIGNATURE = 0x00000010,
};
uint32_t policy_flags;
diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java
index ad25a06..5f324f7 100644
--- a/media/java/android/media/MediaHTTPConnection.java
+++ b/media/java/android/media/MediaHTTPConnection.java
@@ -16,6 +16,8 @@
package android.media;
+import static android.media.MediaPlayer.MEDIA_ERROR_UNSUPPORTED;
+
import android.annotation.UnsupportedAppUsage;
import android.net.NetworkUtils;
import android.os.IBinder;
@@ -23,21 +25,19 @@
import android.util.Log;
import java.io.BufferedInputStream;
-import java.io.InputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.net.CookieHandler;
-import java.net.CookieManager;
-import java.net.Proxy;
-import java.net.URL;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.NoRouteToHostException;
import java.net.ProtocolException;
+import java.net.Proxy;
+import java.net.URL;
import java.net.UnknownServiceException;
import java.util.HashMap;
import java.util.Map;
-
-import static android.media.MediaPlayer.MEDIA_ERROR_UNSUPPORTED;
+import java.util.concurrent.atomic.AtomicBoolean;
/** @hide */
public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
@@ -67,6 +67,7 @@
// from com.squareup.okhttp.internal.http
private final static int HTTP_TEMP_REDIRECT = 307;
private final static int MAX_REDIRECTS = 20;
+ private AtomicBoolean mIsConnected = new AtomicBoolean(false);
@UnsupportedAppUsage
public MediaHTTPConnection() {
@@ -90,6 +91,7 @@
mAllowCrossDomainRedirect = true;
mURL = new URL(uri);
mHeaders = convertHeaderStringToMap(headers);
+ mIsConnected.set(true);
} catch (MalformedURLException e) {
return null;
}
@@ -140,7 +142,14 @@
@Override
@UnsupportedAppUsage
public void disconnect() {
- teardownConnection();
+ if (mIsConnected.getAndSet(false)) {
+ (new Thread() {
+ @Override
+ public void run() {
+ teardownConnection();
+ }
+ }).start();
+ }
mHeaders = null;
mURL = null;
}
@@ -325,7 +334,14 @@
@Override
@UnsupportedAppUsage
public int readAt(long offset, int size) {
- return native_readAt(offset, size);
+ if (!mIsConnected.get()) {
+ return -1;
+ }
+ int result = native_readAt(offset, size);
+ if (!mIsConnected.get()) {
+ return -1;
+ }
+ return result;
}
private int readAt(long offset, byte[] data, int size) {
diff --git a/packages/CaptivePortalLogin/Android.bp b/packages/CaptivePortalLogin/Android.bp
index 7acdfa1..a71977f 100644
--- a/packages/CaptivePortalLogin/Android.bp
+++ b/packages/CaptivePortalLogin/Android.bp
@@ -18,7 +18,7 @@
name: "CaptivePortalLogin",
srcs: ["src/**/*.java"],
sdk_version: "system_current",
- certificate: "platform",
+ certificate: "networkstack",
static_libs: [
"androidx.legacy_legacy-support-v4",
"metrics-constants-protos",
diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml
index e15dca0..0894ee5 100644
--- a/packages/CaptivePortalLogin/AndroidManifest.xml
+++ b/packages/CaptivePortalLogin/AndroidManifest.xml
@@ -23,8 +23,8 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
- <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
<uses-permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS" />
+ <uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" />
<application android:label="@string/app_name"
android:usesCleartextTraffic="true"
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index d656593..b700bf3 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -35,11 +35,12 @@
android_app {
name: "NetworkStack",
sdk_version: "system_current",
- certificate: "platform",
+ certificate: "networkstack",
privileged: true,
static_libs: [
"NetworkStackLib"
],
+ jarjar_rules: "jarjar-rules-shared.txt",
manifest: "AndroidManifest.xml",
required: ["NetworkStackPermissionStub"],
}
\ No newline at end of file
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
index 860ebfb..0476712 100644
--- a/packages/NetworkStack/AndroidManifest.xml
+++ b/packages/NetworkStack/AndroidManifest.xml
@@ -24,12 +24,10 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
- <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
<!-- Signature permission defined in NetworkStackStub -->
<uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" />
<!-- Send latency broadcast as current user -->
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
- <uses-permission android:name="android.permission.NETWORK_STACK" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
<application
diff --git a/packages/NetworkStack/jarjar-rules-shared.txt b/packages/NetworkStack/jarjar-rules-shared.txt
new file mode 100644
index 0000000..a8c712a
--- /dev/null
+++ b/packages/NetworkStack/jarjar-rules-shared.txt
@@ -0,0 +1,19 @@
+rule com.android.internal.util.** android.net.networkstack.util.@1
+
+rule android.net.shared.Inet4AddressUtils* android.net.networkstack.shared.Inet4AddressUtils@1
+rule android.net.shared.InetAddressUtils* android.net.networkstack.shared.InetAddressUtils@1
+
+# Ignore DhcpResultsParcelable, but jarjar DhcpResults
+# TODO: move DhcpResults into services.net and delete from here
+rule android.net.DhcpResultsParcelable* @0
+rule android.net.DhcpResults* android.net.networkstack.DhcpResults@1
+rule android.net.LocalLog* android.net.networkstack.LocalLog@1
+
+# TODO: remove from framework dependencies, then remove here
+rule android.net.InterfaceConfigurationParcel* android.net.networkstack.InterfaceConfigurationParcel@1
+rule android.net.TetherStatsParcel* android.net.networkstack.TetherStatsParcel@1
+
+# Used by UidRange, which is used by framework classes such as NetworkCapabilities.
+rule android.net.UidRangeParcel* android.net.networkstack.UidRangeParcel@1
+# TODO: move TcpKeepalivePacketData to services.net and delete
+rule android.net.TcpKeepalivePacketDataParcelable* android.net.networkstack.TcpKeepalivePacketDataParcelable@1
\ No newline at end of file
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java b/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java
index 96d1a28..97d26c7 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpPacketListener.java
@@ -18,7 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.net.shared.FdEventsReader;
+import android.net.util.FdEventsReader;
import android.os.Handler;
import android.system.Os;
diff --git a/core/java/android/net/shared/FdEventsReader.java b/packages/NetworkStack/src/android/net/util/FdEventsReader.java
similarity index 98%
rename from core/java/android/net/shared/FdEventsReader.java
rename to packages/NetworkStack/src/android/net/util/FdEventsReader.java
index bffbfb1..1380ea7 100644
--- a/core/java/android/net/shared/FdEventsReader.java
+++ b/packages/NetworkStack/src/android/net/util/FdEventsReader.java
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-package android.net.shared;
+package android.net.util;
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.net.util.SocketUtils;
import android.os.Handler;
import android.os.Looper;
import android.os.MessageQueue;
diff --git a/packages/NetworkStack/src/android/net/util/PacketReader.java b/packages/NetworkStack/src/android/net/util/PacketReader.java
index 94b1e9f..4aec6b6 100644
--- a/packages/NetworkStack/src/android/net/util/PacketReader.java
+++ b/packages/NetworkStack/src/android/net/util/PacketReader.java
@@ -18,7 +18,6 @@
import static java.lang.Math.max;
-import android.net.shared.FdEventsReader;
import android.os.Handler;
import android.system.Os;
diff --git a/packages/NetworkStackPermissionStub/Android.bp b/packages/NetworkStackPermissionStub/Android.bp
index 94870c9..dd70cf5 100644
--- a/packages/NetworkStackPermissionStub/Android.bp
+++ b/packages/NetworkStackPermissionStub/Android.bp
@@ -21,7 +21,7 @@
// a classes.dex.
srcs: ["src/**/*.java"],
platform_apis: true,
- certificate: "platform",
+ certificate: "networkstack",
privileged: true,
manifest: "AndroidManifest.xml",
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/SliceBroadcastRelay.java b/packages/SettingsLib/src/com/android/settingslib/SliceBroadcastRelay.java
index e92b36a..b7f7ad2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/SliceBroadcastRelay.java
+++ b/packages/SettingsLib/src/com/android/settingslib/SliceBroadcastRelay.java
@@ -23,6 +23,10 @@
import android.net.Uri;
import android.os.Process;
import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.Set;
/**
* Utility class that allows Settings to use SystemUI to relay broadcasts related to pinned slices.
@@ -38,12 +42,22 @@
public static final String EXTRA_URI = "uri";
public static final String EXTRA_RECEIVER = "receiver";
public static final String EXTRA_FILTER = "filter";
+ private static final String TAG = "SliceBroadcastRelay";
- public static void registerReceiver(Context context, Uri registerKey,
+ private static final Set<Uri> sRegisteredUris = new ArraySet<>();
+
+ /**
+ * Associate intent filter/sliceUri with corresponding receiver.
+ */
+ public static void registerReceiver(Context context, Uri sliceUri,
Class<? extends BroadcastReceiver> receiver, IntentFilter filter) {
+
+ Log.d(TAG, "Registering Uri for broadcast relay: " + sliceUri);
+ sRegisteredUris.add(sliceUri);
+
Intent registerBroadcast = new Intent(ACTION_REGISTER);
registerBroadcast.setPackage(SYSTEMUI_PACKAGE);
- registerBroadcast.putExtra(EXTRA_URI, ContentProvider.maybeAddUserId(registerKey,
+ registerBroadcast.putExtra(EXTRA_URI, ContentProvider.maybeAddUserId(sliceUri,
Process.myUserHandle().getIdentifier()));
registerBroadcast.putExtra(EXTRA_RECEIVER,
new ComponentName(context.getPackageName(), receiver.getName()));
@@ -52,12 +66,21 @@
context.sendBroadcastAsUser(registerBroadcast, UserHandle.SYSTEM);
}
- public static void unregisterReceivers(Context context, Uri registerKey) {
- Intent registerBroadcast = new Intent(ACTION_UNREGISTER);
+ /**
+ * Unregisters all receivers for a given slice uri.
+ */
+
+ public static void unregisterReceivers(Context context, Uri sliceUri) {
+ if (!sRegisteredUris.contains(sliceUri)) {
+ return;
+ }
+ Log.d(TAG, "Unregistering uri broadcast relay: " + sliceUri);
+ final Intent registerBroadcast = new Intent(ACTION_UNREGISTER);
registerBroadcast.setPackage(SYSTEMUI_PACKAGE);
- registerBroadcast.putExtra(EXTRA_URI, ContentProvider.maybeAddUserId(registerKey,
+ registerBroadcast.putExtra(EXTRA_URI, ContentProvider.maybeAddUserId(sliceUri,
Process.myUserHandle().getIdentifier()));
context.sendBroadcastAsUser(registerBroadcast, UserHandle.SYSTEM);
+ sRegisteredUris.remove(sliceUri);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index ac2c2c9..43affcd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -1065,7 +1065,7 @@
}
public boolean isSaved() {
- return networkId != WifiConfiguration.INVALID_NETWORK_ID;
+ return mConfig != null;
}
public Object getTag() {
diff --git a/packages/SystemUI/res/drawable/privacy_chip_bg.xml b/packages/SystemUI/res/drawable/privacy_chip_bg.xml
index f1158ef..b7b21fa 100644
--- a/packages/SystemUI/res/drawable/privacy_chip_bg.xml
+++ b/packages/SystemUI/res/drawable/privacy_chip_bg.xml
@@ -16,8 +16,8 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="#4a4a4a" />
+ <solid android:color="#242424" /> <!-- 14% of white -->
<padding android:paddingTop="@dimen/ongoing_appops_chip_bg_padding"
- android:paddingBottom="@dimen/ongoing_appops_chip_bg_padding"/>
+ android:paddingBottom="@dimen/ongoing_appops_chip_bg_padding" />
<corners android:radius="@dimen/ongoing_appops_chip_bg_corner_radius" />
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
index 58fe811..f64a64e6 100644
--- a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
@@ -15,6 +15,7 @@
limitations under the License.
-->
+
<com.android.systemui.privacy.OngoingPrivacyChip
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/privacy_chip"
@@ -22,47 +23,39 @@
android:layout_width="wrap_content"
android:layout_marginLeft="@dimen/ongoing_appops_chip_margin"
android:layout_marginRight="@dimen/ongoing_appops_chip_margin"
- android:layout_marginTop="@dimen/ongoing_appops_top_chip_margin"
- android:layout_marginBottom="@dimen/ongoing_appops_top_chip_margin"
- android:gravity="center_vertical|center_horizontal"
android:layout_gravity="center_vertical|start"
+ android:gravity="center_vertical"
android:orientation="horizontal"
- android:paddingStart="@dimen/ongoing_appops_chip_side_padding"
- android:paddingEnd="@dimen/ongoing_appops_chip_side_padding"
android:focusable="true">
- <TextView
- android:id="@+id/in_use_text"
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- android:layout_gravity="center_vertical|start"
- android:layout_marginEnd="@dimen/ongoing_appops_chip_icon_margin_collapsed"
- android:gravity="center_vertical"
- android:textAppearance="@style/TextAppearance.StatusBar.Clock"
- android:textColor="@color/status_bar_clock_color"
- android:text="@string/ongoing_privacy_chip_in_use"
- />
-
<LinearLayout
- android:id="@+id/icons_container"
- android:layout_height="match_parent"
+ android:id="@+id/background"
+ android:layout_height="@dimen/ongoing_appops_chip_height"
android:layout_width="wrap_content"
- android:layout_gravity="center_vertical"
- android:gravity="center_vertical"
- />
+ >
+ <LinearLayout
+ android:id="@+id/icons_container"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:layout_marginStart="@dimen/ongoing_appops_chip_items_margin"
+ android:layout_gravity="center_vertical"
+ android:gravity="center_vertical"
+ />
- <TextView
- android:id="@+id/text_container"
- android:layout_height="match_parent"
- android:layout_width="wrap_content"
- android:singleLine="true"
- android:ellipsize="end"
- android:lines="1"
- android:layout_gravity="center_vertical|end"
- android:gravity="center_vertical"
- android:textAppearance="@style/TextAppearance.StatusBar.Clock"
- android:textColor="@color/status_bar_clock_color"
- android:layout_marginStart="@dimen/ongoing_appops_chip_icon_margin_collapsed"
- android:layout_marginEnd="@dimen/ongoing_appops_chip_icon_margin_collapsed"
- />
+ <TextView
+ android:id="@+id/text_container"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical|end"
+ android:paddingStart="@dimen/ongoing_appops_chip_text_padding"
+ android:paddingEnd="@dimen/ongoing_appops_chip_text_padding"
+ android:gravity="center_vertical"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:lines="1"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+ android:textSize="@dimen/ongoing_appops_chip_text_size"
+ android:textColor="@color/status_bar_clock_color"
+ />
+ </LinearLayout>
</com.android.systemui.privacy.OngoingPrivacyChip>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index df858f0..bb0c6f6 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -34,5 +34,4 @@
<bool name="quick_settings_wide">true</bool>
<dimen name="qs_detail_margin_top">0dp</dimen>
<dimen name="qs_paged_tile_layout_padding_bottom">0dp</dimen>
- <dimen name="ongoing_appops_top_chip_margin">2dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 1e1245f..1c7ee36 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -980,26 +980,32 @@
<dimen name="ongoing_appops_dialog_items_bottom_margin">24dp</dimen>
<!-- Top and bottom margin of title in Ongoing App Ops dialog -->
<dimen name="ongoing_appops_dialog_title_margin_top_bottom">18dp</dimen>
- <!-- Side margins around the Ongoing App Ops chip-->
- <dimen name="ongoing_appops_chip_margin">12dp</dimen>
- <!-- Top and bottom margins around the Ongoing App Ops chip -->
- <dimen name="ongoing_appops_top_chip_margin">12dp</dimen>
- <!-- Start and End padding for Ongoing App Ops chip -->
- <dimen name="ongoing_appops_chip_side_padding">6dp</dimen>
- <!-- Padding between background of Ongoing App Ops chip and content -->
- <dimen name="ongoing_appops_chip_bg_padding">0dp</dimen>
- <!-- Margin between icons of Ongoing App Ops chip when QQS-->
- <dimen name="ongoing_appops_chip_icon_margin_collapsed">0dp</dimen>
- <!-- Margin between icons of Ongoing App Ops chip when QS-->
- <dimen name="ongoing_appops_chip_icon_margin_expanded">8dp</dimen>
- <!-- Icon size of Ongoing App Ops chip -->
- <dimen name="ongoing_appops_chip_icon_size">18dp</dimen>
- <!-- Radius of Ongoing App Ops chip corners -->
- <dimen name="ongoing_appops_chip_bg_corner_radius">4dp</dimen>
<!-- Text size for Ongoing App Ops dialog title -->
<dimen name="ongoing_appops_dialog_title_size">20sp</dimen>
<!-- Text size for Ongoing App Ops dialog items -->
<dimen name="ongoing_appops_dialog_item_size">16sp</dimen>
+ <!-- Side margins around the Ongoing App Ops chip-->
+ <dimen name="ongoing_appops_chip_margin">0dp</dimen>
+ <!-- Height of the Ongoing App Ops chip -->
+ <dimen name="ongoing_appops_chip_height">32dp</dimen>
+ <!-- Start and End padding for Ongoing App Ops chip -->
+ <dimen name="ongoing_appops_chip_text_padding">8dp</dimen>
+ <!-- Padding between background of Ongoing App Ops chip and content -->
+ <dimen name="ongoing_appops_chip_bg_padding">0dp</dimen>
+ <!-- Side padding between background of Ongoing App Ops chip and content -->
+ <dimen name="ongoing_appops_chip_side_padding">8dp</dimen>
+ <!-- Margin between icons of Ongoing App Ops chip when QQS-->
+ <dimen name="ongoing_appops_chip_icon_margin_collapsed">0dp</dimen>
+ <!-- Margin between icons of Ongoing App Ops chip when QS-->
+ <dimen name="ongoing_appops_chip_icon_margin_expanded">2dp</dimen>
+ <!-- Icon size of Ongoing App Ops chip -->
+ <dimen name="ongoing_appops_chip_icon_size">@*android:dimen/status_bar_icon_size</dimen>
+ <!-- Radius of Ongoing App Ops chip corners -->
+ <dimen name="ongoing_appops_chip_bg_corner_radius">16dp</dimen>
+ <!-- Size of text of Ongoing App Ops chip -->
+ <dimen name="ongoing_appops_chip_text_size">12sp</dimen>
+ <!-- Margin between items in Ongoing App Ops chip -->
+ <dimen name="ongoing_appops_chip_items_margin">8dp</dimen>
<!-- How much a bubble is elevated -->
<dimen name="bubble_elevation">8dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index f277c43..3ac7fd4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -724,6 +724,7 @@
}
private void handleFaceAuthFailed() {
+ setFaceRunningState(BIOMETRIC_STATE_STOPPED);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 6d583df..6bb4fb5 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -41,6 +41,7 @@
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
+import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
@@ -141,7 +142,7 @@
StatusBar statusBar, StatusBarStateController statusBarStateController,
NotificationListener listener) {
return new NotificationIconAreaController(context, statusBar, statusBarStateController,
- listener);
+ listener, Dependency.get(NotificationMediaManager.class));
}
public KeyguardIndicationController createKeyguardIndicationController(Context context,
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
index 1765dc8..15dc43f 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
@@ -16,7 +16,6 @@
import android.content.Context
import android.util.AttributeSet
-import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
@@ -40,10 +39,12 @@
context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_size)
private val iconColor = context.resources.getColor(
R.color.status_bar_clock_color, context.theme)
+ private val sidePadding =
+ context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_side_padding)
private val backgroundDrawable = context.getDrawable(R.drawable.privacy_chip_bg)
private lateinit var text: TextView
private lateinit var iconsContainer: LinearLayout
- private lateinit var inUseText: TextView
+ private lateinit var back: LinearLayout
var expanded = false
set(value) {
if (value != field) {
@@ -64,15 +65,15 @@
override fun onFinishInflate() {
super.onFinishInflate()
- inUseText = findViewById(R.id.in_use_text)
+ back = findViewById(R.id.background)
text = findViewById(R.id.text_container)
iconsContainer = findViewById(R.id.icons_container)
}
// Should only be called if the builder icons or app changed
private fun updateView() {
- inUseText.visibility = if (expanded) View.GONE else View.VISIBLE
- background = if (expanded) backgroundDrawable else null
+ back.background = if (expanded) backgroundDrawable else null
+ back.setPaddingRelative(0, 0, if (expanded) sidePadding else 0, 0)
fun setIcons(dialogBuilder: PrivacyDialogBuilder, iconsContainer: ViewGroup) {
iconsContainer.removeAllViews()
dialogBuilder.generateIcons().forEachIndexed { i, it ->
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index c0f87cb..6a8c19a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -81,6 +81,7 @@
import com.android.systemui.statusbar.policy.NextAlarmController;
import com.android.systemui.statusbar.policy.ZenModeController;
+import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
@@ -200,6 +201,8 @@
mSystemIconsView = findViewById(R.id.quick_status_bar_system_icons);
mQuickQsStatusIcons = findViewById(R.id.quick_qs_status_icons);
StatusIconContainer iconContainer = findViewById(R.id.statusIcons);
+ // Ignore privacy icons because they show in the space above QQS
+ iconContainer.addIgnoredSlots(getIgnoredIconSlots());
iconContainer.setShouldRestrictIcons(false);
mIconManager = new TintedIconManager(iconContainer);
@@ -241,6 +244,18 @@
updateShowPercent();
}
+ private List<String> getIgnoredIconSlots() {
+ ArrayList<String> ignored = new ArrayList<>();
+ ignored.add(mContext.getResources().getString(
+ com.android.internal.R.string.status_bar_camera));
+ ignored.add(mContext.getResources().getString(
+ com.android.internal.R.string.status_bar_microphone));
+ ignored.add(mContext.getResources().getString(
+ com.android.internal.R.string.status_bar_location));
+
+ return ignored;
+ }
+
private void updateStatusText() {
boolean changed = updateRingerStatus() || updateAlarmStatus();
@@ -372,15 +387,6 @@
setLayoutParams(lp);
- if (mPrivacyChip != null) {
- MarginLayoutParams lm = (MarginLayoutParams) mPrivacyChip.getLayoutParams();
- int sideMargins = lm.leftMargin;
- int topBottomMargins = resources.getDimensionPixelSize(
- R.dimen.ongoing_appops_top_chip_margin);
- lm.setMargins(sideMargins, topBottomMargins, sideMargins, topBottomMargins);
- mPrivacyChip.setLayoutParams(lm);
- }
-
updateStatusIconAlphaAnimator();
updateHeaderTextContainerAlphaAnimator();
updatePrivacyChipAlphaAnimator();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
index af442d3..64209a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
@@ -114,7 +114,7 @@
lp.accessibilityTitle = context.getString(R.string.nav_bar_edge_panel);
lp.windowAnimations = 0;
NavigationBarEdgePanel panel = new NavigationBarEdgePanel(
- context, (gravity & Gravity.LEFT) != 0);
+ context, (gravity & Gravity.LEFT) == Gravity.LEFT);
panel.setLayoutParams(lp);
return panel;
}
@@ -269,12 +269,21 @@
dist));
if (dist < mGestureLength) {
- setLegProgress(MathUtils.constrainedMap(
+ float calculatedLegProgress = MathUtils.constrainedMap(
0f, POINTEDNESS_BEFORE_SNAP_RATIO,
mGestureLength * START_POINTING_RATIO, mGestureLength,
- dist));
+ dist);
- mGestureDetected = false;
+ // Blend animated value with drag calculated value, allow the gesture to continue
+ // while the animation is playing with jump cuts in the animation.
+ setLegProgress(MathUtils.lerp(calculatedLegProgress, mLegProgress, mDragProgress));
+
+ if (mGestureDetected) {
+ mGestureDetected = false;
+
+ mLegAnimator.setFloatValues(POINTEDNESS_BEFORE_SNAP_RATIO);
+ mLegAnimator.start();
+ }
} else {
if (!mGestureDetected) {
performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 62f85fe..99269cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -24,6 +24,7 @@
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -47,6 +48,7 @@
private final NotificationEntryManager mEntryManager;
private final Runnable mUpdateStatusBarIcons = this::updateStatusBarIcons;
private final StatusBarStateController mStatusBarStateController;
+ private final NotificationMediaManager mMediaManager;
@VisibleForTesting
final NotificationListener.NotificationSettingsListener mSettingsListener =
new NotificationListener.NotificationSettingsListener() {
@@ -93,13 +95,15 @@
public NotificationIconAreaController(Context context, StatusBar statusBar,
StatusBarStateController statusBarStateController,
- NotificationListener notificationListener) {
+ NotificationListener notificationListener,
+ NotificationMediaManager notificationMediaManager) {
mStatusBar = statusBar;
mContrastColorUtil = ContrastColorUtil.getInstance(context);
mContext = context;
mEntryManager = Dependency.get(NotificationEntryManager.class);
mStatusBarStateController = statusBarStateController;
mStatusBarStateController.addCallback(this);
+ mMediaManager = notificationMediaManager;
notificationListener.addNotificationSettingsListener(mSettingsListener);
initializeNotificationAreaViews(context);
@@ -192,10 +196,13 @@
protected boolean shouldShowNotificationIcon(NotificationEntry entry,
boolean showAmbient, boolean showLowPriority, boolean hideDismissed,
- boolean hideRepliedMessages) {
+ boolean hideRepliedMessages, boolean hideCurrentMedia) {
if (mEntryManager.getNotificationData().isAmbient(entry.key) && !showAmbient) {
return false;
}
+ if (hideCurrentMedia && entry.key.equals(mMediaManager.getMediaNotificationKey())) {
+ return false;
+ }
if (!showLowPriority && !entry.isHighPriority()) {
return false;
}
@@ -235,14 +242,16 @@
private void updateShelfIcons() {
updateIconsForLayout(entry -> entry.expandedIcon, mShelfIcons,
true /* showAmbient */, !mFullyDark /* showLowPriority */,
- false /* hideDismissed */, mFullyDark /* hideRepliedMessages */);
+ false /* hideDismissed */, mFullyDark /* hideRepliedMessages */,
+ mFullyDark /* hideCurrentMedia */);
}
public void updateStatusBarIcons() {
updateIconsForLayout(entry -> entry.icon, mNotificationIcons,
false /* showAmbient */, mShowLowPriority /* showLowPriority */,
true /* hideDismissed */,
- true /* hideRepliedMessages */);
+ true /* hideRepliedMessages */,
+ false /* hideCurrentMedia */);
}
@VisibleForTesting
@@ -261,7 +270,7 @@
*/
private void updateIconsForLayout(Function<NotificationEntry, StatusBarIconView> function,
NotificationIconContainer hostLayout, boolean showAmbient, boolean showLowPriority,
- boolean hideDismissed, boolean hideRepliedMessages) {
+ boolean hideDismissed, boolean hideRepliedMessages, boolean hideCurrentMedia) {
ArrayList<StatusBarIconView> toShow = new ArrayList<>(
mNotificationScrollLayout.getChildCount());
@@ -271,7 +280,7 @@
if (view instanceof ExpandableNotificationRow) {
NotificationEntry ent = ((ExpandableNotificationRow) view).getEntry();
if (shouldShowNotificationIcon(ent, showAmbient, showLowPriority, hideDismissed,
- hideRepliedMessages)) {
+ hideRepliedMessages, hideCurrentMedia)) {
toShow.add(function.apply(ent));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index 6495910..6e36c01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -38,6 +38,7 @@
import com.android.systemui.statusbar.notification.stack.ViewState;
import java.util.ArrayList;
+import java.util.List;
/**
* A container for Status bar system icons. Limits the number of system icons and handles overflow
@@ -67,6 +68,8 @@
private ArrayList<StatusIconState> mLayoutStates = new ArrayList<>();
// So we can count and measure properly
private ArrayList<View> mMeasureViews = new ArrayList<>();
+ // Any ignored icon will never be added as a child
+ private ArrayList<String> mIgnoredSlots = new ArrayList<>();
public StatusIconContainer(Context context) {
this(context, null);
@@ -146,7 +149,8 @@
// Collect all of the views which want to be laid out
for (int i = 0; i < count; i++) {
StatusIconDisplayable icon = (StatusIconDisplayable) getChildAt(i);
- if (icon.isIconVisible() && !icon.isIconBlocked()) {
+ if (icon.isIconVisible() && !icon.isIconBlocked()
+ && !mIgnoredSlots.contains(icon.getSlot())) {
mMeasureViews.add((View) icon);
}
}
@@ -205,6 +209,47 @@
}
/**
+ * Add a name of an icon slot to be ignored. It will not show up nor be measured
+ * @param slotName name of the icon as it exists in
+ * frameworks/base/core/res/res/values/config.xml
+ */
+ public void addIgnoredSlot(String slotName) {
+ addIgnoredSlotInternal(slotName);
+ requestLayout();
+ }
+
+ /**
+ * Add a list of slots to be ignored
+ * @param slots names of the icons to ignore
+ */
+ public void addIgnoredSlots(List<String> slots) {
+ for (String slot : slots) {
+ addIgnoredSlotInternal(slot);
+ }
+
+ requestLayout();
+ }
+
+ private void addIgnoredSlotInternal(String slotName) {
+ if (!mIgnoredSlots.contains(slotName)) {
+ mIgnoredSlots.add(slotName);
+ }
+ }
+
+ /**
+ * Remove a slot from the list of ignored icon slots. It will then be shown when set to visible
+ * by the {@link StatusBarIconController}.
+ * @param slotName name of the icon slot to remove from the ignored list
+ */
+ public void removeIgnoredSlot(String slotName) {
+ if (mIgnoredSlots.contains(slotName)) {
+ mIgnoredSlots.remove(slotName);
+ }
+
+ requestLayout();
+ }
+
+ /**
* Layout is happening from end -> start
*/
private void calculateIconTranslations() {
@@ -223,7 +268,8 @@
StatusIconDisplayable iconView = (StatusIconDisplayable) child;
StatusIconState childState = getViewStateFromChild(child);
- if (!iconView.isIconVisible() || iconView.isIconBlocked()) {
+ if (!iconView.isIconVisible() || iconView.isIconBlocked()
+ || mIgnoredSlots.contains(iconView.getSlot())) {
childState.visibleState = STATE_HIDDEN;
if (DEBUG) Log.d(TAG, "skipping child (" + iconView.getSlot() + ") not visible");
continue;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
index 608dd8b..120d0b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
@@ -29,6 +29,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.NotificationMediaManager;
import org.junit.Before;
import org.junit.Test;
@@ -47,6 +48,8 @@
StatusBar mStatusBar;
@Mock
StatusBarStateController mStatusBarStateController;
+ @Mock
+ private NotificationMediaManager mMediaManager;
private NotificationIconAreaController mController;
@Before
@@ -54,7 +57,7 @@
MockitoAnnotations.initMocks(this);
mController = new NotificationIconAreaController(mContext, mStatusBar,
- mStatusBarStateController, mListener);
+ mStatusBarStateController, mListener, mMediaManager);
}
@Test
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 4dcc9ed..5989a46 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -2801,8 +2801,7 @@
} catch (RemoteException e) {
// if the remote process registering the listener is already dead, just swallow the
// exception and return
- Log.w(TAG, "Could not link " + linkedListener.mListenerName + " death callback.",
- e);
+ Log.w(TAG, "Could not link " + linkedListener.mListenerName + " death callback.", e);
return false;
}
}
@@ -2815,8 +2814,7 @@
} catch (NoSuchElementException e) {
// if the death callback isn't connected (it should be...), log error,
// swallow the exception and return
- Log.w(TAG, "Could not unlink " + linkedListener.mListenerName + " death callback.",
- e);
+ Log.w(TAG, "Could not unlink " + linkedListener.mListenerName + " death callback.", e);
return false;
}
}
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index f293328..47c9b86 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -104,8 +104,7 @@
@Override
public void onSwitchUser(int userId) {
- cancelAndUnbindLocked(peekUserStateLocked(userId),
- AttentionService.ATTENTION_FAILURE_UNKNOWN);
+ cancelAndUnbindLocked(peekUserStateLocked(userId));
}
/** Resolves and sets up the attention service if it had not been done yet. */
@@ -152,7 +151,8 @@
}
synchronized (mLock) {
- unbindAfterTimeoutLocked();
+ final long now = SystemClock.uptimeMillis();
+ freeIfInactiveLocked();
final UserState userState = getOrCreateCurrentUserStateLocked();
// lazily start the service, which should be very lightweight to start
@@ -172,7 +172,7 @@
try {
// throttle frequent requests
final AttentionCheckCache attentionCheckCache = userState.mAttentionCheckCache;
- if (attentionCheckCache != null && SystemClock.uptimeMillis()
+ if (attentionCheckCache != null && now
< attentionCheckCache.mLastComputed + STALE_AFTER_MILLIS) {
callback.onSuccess(requestCode, attentionCheckCache.mResult,
attentionCheckCache.mTimestamp);
@@ -190,6 +190,7 @@
userState.mAttentionCheckCache = new AttentionCheckCache(
SystemClock.uptimeMillis(), result,
timestamp);
+ userState.mCurrentAttentionCheckIsFulfilled = true;
}
StatsLog.write(StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED,
result);
@@ -198,6 +199,7 @@
@Override
public void onFailure(int requestCode, int error) {
callback.onFailure(requestCode, error);
+ userState.mCurrentAttentionCheckIsFulfilled = true;
StatsLog.write(StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED,
error);
}
@@ -214,7 +216,10 @@
/** Cancels the specified attention check. */
public void cancelAttentionCheck(int requestCode) {
synchronized (mLock) {
- final UserState userState = getOrCreateCurrentUserStateLocked();
+ final UserState userState = peekCurrentUserStateLocked();
+ if (userState == null) {
+ return;
+ }
if (userState.mService == null) {
if (userState.mPendingAttentionCheck != null
&& userState.mPendingAttentionCheck.mRequestCode == requestCode) {
@@ -231,8 +236,12 @@
}
@GuardedBy("mLock")
- private void unbindAfterTimeoutLocked() {
- mAttentionHandler.sendEmptyMessageDelayed(AttentionHandler.CONNECTION_EXPIRED,
+ private void freeIfInactiveLocked() {
+ // If we are called here, it means someone used the API again - reset the timer then.
+ mAttentionHandler.removeMessages(AttentionHandler.CHECK_CONNECTION_EXPIRATION);
+
+ // Schedule resources cleanup if no one calls the API again.
+ mAttentionHandler.sendEmptyMessageDelayed(AttentionHandler.CHECK_CONNECTION_EXPIRATION,
CONNECTION_TTL_MILLIS);
}
@@ -259,12 +268,14 @@
}
@GuardedBy("mLock")
- UserState peekCurrentUserStateLocked() {
+ @Nullable
+ private UserState peekCurrentUserStateLocked() {
return peekUserStateLocked(ActivityManager.getCurrentUser());
}
@GuardedBy("mLock")
- UserState peekUserStateLocked(int userId) {
+ @Nullable
+ private UserState peekUserStateLocked(int userId) {
return mUserStates.get(userId);
}
@@ -401,6 +412,8 @@
@GuardedBy("mLock")
int mCurrentAttentionCheckRequestCode;
@GuardedBy("mLock")
+ boolean mCurrentAttentionCheckIsFulfilled;
+ @GuardedBy("mLock")
PendingAttentionCheck mPendingAttentionCheck;
@GuardedBy("mLock")
@@ -496,7 +509,7 @@
}
private class AttentionHandler extends Handler {
- private static final int CONNECTION_EXPIRED = 1;
+ private static final int CHECK_CONNECTION_EXPIRATION = 1;
private static final int ATTENTION_CHECK_TIMEOUT = 2;
AttentionHandler() {
@@ -506,19 +519,26 @@
public void handleMessage(Message msg) {
switch (msg.what) {
// Do not occupy resources when not in use - unbind proactively.
- case CONNECTION_EXPIRED: {
+ case CHECK_CONNECTION_EXPIRATION: {
for (int i = 0; i < mUserStates.size(); i++) {
- cancelAndUnbindLocked(mUserStates.valueAt(i),
- AttentionService.ATTENTION_FAILURE_UNKNOWN);
+ cancelAndUnbindLocked(mUserStates.valueAt(i));
}
-
}
break;
// Callee is no longer interested in the attention check result - cancel.
case ATTENTION_CHECK_TIMEOUT: {
- cancelAndUnbindLocked(peekCurrentUserStateLocked(),
- AttentionService.ATTENTION_FAILURE_TIMED_OUT);
+ synchronized (mLock) {
+ final UserState userState = peekCurrentUserStateLocked();
+ if (userState != null) {
+ // If not called back already.
+ if (!userState.mCurrentAttentionCheckIsFulfilled) {
+ cancel(userState,
+ AttentionService.ATTENTION_FAILURE_TIMED_OUT);
+ }
+
+ }
+ }
}
break;
@@ -528,25 +548,29 @@
}
}
- @GuardedBy("mLock")
- private void cancelAndUnbindLocked(UserState userState,
- @AttentionFailureCodes int failureCode) {
- synchronized (mLock) {
- if (userState != null && userState.mService != null) {
- try {
- userState.mService.cancelAttentionCheck(
- userState.mCurrentAttentionCheckRequestCode);
- } catch (RemoteException e) {
- Slog.e(LOG_TAG, "Unable to cancel attention check");
- }
-
- if (userState.mPendingAttentionCheck != null) {
- userState.mPendingAttentionCheck.cancel(failureCode);
- }
- mContext.unbindService(userState.mConnection);
- userState.mConnection.cleanupService();
- mUserStates.remove(userState.mUserId);
+ private void cancel(UserState userState, @AttentionFailureCodes int failureCode) {
+ if (userState != null && userState.mService != null) {
+ try {
+ userState.mService.cancelAttentionCheck(
+ userState.mCurrentAttentionCheckRequestCode);
+ } catch (RemoteException e) {
+ Slog.e(LOG_TAG, "Unable to cancel attention check");
}
+
+ if (userState.mPendingAttentionCheck != null) {
+ userState.mPendingAttentionCheck.cancel(failureCode);
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void cancelAndUnbindLocked(UserState userState) {
+ synchronized (mLock) {
+ cancel(userState, AttentionService.ATTENTION_FAILURE_UNKNOWN);
+
+ mContext.unbindService(userState.mConnection);
+ userState.mConnection.cleanupService();
+ mUserStates.remove(userState.mUserId);
}
}
@@ -558,8 +582,7 @@
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
- cancelAndUnbindLocked(peekCurrentUserStateLocked(),
- AttentionService.ATTENTION_FAILURE_UNKNOWN);
+ cancelAndUnbindLocked(peekCurrentUserStateLocked());
}
}
}
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index 45f169c..7dd3b36 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -129,240 +129,9 @@
private final NightDisplayTintController mNightDisplayTintController =
new NightDisplayTintController();
- private final TintController mDisplayWhiteBalanceTintController = new TintController() {
- // Three chromaticity coordinates per color: X, Y, and Z
- private final int NUM_VALUES_PER_PRIMARY = 3;
- // Four colors: red, green, blue, and white
- private final int NUM_DISPLAY_PRIMARIES_VALS = 4 * NUM_VALUES_PER_PRIMARY;
-
- private final Object mLock = new Object();
- private int mTemperatureMin;
- private int mTemperatureMax;
- private int mTemperatureDefault;
- private float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
- private ColorSpace.Rgb mDisplayColorSpaceRGB;
- private float[] mChromaticAdaptationMatrix;
- private int mCurrentColorTemperature;
- private float[] mCurrentColorTemperatureXYZ;
- private boolean mSetUp = false;
- private float[] mMatrixDisplayWhiteBalance = new float[16];
- private Boolean mIsAvailable;
-
- @Override
- public void setUp(Context context, boolean needsLinear) {
- mSetUp = false;
- final Resources res = context.getResources();
-
- ColorSpace.Rgb displayColorSpaceRGB = getDisplayColorSpaceFromSurfaceControl();
- if (displayColorSpaceRGB == null) {
- Slog.w(TAG, "Failed to get display color space from SurfaceControl, trying res");
- displayColorSpaceRGB = getDisplayColorSpaceFromResources(res);
- if (displayColorSpaceRGB == null) {
- Slog.e(TAG, "Failed to get display color space from resources");
- return;
- }
- }
-
- final String[] nominalWhiteValues = res.getStringArray(
- R.array.config_displayWhiteBalanceDisplayNominalWhite);
- float[] displayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
- for (int i = 0; i < nominalWhiteValues.length; i++) {
- displayNominalWhiteXYZ[i] = Float.parseFloat(nominalWhiteValues[i]);
- }
-
- final int colorTemperatureMin = res.getInteger(
- R.integer.config_displayWhiteBalanceColorTemperatureMin);
- if (colorTemperatureMin <= 0) {
- Slog.e(TAG, "Display white balance minimum temperature must be greater than 0");
- return;
- }
-
- final int colorTemperatureMax = res.getInteger(
- R.integer.config_displayWhiteBalanceColorTemperatureMax);
- if (colorTemperatureMax < colorTemperatureMin) {
- Slog.e(TAG, "Display white balance max temp must be greater or equal to min");
- return;
- }
-
- final int colorTemperature = res.getInteger(
- R.integer.config_displayWhiteBalanceColorTemperatureDefault);
-
- synchronized (mLock) {
- mDisplayColorSpaceRGB = displayColorSpaceRGB;
- mDisplayNominalWhiteXYZ = displayNominalWhiteXYZ;
- mTemperatureMin = colorTemperatureMin;
- mTemperatureMax = colorTemperatureMax;
- mTemperatureDefault = colorTemperature;
- mSetUp = true;
- }
-
- setMatrix(mTemperatureDefault);
- }
-
- @Override
- public float[] getMatrix() {
- return mSetUp && isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY;
- }
-
- @Override
- public void setMatrix(int cct) {
- if (!mSetUp) {
- Slog.w(TAG, "Can't set display white balance temperature: uninitialized");
- return;
- }
-
- if (cct < mTemperatureMin) {
- Slog.w(TAG, "Requested display color temperature is below allowed minimum");
- cct = mTemperatureMin;
- } else if (cct > mTemperatureMax) {
- Slog.w(TAG, "Requested display color temperature is above allowed maximum");
- cct = mTemperatureMax;
- }
-
- Slog.d(TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct);
-
- synchronized (mLock) {
- mCurrentColorTemperature = cct;
-
- // Adapt the display's nominal white point to match the requested CCT value
- mCurrentColorTemperatureXYZ = ColorSpace.cctToIlluminantdXyz(cct);
-
- mChromaticAdaptationMatrix =
- ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
- mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ);
-
- // Convert the adaptation matrix to RGB space
- float[] result = ColorSpace.mul3x3(mChromaticAdaptationMatrix,
- mDisplayColorSpaceRGB.getTransform());
- result = ColorSpace.mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result);
-
- // Normalize the transform matrix to peak white value in RGB space
- final float adaptedMaxR = result[0] + result[3] + result[6];
- final float adaptedMaxG = result[1] + result[4] + result[7];
- final float adaptedMaxB = result[2] + result[5] + result[8];
- final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB);
- for (int i = 0; i < result.length; i++) {
- result[i] /= denum;
- }
-
- Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
- java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3);
- java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
- java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
- }
- }
-
- @Override
- public int getLevel() {
- return LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
- }
-
- @Override
- public boolean isAvailable(Context context) {
- if (mIsAvailable == null) {
- mIsAvailable = ColorDisplayManager.isDisplayWhiteBalanceAvailable(context);
- }
- return mIsAvailable;
- }
-
- /**
- * Format a given matrix into a string.
- *
- * @param matrix the matrix to format
- * @param cols number of columns in the matrix
- */
- private String matrixToString(float[] matrix, int cols) {
- if (matrix == null || cols <= 0) {
- Slog.e(TAG, "Invalid arguments when formatting matrix to string");
- return "";
- }
-
- StringBuilder sb = new StringBuilder("");
- for (int i = 0; i < matrix.length; i++) {
- if (i % cols == 0) {
- sb.append("\n ");
- }
- sb.append(String.format("%9.6f ", matrix[i]));
- }
- return sb.toString();
- }
-
- @Override
- public void dump(PrintWriter pw) {
- synchronized (mLock) {
- pw.println(" mSetUp = " + mSetUp);
- if (!mSetUp) {
- return;
- }
-
- pw.println(" isActivated = " + isActivated());
- pw.println(" mTemperatureMin = " + mTemperatureMin);
- pw.println(" mTemperatureMax = " + mTemperatureMax);
- pw.println(" mTemperatureDefault = " + mTemperatureDefault);
- pw.println(" mCurrentColorTemperature = " + mCurrentColorTemperature);
- pw.println(" mCurrentColorTemperatureXYZ = " +
- matrixToString(mCurrentColorTemperatureXYZ, 3));
- pw.println(" mDisplayColorSpaceRGB RGB-to-XYZ = " +
- matrixToString(mDisplayColorSpaceRGB.getTransform(), 3));
- pw.println(" mChromaticAdaptationMatrix = " +
- matrixToString(mChromaticAdaptationMatrix, 3));
- pw.println(" mDisplayColorSpaceRGB XYZ-to-RGB = " +
- matrixToString(mDisplayColorSpaceRGB.getInverseTransform(), 3));
- pw.println(" mMatrixDisplayWhiteBalance = " +
- matrixToString(mMatrixDisplayWhiteBalance, 4));
- }
- }
-
- private ColorSpace.Rgb makeRgbColorSpaceFromXYZ(float[] redGreenBlueXYZ, float[] whiteXYZ) {
- return new ColorSpace.Rgb(
- "Display Color Space",
- redGreenBlueXYZ,
- whiteXYZ,
- 2.2f // gamma, unused for display white balance
- );
- }
-
- private ColorSpace.Rgb getDisplayColorSpaceFromSurfaceControl() {
- final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
- if (displayToken == null) {
- return null;
- }
-
- DisplayPrimaries primaries = SurfaceControl.getDisplayNativePrimaries(displayToken);
- if (primaries == null || primaries.red == null || primaries.green == null ||
- primaries.blue == null || primaries.white == null) {
- return null;
- }
-
- return makeRgbColorSpaceFromXYZ(
- new float[] {
- primaries.red.X, primaries.red.Y, primaries.red.Z,
- primaries.green.X, primaries.green.Y, primaries.green.Z,
- primaries.blue.X, primaries.blue.Y, primaries.blue.Z,
- },
- new float[] { primaries.white.X, primaries.white.Y, primaries.white.Z }
- );
- }
-
- private ColorSpace.Rgb getDisplayColorSpaceFromResources(Resources res) {
- final String[] displayPrimariesValues = res.getStringArray(
- R.array.config_displayWhiteBalanceDisplayPrimaries);
- float[] displayRedGreenBlueXYZ =
- new float[NUM_DISPLAY_PRIMARIES_VALS - NUM_VALUES_PER_PRIMARY];
- float[] displayWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
-
- for (int i = 0; i < displayRedGreenBlueXYZ.length; i++) {
- displayRedGreenBlueXYZ[i] = Float.parseFloat(displayPrimariesValues[i]);
- }
-
- for (int i = 0; i < displayWhiteXYZ.length; i++) {
- displayWhiteXYZ[i] = Float.parseFloat(
- displayPrimariesValues[displayRedGreenBlueXYZ.length + i]);
- }
-
- return makeRgbColorSpaceFromXYZ(displayRedGreenBlueXYZ, displayWhiteXYZ);
- }
- };
+ @VisibleForTesting
+ final DisplayWhiteBalanceTintController mDisplayWhiteBalanceTintController =
+ new DisplayWhiteBalanceTintController();
private final TintController mGlobalSaturationTintController = new TintController() {
@@ -860,7 +629,8 @@
return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt;
}
- private void updateDisplayWhiteBalanceStatus() {
+ @VisibleForTesting
+ void updateDisplayWhiteBalanceStatus() {
boolean oldActivated = mDisplayWhiteBalanceTintController.isActivated();
mDisplayWhiteBalanceTintController.setActivated(isDisplayWhiteBalanceSettingEnabled() &&
!mNightDisplayTintController.isActivated() &&
@@ -1101,6 +871,7 @@
pw.println("Display white balance:");
if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
pw.println(" Activated: " + mDisplayWhiteBalanceTintController.isActivated());
+ mDisplayWhiteBalanceTintController.dump(pw);
} else {
pw.println(" Not available");
}
@@ -1533,6 +1304,244 @@
}
}
+ final class DisplayWhiteBalanceTintController extends TintController {
+ // Three chromaticity coordinates per color: X, Y, and Z
+ private final int NUM_VALUES_PER_PRIMARY = 3;
+ // Four colors: red, green, blue, and white
+ private final int NUM_DISPLAY_PRIMARIES_VALS = 4 * NUM_VALUES_PER_PRIMARY;
+
+ private final Object mLock = new Object();
+ @VisibleForTesting
+ int mTemperatureMin;
+ @VisibleForTesting
+ int mTemperatureMax;
+ private int mTemperatureDefault;
+ private float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+ @VisibleForTesting
+ ColorSpace.Rgb mDisplayColorSpaceRGB;
+ private float[] mChromaticAdaptationMatrix;
+ @VisibleForTesting
+ int mCurrentColorTemperature;
+ private float[] mCurrentColorTemperatureXYZ;
+ private boolean mSetUp = false;
+ private float[] mMatrixDisplayWhiteBalance = new float[16];
+ private Boolean mIsAvailable;
+
+ @Override
+ public void setUp(Context context, boolean needsLinear) {
+ mSetUp = false;
+ final Resources res = context.getResources();
+
+ ColorSpace.Rgb displayColorSpaceRGB = getDisplayColorSpaceFromSurfaceControl();
+ if (displayColorSpaceRGB == null) {
+ Slog.w(TAG, "Failed to get display color space from SurfaceControl, trying res");
+ displayColorSpaceRGB = getDisplayColorSpaceFromResources(res);
+ if (displayColorSpaceRGB == null) {
+ Slog.e(TAG, "Failed to get display color space from resources");
+ return;
+ }
+ }
+
+ final String[] nominalWhiteValues = res.getStringArray(
+ R.array.config_displayWhiteBalanceDisplayNominalWhite);
+ float[] displayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+ for (int i = 0; i < nominalWhiteValues.length; i++) {
+ displayNominalWhiteXYZ[i] = Float.parseFloat(nominalWhiteValues[i]);
+ }
+
+ final int colorTemperatureMin = res.getInteger(
+ R.integer.config_displayWhiteBalanceColorTemperatureMin);
+ if (colorTemperatureMin <= 0) {
+ Slog.e(TAG, "Display white balance minimum temperature must be greater than 0");
+ return;
+ }
+
+ final int colorTemperatureMax = res.getInteger(
+ R.integer.config_displayWhiteBalanceColorTemperatureMax);
+ if (colorTemperatureMax < colorTemperatureMin) {
+ Slog.e(TAG, "Display white balance max temp must be greater or equal to min");
+ return;
+ }
+
+ final int colorTemperature = res.getInteger(
+ R.integer.config_displayWhiteBalanceColorTemperatureDefault);
+
+ synchronized (mLock) {
+ mDisplayColorSpaceRGB = displayColorSpaceRGB;
+ mDisplayNominalWhiteXYZ = displayNominalWhiteXYZ;
+ mTemperatureMin = colorTemperatureMin;
+ mTemperatureMax = colorTemperatureMax;
+ mTemperatureDefault = colorTemperature;
+ mSetUp = true;
+ }
+
+ setMatrix(mTemperatureDefault);
+ }
+
+ @Override
+ public float[] getMatrix() {
+ return mSetUp && isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY;
+ }
+
+ @Override
+ public void setMatrix(int cct) {
+ if (!mSetUp) {
+ Slog.w(TAG, "Can't set display white balance temperature: uninitialized");
+ return;
+ }
+
+ if (cct < mTemperatureMin) {
+ Slog.w(TAG, "Requested display color temperature is below allowed minimum");
+ cct = mTemperatureMin;
+ } else if (cct > mTemperatureMax) {
+ Slog.w(TAG, "Requested display color temperature is above allowed maximum");
+ cct = mTemperatureMax;
+ }
+
+ Slog.d(TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct);
+
+ synchronized (mLock) {
+ mCurrentColorTemperature = cct;
+
+ // Adapt the display's nominal white point to match the requested CCT value
+ mCurrentColorTemperatureXYZ = ColorSpace.cctToIlluminantdXyz(cct);
+
+ mChromaticAdaptationMatrix =
+ ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
+ mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ);
+
+ // Convert the adaptation matrix to RGB space
+ float[] result = ColorSpace.mul3x3(mChromaticAdaptationMatrix,
+ mDisplayColorSpaceRGB.getTransform());
+ result = ColorSpace.mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result);
+
+ // Normalize the transform matrix to peak white value in RGB space
+ final float adaptedMaxR = result[0] + result[3] + result[6];
+ final float adaptedMaxG = result[1] + result[4] + result[7];
+ final float adaptedMaxB = result[2] + result[5] + result[8];
+ final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB);
+ for (int i = 0; i < result.length; i++) {
+ result[i] /= denum;
+ }
+
+ Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
+ java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3);
+ java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
+ java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
+ }
+ }
+
+ @Override
+ public int getLevel() {
+ return LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
+ }
+
+ @Override
+ public boolean isAvailable(Context context) {
+ if (mIsAvailable == null) {
+ mIsAvailable = ColorDisplayManager.isDisplayWhiteBalanceAvailable(context);
+ }
+ return mIsAvailable;
+ }
+
+ /**
+ * Format a given matrix into a string.
+ *
+ * @param matrix the matrix to format
+ * @param cols number of columns in the matrix
+ */
+ private String matrixToString(float[] matrix, int cols) {
+ if (matrix == null || cols <= 0) {
+ Slog.e(TAG, "Invalid arguments when formatting matrix to string");
+ return "";
+ }
+
+ StringBuilder sb = new StringBuilder("");
+ for (int i = 0; i < matrix.length; i++) {
+ if (i % cols == 0) {
+ sb.append("\n ");
+ }
+ sb.append(String.format("%9.6f ", matrix[i]));
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public void dump(PrintWriter pw) {
+ synchronized (mLock) {
+ pw.println(" mSetUp = " + mSetUp);
+ if (!mSetUp) {
+ return;
+ }
+
+ pw.println(" mTemperatureMin = " + mTemperatureMin);
+ pw.println(" mTemperatureMax = " + mTemperatureMax);
+ pw.println(" mTemperatureDefault = " + mTemperatureDefault);
+ pw.println(" mCurrentColorTemperature = " + mCurrentColorTemperature);
+ pw.println(" mCurrentColorTemperatureXYZ = " +
+ matrixToString(mCurrentColorTemperatureXYZ, 3));
+ pw.println(" mDisplayColorSpaceRGB RGB-to-XYZ = " +
+ matrixToString(mDisplayColorSpaceRGB.getTransform(), 3));
+ pw.println(" mChromaticAdaptationMatrix = " +
+ matrixToString(mChromaticAdaptationMatrix, 3));
+ pw.println(" mDisplayColorSpaceRGB XYZ-to-RGB = " +
+ matrixToString(mDisplayColorSpaceRGB.getInverseTransform(), 3));
+ pw.println(" mMatrixDisplayWhiteBalance = " +
+ matrixToString(mMatrixDisplayWhiteBalance, 4));
+ }
+ }
+
+ private ColorSpace.Rgb makeRgbColorSpaceFromXYZ(float[] redGreenBlueXYZ, float[] whiteXYZ) {
+ return new ColorSpace.Rgb(
+ "Display Color Space",
+ redGreenBlueXYZ,
+ whiteXYZ,
+ 2.2f // gamma, unused for display white balance
+ );
+ }
+
+ private ColorSpace.Rgb getDisplayColorSpaceFromSurfaceControl() {
+ final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
+ if (displayToken == null) {
+ return null;
+ }
+
+ DisplayPrimaries primaries = SurfaceControl.getDisplayNativePrimaries(displayToken);
+ if (primaries == null || primaries.red == null || primaries.green == null ||
+ primaries.blue == null || primaries.white == null) {
+ return null;
+ }
+
+ return makeRgbColorSpaceFromXYZ(
+ new float[] {
+ primaries.red.X, primaries.red.Y, primaries.red.Z,
+ primaries.green.X, primaries.green.Y, primaries.green.Z,
+ primaries.blue.X, primaries.blue.Y, primaries.blue.Z,
+ },
+ new float[] { primaries.white.X, primaries.white.Y, primaries.white.Z }
+ );
+ }
+
+ private ColorSpace.Rgb getDisplayColorSpaceFromResources(Resources res) {
+ final String[] displayPrimariesValues = res.getStringArray(
+ R.array.config_displayWhiteBalanceDisplayPrimaries);
+ float[] displayRedGreenBlueXYZ =
+ new float[NUM_DISPLAY_PRIMARIES_VALS - NUM_VALUES_PER_PRIMARY];
+ float[] displayWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+
+ for (int i = 0; i < displayRedGreenBlueXYZ.length; i++) {
+ displayRedGreenBlueXYZ[i] = Float.parseFloat(displayPrimariesValues[i]);
+ }
+
+ for (int i = 0; i < displayWhiteXYZ.length; i++) {
+ displayWhiteXYZ[i] = Float.parseFloat(
+ displayPrimariesValues[displayRedGreenBlueXYZ.length + i]);
+ }
+
+ return makeRgbColorSpaceFromXYZ(displayRedGreenBlueXYZ, displayWhiteXYZ);
+ }
+ };
+
/**
* Local service that allows color transforms to be enabled from other system services.
*/
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index e71b156..243b6fe 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -373,6 +373,7 @@
private final NtpTimeHelper mNtpTimeHelper;
private final GnssBatchingProvider mGnssBatchingProvider;
private final GnssGeofenceProvider mGnssGeofenceProvider;
+ // Available only on GNSS HAL 2.0 implementations and later.
private GnssVisibilityControl mGnssVisibilityControl;
// Handler for processing events
@@ -463,8 +464,8 @@
}
};
- // TODO(b/119326010): replace OnSubscriptionsChangedListener with
- // ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED broadcast reseiver.
+ // TODO: replace OnSubscriptionsChangedListener with ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED
+ // broadcast receiver.
private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
new OnSubscriptionsChangedListener() {
@Override
@@ -676,8 +677,7 @@
mNtpTimeHelper.onNetworkAvailable();
if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
if (mSupportsXtra) {
- // Download only if supported, (prevents an unneccesary on-boot
- // download)
+ // Download only if supported, (prevents an unnecessary on-boot download)
xtraDownloadRequest();
}
}
@@ -764,7 +764,7 @@
/** Returns true if the location request is too frequent. */
private boolean isRequestLocationRateLimited() {
- // TODO(b/73198123): implement exponential backoff.
+ // TODO: implement exponential backoff.
return false;
}
diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java
index c3f25bf..20f872a 100644
--- a/services/core/java/com/android/server/location/GnssVisibilityControl.java
+++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java
@@ -24,10 +24,13 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.location.LocationManager;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
import android.os.UserHandle;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.util.StatsLog;
@@ -70,7 +73,7 @@
private final Handler mHandler;
private final Context mContext;
- private boolean mIsMasterLocationSettingsEnabled = true;
+ private boolean mIsDeviceLocationSettingsEnabled;
// Number of non-framework location access proxy apps is expected to be small (< 5).
private static final int HASH_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS = 7;
@@ -88,13 +91,9 @@
mAppOps = mContext.getSystemService(AppOpsManager.class);
mPackageManager = mContext.getPackageManager();
- // Set to empty proxy app list initially until the configuration properties are loaded.
- updateNfwLocationAccessProxyAppsInGnssHal();
-
- // Listen for proxy app package installation, removal events.
- listenForProxyAppsPackageUpdates();
-
- // TODO(b/122855984): Handle global location settings on/off.
+ // Complete initialization as the first event to run in mHandler thread. After that,
+ // all object state read/update events run in the mHandler thread.
+ runOnHandler(this::handleInitialize);
}
void updateProxyApps(List<String> nfwLocationAccessProxyApps) {
@@ -105,10 +104,6 @@
runOnHandler(() -> handleUpdateProxyApps(nfwLocationAccessProxyApps));
}
- void masterLocationSettingsUpdated(boolean enabled) {
- runOnHandler(() -> handleMasterLocationSettingsUpdated(enabled));
- }
-
void reportNfwNotification(String proxyAppPackageName, byte protocolStack,
String otherProtocolStackName, byte requestor, String requestorId, byte responseType,
boolean inEmergencyMode, boolean isCachedLocation) {
@@ -117,7 +112,19 @@
requestor, requestorId, responseType, inEmergencyMode, isCachedLocation)));
}
+ private void handleInitialize() {
+ disableNfwLocationAccess(); // Disable until config properties are loaded.
+ listenForProxyAppsPackageUpdates();
+ listenForDeviceLocationSettingsUpdate();
+ mIsDeviceLocationSettingsEnabled = getDeviceLocationSettings();
+ }
+
+ private boolean getDeviceLocationSettings() {
+ return mContext.getSystemService(LocationManager.class).isLocationEnabled();
+ }
+
private void listenForProxyAppsPackageUpdates() {
+ // Listen for proxy apps package installation, removal events.
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
@@ -143,11 +150,22 @@
}, UserHandle.ALL, intentFilter, null, mHandler);
}
+ private void listenForDeviceLocationSettingsUpdate() {
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCATION_MODE),
+ true,
+ new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ handleDeviceLocationSettingsUpdated();
+ }
+ }, UserHandle.USER_ALL);
+ }
+
private void handleProxyAppPackageUpdate(String pkgName, String action) {
final Boolean locationPermission = mProxyAppToLocationPermissions.get(pkgName);
- // pkgName is not one of the proxy apps in our list.
if (locationPermission == null) {
- return;
+ return; // ignore, pkgName is not one of the proxy apps in our list.
}
Log.i(TAG, "Proxy app " + pkgName + " package changed: " + action);
@@ -197,15 +215,33 @@
return true;
}
}
-
return false;
}
- private void handleMasterLocationSettingsUpdated(boolean enabled) {
- mIsMasterLocationSettingsEnabled = enabled;
- Log.i(TAG, "Master location settings switch changed to "
- + (enabled ? "enabled" : "disabled"));
- updateNfwLocationAccessProxyAppsInGnssHal();
+ private void handleDeviceLocationSettingsUpdated() {
+ final boolean enabled = getDeviceLocationSettings();
+ Log.i(TAG, "Device location settings enabled: " + enabled);
+
+ if (mIsDeviceLocationSettingsEnabled == enabled) {
+ return;
+ }
+
+ mIsDeviceLocationSettingsEnabled = enabled;
+ if (!mIsDeviceLocationSettingsEnabled) {
+ disableNfwLocationAccess();
+ return;
+ }
+
+ // When device location settings was disabled, we already set the proxy app list
+ // to empty in GNSS HAL. Update only if the proxy app list is not empty.
+ String[] locationPermissionEnabledProxyApps = getLocationPermissionEnabledProxyApps();
+ if (locationPermissionEnabledProxyApps.length != 0) {
+ setNfwLocationAccessProxyAppsInGnssHal(locationPermissionEnabledProxyApps);
+ }
+ }
+
+ private void disableNfwLocationAccess() {
+ setNfwLocationAccessProxyAppsInGnssHal(NO_LOCATION_ENABLED_PROXY_APPS);
}
// Represents NfwNotification structure in IGnssVisibilityControlCallback.hal
@@ -316,8 +352,7 @@
return mPackageManager.getApplicationInfo(pkgName, 0).uid;
} catch (PackageManager.NameNotFoundException e) {
if (DEBUG) {
- Log.d(TAG, "Non-framework location access proxy app "
- + pkgName + " is not found.");
+ Log.d(TAG, "Non-framework location access proxy app " + pkgName + " is not found.");
}
return null;
}
@@ -329,8 +364,14 @@
}
private void updateNfwLocationAccessProxyAppsInGnssHal() {
- final String[] locationPermissionEnabledProxyApps = shouldDisableNfwLocationAccess()
- ? NO_LOCATION_ENABLED_PROXY_APPS : getLocationPermissionEnabledProxyApps();
+ if (!mIsDeviceLocationSettingsEnabled) {
+ return; // Keep non-framework location access disabled.
+ }
+ setNfwLocationAccessProxyAppsInGnssHal(getLocationPermissionEnabledProxyApps());
+ }
+
+ private void setNfwLocationAccessProxyAppsInGnssHal(
+ String[] locationPermissionEnabledProxyApps) {
final String proxyAppsStr = Arrays.toString(locationPermissionEnabledProxyApps);
Log.i(TAG, "Updating non-framework location access proxy apps in the GNSS HAL to: "
+ proxyAppsStr);
@@ -341,12 +382,8 @@
}
}
- private boolean shouldDisableNfwLocationAccess() {
- return !mIsMasterLocationSettingsEnabled;
- }
-
private String[] getLocationPermissionEnabledProxyApps() {
- // Get a count of proxy apps with location permission enabled to array creation size.
+ // Get a count of proxy apps with location permission enabled for array creation size.
int countLocationPermissionEnabledProxyApps = 0;
for (Boolean hasLocationPermissionEnabled : mProxyAppToLocationPermissions.values()) {
if (hasLocationPermissionEnabled) {
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index e479a15..d0c59c1 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -320,6 +320,11 @@
private final class PackageReceiver extends BroadcastReceiver {
@Override
public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
+ final String action = intent.getAction();
+ if (action == null) {
+ Slog.e(TAG, "Cannot handle package broadcast with null action");
+ return;
+ }
final Uri data = intent.getData();
if (data == null) {
Slog.e(TAG, "Cannot handle package broadcast with null data");
@@ -337,7 +342,7 @@
userIds = new int[] { UserHandle.getUserId(extraUid) };
}
- switch (intent.getAction()) {
+ switch (action) {
case ACTION_PACKAGE_ADDED:
if (replacing) {
onPackageUpgraded(packageName, userIds);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 8608349..f5d88e3 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -84,7 +84,7 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.IoThread;
import com.android.server.LocalServices;
-import com.android.server.pm.permission.PermissionManagerInternal;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
import libcore.io.IoUtils;
@@ -131,7 +131,7 @@
private final Context mContext;
private final PackageManagerService mPm;
private final StagingManager mStagingManager;
- private final PermissionManagerInternal mPermissionManager;
+ private final PermissionManagerServiceInternal mPermissionManager;
private AppOpsManager mAppOps;
@@ -189,7 +189,7 @@
public PackageInstallerService(Context context, PackageManagerService pm, ApexManager am) {
mContext = context;
mPm = pm;
- mPermissionManager = LocalServices.getService(PermissionManagerInternal.class);
+ mPermissionManager = LocalServices.getService(PermissionManagerServiceInternal.class);
mInstallThread = new HandlerThread(TAG);
mInstallThread.start();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 61a1a2f..b1c186e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -238,7 +238,6 @@
import android.os.storage.StorageManagerInternal;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
-import android.permission.PermissionControllerManager;
import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.provider.Settings.Global;
@@ -291,7 +290,6 @@
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
-import com.android.internal.util.XmlUtils;
import com.android.server.AttributeCache;
import com.android.server.DeviceIdleController;
import com.android.server.EventLogTags;
@@ -315,9 +313,9 @@
import com.android.server.pm.permission.BasePermission;
import com.android.server.pm.permission.DefaultPermissionGrantPolicy;
import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback;
-import com.android.server.pm.permission.PermissionManagerInternal;
-import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback;
import com.android.server.pm.permission.PermissionManagerService;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback;
import com.android.server.pm.permission.PermissionsState;
import com.android.server.security.VerityUtils;
import com.android.server.storage.DeviceStorageMonitorInternal;
@@ -371,7 +369,6 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -445,8 +442,6 @@
private static final boolean ENABLE_FREE_CACHE_V2 =
SystemProperties.getBoolean("fw.free_cache_v2", true);
- private static final long BACKUP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(60);
-
private static final String PRECOMPILE_LAYOUTS = "pm.precompile_layouts";
private static final int RADIO_UID = Process.PHONE_UID;
@@ -940,7 +935,7 @@
// TODO remove this and go through mPermissonManager directly
final DefaultPermissionGrantPolicy mDefaultPermissionPolicy;
- private final PermissionManagerInternal mPermissionManager;
+ private final PermissionManagerServiceInternal mPermissionManager;
private final ComponentResolver mComponentResolver;
// List of packages names to keep cached, even if they are uninstalled for all users
@@ -1940,9 +1935,10 @@
}
}
- // We may also need to apply pending (restored) runtime
- // permission grants within these users.
- mSettings.applyPendingPermissionGrantsLPw(packageName, userId);
+ // We may also need to apply pending (restored) runtime permission grants
+ // within these users.
+ mPermissionManager.restoreDelayedRuntimePermissions(packageName,
+ UserHandle.of(userId));
// Persistent preferred activity might have came into effect due to this
// install.
@@ -18825,7 +18821,7 @@
// permission as requiring a review as this is the initial state.
int flags = 0;
if (ps.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M && bp.isRuntime()) {
- flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
+ flags |= FLAG_PERMISSION_REVIEW_REQUIRED | FLAG_PERMISSION_REVOKE_ON_UPGRADE;
}
if (permissionsState.updatePermissionFlags(bp, userId, userSettableMask, flags)) {
if (hasInstallState) {
@@ -19665,139 +19661,6 @@
}
@Override
- public byte[] getPermissionGrantBackup(int userId) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Only the system may call getPermissionGrantBackup()");
- }
-
- AtomicReference<byte[]> backup = new AtomicReference<>();
- mContext.getSystemService(PermissionControllerManager.class).getRuntimePermissionBackup(
- UserHandle.of(userId), mContext.getMainExecutor(), (b) -> {
- synchronized (backup) {
- backup.set(b);
- backup.notifyAll();
- }
- });
-
- long start = System.currentTimeMillis();
- synchronized (backup) {
- while (backup.get() == null) {
- long timeLeft = start + BACKUP_TIMEOUT_MILLIS - System.currentTimeMillis();
- if (timeLeft <= 0) {
- return null;
- }
-
- try {
- backup.wait(timeLeft);
- } catch (InterruptedException ignored) {
- return null;
- }
- }
- }
-
- return backup.get();
- }
-
- @Override
- public void restorePermissionGrants(byte[] backup, int userId) {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Only the system may call restorePermissionGrants()");
- }
-
- try {
- final XmlPullParser parser = Xml.newPullParser();
- parser.setInput(new ByteArrayInputStream(backup), StandardCharsets.UTF_8.name());
- restoreFromXml(parser, userId, TAG_PERMISSION_BACKUP,
- (parser1, userId1) -> {
- synchronized (mPackages) {
- processRestoredPermissionGrantsLPr(parser1, userId1);
- }
- });
- } catch (Exception e) {
- if (DEBUG_BACKUP) {
- Slog.e(TAG, "Exception restoring preferred activities: " + e.getMessage());
- }
- }
- }
-
- @GuardedBy("mPackages")
- private void processRestoredPermissionGrantsLPr(XmlPullParser parser, int userId)
- throws XmlPullParserException, IOException {
- String pkgName = null;
- 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;
- }
-
- final String tagName = parser.getName();
- if (tagName.equals(TAG_GRANT)) {
- pkgName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
- if (DEBUG_BACKUP) {
- Slog.v(TAG, "+++ Restoring grants for package " + pkgName);
- }
- } else if (tagName.equals(TAG_PERMISSION)) {
-
- final boolean isGranted = "true".equals(parser.getAttributeValue(null, ATTR_IS_GRANTED));
- final String permName = parser.getAttributeValue(null, ATTR_PERMISSION_NAME);
-
- int newFlagSet = 0;
- if ("true".equals(parser.getAttributeValue(null, ATTR_USER_SET))) {
- newFlagSet |= FLAG_PERMISSION_USER_SET;
- }
- if ("true".equals(parser.getAttributeValue(null, ATTR_USER_FIXED))) {
- newFlagSet |= FLAG_PERMISSION_USER_FIXED;
- }
- if ("true".equals(parser.getAttributeValue(null, ATTR_REVOKE_ON_UPGRADE))) {
- 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));
- }
- final PackageSetting ps = mSettings.mPackages.get(pkgName);
- if (ps != null) {
- // Already installed so we apply the grant immediately
- if (DEBUG_BACKUP) {
- Slog.v(TAG, " + already installed; applying");
- }
- PermissionsState perms = ps.getPermissionsState();
- 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);
- }
- }
- } else {
- // Need to wait for post-restore install to apply the grant
- if (DEBUG_BACKUP) {
- Slog.v(TAG, " - not yet installed; saving for later");
- }
- mSettings.processRestoredPermissionGrantLPr(pkgName, permName,
- isGranted, newFlagSet, userId);
- }
- } else {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Unknown element under <" + TAG_PERMISSION_BACKUP + ">: " + tagName);
- XmlUtils.skipCurrentTag(parser);
- }
- }
-
- scheduleWriteSettingsLocked();
- mSettings.writeRuntimePermissionsForUserLPr(userId, false);
- }
-
- @Override
public void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage,
int sourceUserId, int targetUserId, int flags) {
mContext.enforceCallingOrSelfPermission(
@@ -21285,10 +21148,6 @@
}
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS) && packageName == null) {
- mSettings.dumpRestoredPermissionGrantsLPr(pw, dumpState);
- }
-
if (!checkin && dumpState.isDumping(DumpState.DUMP_FROZEN) && packageName == null) {
// XXX should handle packageName != null by dumping only install data that
// the given package is involved with.
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 975ffb2..92fe377 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -19,10 +19,6 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
@@ -249,23 +245,6 @@
private static final String ATTR_SDK_VERSION = "sdkVersion";
private static final String ATTR_DATABASE_VERSION = "databaseVersion";
- // Bookkeeping for restored permission grants
- private static final String TAG_RESTORED_RUNTIME_PERMISSIONS = "restored-perms";
- // package name: ATTR_PACKAGE_NAME
- private static final String TAG_PERMISSION_ENTRY = "perm";
- // permission name: ATTR_NAME
- // permission granted (boolean): ATTR_GRANTED
- private static final String ATTR_USER_SET = "set";
- private static final String ATTR_USER_FIXED = "fixed";
- private static final String ATTR_REVOKE_ON_UPGRADE = "rou";
- private static final String ATTR_REVOKE_WHEN_REQUESTED = "rwr";
-
- // Flag mask of restored permission grants that are applied at install time
- private static final int USER_RUNTIME_GRANT_MASK =
- FLAG_PERMISSION_USER_SET
- | FLAG_PERMISSION_USER_FIXED
- | FLAG_PERMISSION_REVOKE_ON_UPGRADE;
-
private final Object mLock;
private final RuntimePermissionPersistence mRuntimePermissionsPersistence;
@@ -303,26 +282,6 @@
int[] excludedUserIds;
}
- // Bookkeeping for restored user permission grants
- final class RestoredPermissionGrant {
- String permissionName;
- boolean granted;
- int grantBits;
-
- RestoredPermissionGrant(String name, boolean isGranted, int theGrantBits) {
- permissionName = name;
- granted = isGranted;
- grantBits = theGrantBits;
- }
- }
-
- // This would be more compact as a flat array of restored grants or something, but we
- // may have quite a few, especially during early device lifetime, and avoiding all those
- // linear lookups will be important.
- private final SparseArray<ArrayMap<String, ArraySet<RestoredPermissionGrant>>>
- mRestoredUserGrants =
- new SparseArray<ArrayMap<String, ArraySet<RestoredPermissionGrant>>>();
-
private static int mFirstAvailableUid = 0;
/** Map from volume UUID to {@link VersionInfo} */
@@ -461,43 +420,6 @@
return mRenamedPackages.put(pkgName, origPkgName);
}
- void applyPendingPermissionGrantsLPw(String packageName, int userId) {
- ArrayMap<String, ArraySet<RestoredPermissionGrant>> grantsByPackage =
- mRestoredUserGrants.get(userId);
- if (grantsByPackage == null || grantsByPackage.size() == 0) {
- return;
- }
-
- ArraySet<RestoredPermissionGrant> grants = grantsByPackage.get(packageName);
- if (grants == null || grants.size() == 0) {
- return;
- }
-
- final PackageSetting ps = mPackages.get(packageName);
- if (ps == null) {
- Slog.e(TAG, "Can't find supposedly installed package " + packageName);
- return;
- }
- final PermissionsState perms = ps.getPermissionsState();
-
- for (RestoredPermissionGrant grant : grants) {
- BasePermission bp = mPermissions.getPermission(grant.permissionName);
- if (bp != null) {
- if (grant.granted) {
- perms.grantRuntimePermission(bp, userId);
- }
- perms.updatePermissionFlags(bp, userId, USER_RUNTIME_GRANT_MASK, grant.grantBits);
- }
- }
-
- // And remove it from the pending-grant bookkeeping
- grantsByPackage.remove(packageName);
- if (grantsByPackage.size() < 1) {
- mRestoredUserGrants.remove(userId);
- }
- writeRuntimePermissionsForUserLPr(userId, false);
- }
-
public boolean canPropagatePermissionToInstantApp(String permName) {
return mPermissions.canPropagatePermissionToInstantApp(permName);
}
@@ -1982,13 +1904,6 @@
}
}
- // Specifically for backup/restore
- public void processRestoredPermissionGrantLPr(String pkgName, String permission,
- boolean isGranted, int restoredFlagSet, int userId) {
- mRuntimePermissionsPersistence.rememberRestoredUserGrantLPr(
- pkgName, permission, isGranted, restoredFlagSet, userId);
- }
-
void writeDefaultAppsLPr(XmlSerializer serializer, int userId)
throws IllegalArgumentException, IllegalStateException, IOException {
serializer.startTag(null, TAG_DEFAULT_APPS);
@@ -5014,51 +4929,6 @@
pw.print(mReadMessages.toString());
}
- void dumpRestoredPermissionGrantsLPr(PrintWriter pw, DumpState dumpState) {
- if (mRestoredUserGrants.size() > 0) {
- pw.println();
- pw.println("Restored (pending) permission grants:");
- for (int userIndex = 0; userIndex < mRestoredUserGrants.size(); userIndex++) {
- ArrayMap<String, ArraySet<RestoredPermissionGrant>> grantsByPackage =
- mRestoredUserGrants.valueAt(userIndex);
- if (grantsByPackage != null && grantsByPackage.size() > 0) {
- final int userId = mRestoredUserGrants.keyAt(userIndex);
- pw.print(" User "); pw.println(userId);
-
- for (int pkgIndex = 0; pkgIndex < grantsByPackage.size(); pkgIndex++) {
- ArraySet<RestoredPermissionGrant> grants = grantsByPackage.valueAt(pkgIndex);
- if (grants != null && grants.size() > 0) {
- final String pkgName = grantsByPackage.keyAt(pkgIndex);
- pw.print(" "); pw.print(pkgName); pw.println(" :");
-
- for (RestoredPermissionGrant g : grants) {
- pw.print(" ");
- pw.print(g.permissionName);
- if (g.granted) {
- pw.print(" GRANTED");
- }
- if ((g.grantBits&FLAG_PERMISSION_USER_SET) != 0) {
- pw.print(" user_set");
- }
- if ((g.grantBits&FLAG_PERMISSION_USER_FIXED) != 0) {
- pw.print(" user_fixed");
- }
- if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
- pw.print(" revoke_on_upgrade");
- }
- if ((g.grantBits & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) {
- pw.print(" revoke_when_requested");
- }
- pw.println();
- }
- }
- }
- }
- }
- pw.println();
- }
- }
-
private static void dumpSplitNames(PrintWriter pw, PackageParser.Package pkg) {
if (pkg == null) {
pw.print("unknown");
@@ -5328,55 +5198,6 @@
serializer.endTag(null, TAG_RUNTIME_PERMISSIONS);
- // Now any restored permission grants that are waiting for the apps
- // in question to be installed. These are stored as per-package
- // TAG_RESTORED_RUNTIME_PERMISSIONS blocks, each containing some
- // number of individual permission grant entities.
- if (mRestoredUserGrants.get(userId) != null) {
- ArrayMap<String, ArraySet<RestoredPermissionGrant>> restoredGrants =
- mRestoredUserGrants.get(userId);
- if (restoredGrants != null) {
- final int pkgCount = restoredGrants.size();
- for (int i = 0; i < pkgCount; i++) {
- final ArraySet<RestoredPermissionGrant> pkgGrants =
- restoredGrants.valueAt(i);
- if (pkgGrants != null && pkgGrants.size() > 0) {
- final String pkgName = restoredGrants.keyAt(i);
- serializer.startTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS);
- serializer.attribute(null, ATTR_PACKAGE_NAME, pkgName);
-
- final int N = pkgGrants.size();
- for (int z = 0; z < N; z++) {
- RestoredPermissionGrant g = pkgGrants.valueAt(z);
- serializer.startTag(null, TAG_PERMISSION_ENTRY);
- serializer.attribute(null, ATTR_NAME, g.permissionName);
-
- if (g.granted) {
- serializer.attribute(null, ATTR_GRANTED, "true");
- }
-
- if ((g.grantBits&FLAG_PERMISSION_USER_SET) != 0) {
- serializer.attribute(null, ATTR_USER_SET, "true");
- }
- if ((g.grantBits&FLAG_PERMISSION_USER_FIXED) != 0) {
- serializer.attribute(null, ATTR_USER_FIXED, "true");
- }
- if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
- serializer.attribute(null, ATTR_REVOKE_ON_UPGRADE, "true");
- }
- if ((g.grantBits & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED)
- != 0) {
- serializer.attribute(null, ATTR_REVOKE_WHEN_REQUESTED,
- "true");
- }
- serializer.endTag(null, TAG_PERMISSION_ENTRY);
- }
- serializer.endTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS);
- }
- }
- }
- }
-
serializer.endDocument();
destination.finishWrite(out);
@@ -5455,29 +5276,6 @@
}
}
- // Backup/restore support
-
- public void rememberRestoredUserGrantLPr(String pkgName, String permission,
- boolean isGranted, int restoredFlagSet, int userId) {
- // This change will be remembered at write-settings time
- ArrayMap<String, ArraySet<RestoredPermissionGrant>> grantsByPackage =
- mRestoredUserGrants.get(userId);
- if (grantsByPackage == null) {
- grantsByPackage = new ArrayMap<String, ArraySet<RestoredPermissionGrant>>();
- mRestoredUserGrants.put(userId, grantsByPackage);
- }
-
- ArraySet<RestoredPermissionGrant> grants = grantsByPackage.get(pkgName);
- if (grants == null) {
- grants = new ArraySet<RestoredPermissionGrant>();
- grantsByPackage.put(pkgName, grants);
- }
-
- RestoredPermissionGrant grant = new RestoredPermissionGrant(permission,
- isGranted, restoredFlagSet);
- grants.add(grant);
- }
-
// Private internals
@GuardedBy("Settings.this.mLock")
@@ -5520,50 +5318,6 @@
}
parsePermissionsLPr(parser, sus.getPermissionsState(), userId);
} break;
-
- case TAG_RESTORED_RUNTIME_PERMISSIONS: {
- final String pkgName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
- parseRestoredRuntimePermissionsLPr(parser, pkgName, userId);
- } break;
- }
- }
- }
-
- private void parseRestoredRuntimePermissionsLPr(XmlPullParser parser,
- final String pkgName, final int userId) 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;
- }
-
- switch (parser.getName()) {
- case TAG_PERMISSION_ENTRY: {
- final String permName = parser.getAttributeValue(null, ATTR_NAME);
- final boolean isGranted = "true".equals(
- parser.getAttributeValue(null, ATTR_GRANTED));
-
- int permBits = 0;
- if ("true".equals(parser.getAttributeValue(null, ATTR_USER_SET))) {
- permBits |= FLAG_PERMISSION_USER_SET;
- }
- if ("true".equals(parser.getAttributeValue(null, ATTR_USER_FIXED))) {
- permBits |= FLAG_PERMISSION_USER_FIXED;
- }
- if ("true".equals(parser.getAttributeValue(null, ATTR_REVOKE_ON_UPGRADE))) {
- permBits |= FLAG_PERMISSION_REVOKE_ON_UPGRADE;
- }
- if ("true".equals(parser.getAttributeValue(null,
- ATTR_REVOKE_WHEN_REQUESTED))) {
- permBits |= FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
- }
-
- if (isGranted || permBits != 0) {
- rememberRestoredUserGrantLPr(pkgName, permName, isGranted, permBits, userId);
- }
- } break;
}
}
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 38940d6..f56b984 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -30,6 +30,7 @@
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
@@ -43,6 +44,9 @@
import static com.android.server.pm.PackageManagerService.DEBUG_PERMISSIONS;
import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_FAILURE;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
import android.Manifest;
import android.annotation.NonNull;
@@ -69,7 +73,9 @@
import android.os.UserManagerInternal;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
+import android.permission.PermissionControllerManager;
import android.permission.PermissionManager;
+import android.permission.PermissionManagerInternal;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -77,6 +83,7 @@
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
@@ -91,9 +98,8 @@
import com.android.server.pm.PackageSetting;
import com.android.server.pm.SharedUserSetting;
import com.android.server.pm.UserManagerService;
-import com.android.server.pm.permission.DefaultPermissionGrantPolicy
- .DefaultPermissionGrantedCallback;
-import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback;
+import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback;
+import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback;
import com.android.server.pm.permission.PermissionsState.PermissionState;
import libcore.util.EmptyArray;
@@ -106,6 +112,10 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* Manages all permissions and handles permissions related tasks.
@@ -122,6 +132,8 @@
/** Permission grant: grant as runtime a permission that was granted as an install time one. */
private static final int GRANT_UPGRADE = 4;
+ private static final long BACKUP_TIMEOUT_MILLIS = SECONDS.toMillis(60);
+
/** Cap the size of permission trees that 3rd party apps can define; in characters of text */
private static final int MAX_PERMISSION_TREE_FOOTPRINT = 32768;
/** Empty array to avoid allocations */
@@ -146,6 +158,9 @@
/** Internal connection to the user manager */
private final UserManagerInternal mUserManagerInt;
+ /** Permission controller: User space permission management */
+ private PermissionControllerManager mPermissionControllerManager;
+
/** Default permission policy to provide proper behaviour out-of-the-box */
private final DefaultPermissionGrantPolicy mDefaultPermissionGrantPolicy;
@@ -180,6 +195,16 @@
@GuardedBy("mLock")
private ArrayMap<String, List<String>> mBackgroundPermissions;
+ /**
+ * A permission backup might contain apps that are not installed. In this case we delay the
+ * restoration until the app is installed.
+ *
+ * <p>This array ({@code userId -> noDelayedBackupLeft}) is {@code true} for all the users where
+ * there is <u>no more</u> delayed backup left.
+ */
+ @GuardedBy("mLock")
+ private final SparseBooleanArray mHasNoDelayedPermBackup = new SparseBooleanArray();
+
PermissionManagerService(Context context,
@Nullable DefaultPermissionGrantedCallback defaultGrantCallback,
@NonNull Object externalLock) {
@@ -218,29 +243,31 @@
}
}
- LocalServices.addService(
- PermissionManagerInternal.class, new PermissionManagerInternalImpl());
+ PermissionManagerServiceInternalImpl localService =
+ new PermissionManagerServiceInternalImpl();
+ LocalServices.addService(PermissionManagerServiceInternal.class, localService);
+ LocalServices.addService(PermissionManagerInternal.class, localService);
}
/**
* 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);}
+ * {@code LocalServices.getService(PermissionManagerServiceInternal.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,
+ public static PermissionManagerServiceInternal create(Context context,
@Nullable DefaultPermissionGrantedCallback defaultGrantCallback,
@NonNull Object externalLock) {
- final PermissionManagerInternal permMgrInt =
- LocalServices.getService(PermissionManagerInternal.class);
+ final PermissionManagerServiceInternal permMgrInt =
+ LocalServices.getService(PermissionManagerServiceInternal.class);
if (permMgrInt != null) {
return permMgrInt;
}
new PermissionManagerService(context, defaultGrantCallback, externalLock);
- return LocalServices.getService(PermissionManagerInternal.class);
+ return LocalServices.getService(PermissionManagerServiceInternal.class);
}
@Nullable BasePermission getPermission(String permName) {
@@ -332,6 +359,74 @@
}
/**
+ * Get the state of the runtime permissions as xml file.
+ *
+ * <p>Can not be called on main thread.
+ *
+ * @param user The user the data should be extracted for
+ *
+ * @return The state as a xml file
+ */
+ private @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user) {
+ CompletableFuture<byte[]> backup = new CompletableFuture<>();
+ mPermissionControllerManager.getRuntimePermissionBackup(user, mContext.getMainExecutor(),
+ backup::complete);
+
+ try {
+ return backup.get(BACKUP_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ Slog.e(TAG, "Cannot create permission backup for " + user, e);
+ return null;
+ }
+ }
+
+ /**
+ * Restore a permission state previously backed up via {@link #backupRuntimePermissions}.
+ *
+ * <p>If not all state can be restored, the un-appliable state will be delayed and can be
+ * applied via {@link #restoreDelayedRuntimePermissions}.
+ *
+ * @param backup The state as an xml file
+ * @param user The user the data should be restored for
+ */
+ private void restoreRuntimePermissions(@NonNull byte[] backup, @NonNull UserHandle user) {
+ synchronized (mLock) {
+ mHasNoDelayedPermBackup.delete(user.getIdentifier());
+ mPermissionControllerManager.restoreRuntimePermissionBackup(backup, user);
+ }
+ }
+
+ /**
+ * Try to apply permission backup that was previously not applied.
+ *
+ * <p>Can not be called on main thread.
+ *
+ * @param packageName The package that is newly installed
+ * @param user The user the package is installed for
+ *
+ * @see #restoreRuntimePermissions
+ */
+ private void restoreDelayedRuntimePermissions(@NonNull String packageName,
+ @NonNull UserHandle user) {
+ synchronized (mLock) {
+ if (mHasNoDelayedPermBackup.get(user.getIdentifier(), false)) {
+ return;
+ }
+
+ mPermissionControllerManager.restoreDelayedRuntimePermissionBackup(packageName, user,
+ mContext.getMainExecutor(), (hasMoreBackup) -> {
+ if (hasMoreBackup) {
+ return;
+ }
+
+ synchronized (mLock) {
+ mHasNoDelayedPermBackup.put(user.getIdentifier(), true);
+ }
+ });
+ }
+ }
+
+ /**
* Returns {@code true} if the permission can be implied from another granted permission.
* <p>Some permissions, such as ACCESS_FINE_LOCATION, imply other permissions,
* such as ACCESS_COURSE_LOCATION. If the caller holds an umbrella permission, give
@@ -741,7 +836,6 @@
if (ps == null) {
return;
}
- final boolean isLegacySystemApp = mPackageManagerInt.isLegacySystemApp(pkg);
final PermissionsState permissionsState = ps.getPermissionsState();
PermissionsState origPermissions = permissionsState;
@@ -828,17 +922,9 @@
// For all apps normal permissions are install time ones.
grant = GRANT_INSTALL;
} else if (bp.isRuntime()) {
- // 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 (origPermissions.hasInstallPermission(bp.getName())) {
- // For legacy apps that became modern, install becomes runtime.
- grant = GRANT_UPGRADE;
- } else if (isLegacySystemApp) {
- // For legacy system apps, install becomes runtime.
- // We cannot check hasInstallPermission() for system apps since those
- // permissions were granted implicitly and not persisted pre-M.
+ // Before Q we represented some runtime permissions as install permissions,
+ // in Q we cannot do this anymore. Hence upgrade them all.
grant = GRANT_UPGRADE;
} else {
// For modern apps keep runtime permissions unchanged.
@@ -891,110 +977,111 @@
}
// Grant an install permission.
if (permissionsState.grantInstallPermission(bp) !=
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ PERMISSION_OPERATION_FAILURE) {
changedInstallPermission = true;
}
} break;
case GRANT_RUNTIME: {
- // Grant previously granted runtime permissions.
- for (int userId : UserManagerService.getInstance().getUserIds()) {
- final PermissionState permissionState = origPermissions
+ for (int userId : currentUserIds) {
+ PermissionState permState = origPermissions
.getRuntimePermissionState(perm, userId);
- int flags = permissionState != null
- ? permissionState.getFlags() : 0;
- if (origPermissions.hasRuntimePermission(perm, userId)) {
- // Don't propagate the permission in a permission review
- // mode if the former was revoked, i.e. marked to not
- // propagate on upgrade. Note that in a permission review
- // mode install permissions are represented as constantly
- // granted runtime ones since we need to keep a per user
- // state associated with the permission. Also the revoke
- // on upgrade flag is no longer applicable and is reset.
- final boolean revokeOnUpgrade = (flags & PackageManager
- .FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0;
- if (revokeOnUpgrade) {
- flags &= ~PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
- // Since we changed the flags, we have to write.
- updatedUserIds = ArrayUtils.appendInt(
- updatedUserIds, userId);
+ int flags = permState != null ? permState.getFlags() : 0;
+
+ boolean wasChanged = false;
+
+ if (appSupportsRuntimePermissions) {
+ // Remove review flag as it is not necessary anymore
+ if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
+ flags &= ~FLAG_PERMISSION_REVIEW_REQUIRED;
+ wasChanged = true;
}
- if (!revokeOnUpgrade) {
- if (permissionsState.grantRuntimePermission(bp, userId) ==
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- // If we cannot put the permission as it was,
- // we have to write.
- updatedUserIds = ArrayUtils.appendInt(
- updatedUserIds, userId);
+
+ if ((flags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
+ flags &= ~FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+ wasChanged = true;
+ } else {
+ if (permState != null && permState.isGranted()) {
+ if (permissionsState.grantRuntimePermission(bp, userId)
+ == PERMISSION_OPERATION_FAILURE) {
+ wasChanged = true;
+ }
+ }
+ }
+ } else {
+ if (permState == null) {
+ // New permission
+ if (PLATFORM_PACKAGE_NAME.equals(
+ bp.getSourcePackageName())) {
+ if (!bp.isRemoved()) {
+ flags |= FLAG_PERMISSION_REVIEW_REQUIRED
+ | FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+ wasChanged = true;
+ }
}
}
- // If the app supports runtime permissions no need for a review.
- if (appSupportsRuntimePermissions
- && (flags & PackageManager
- .FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
- flags &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
- // Since we changed the flags, we have to write.
- updatedUserIds = ArrayUtils.appendInt(
- updatedUserIds, userId);
- }
- } else if (!appSupportsRuntimePermissions) {
- // For legacy apps that need a permission review, every new
- // runtime permission is granted but it is pending a review.
- // We also need to review only platform defined runtime
- // permissions as these are the only ones the platform knows
- // how to disable the API to simulate revocation as legacy
- // apps don't expect to run with revoked permissions.
- if (PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName())) {
- if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0
- && !bp.isRemoved()) {
- flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
- // We changed the flags, hence have to write.
- updatedUserIds = ArrayUtils.appendInt(
- updatedUserIds, userId);
- }
- }
if (permissionsState.grantRuntimePermission(bp, userId)
- != PermissionsState.PERMISSION_OPERATION_FAILURE) {
- // We changed the permission, hence have to write.
- updatedUserIds = ArrayUtils.appendInt(
- updatedUserIds, userId);
+ != PERMISSION_OPERATION_FAILURE) {
+ wasChanged = true;
}
}
- // Propagate the permission flags.
+
+ if (wasChanged) {
+ updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
+ }
+
permissionsState.updatePermissionFlags(bp, userId, flags, flags);
}
} break;
case GRANT_UPGRADE: {
- // Grant runtime permissions for a previously held install permission.
- final PermissionState permissionState = origPermissions
+ // Upgrade from Pre-Q to Q permission model. Make all permissions
+ // runtime
+ PermissionState permState = origPermissions
.getInstallPermissionState(perm);
- final int flags =
- (permissionState != null) ? permissionState.getFlags() : 0;
+ int flags = (permState != null) ? permState.getFlags() : 0;
+ // Remove install permission
if (origPermissions.revokeInstallPermission(bp)
- != PermissionsState.PERMISSION_OPERATION_FAILURE) {
- // We will be transferring the permission flags, so clear them.
+ != PERMISSION_OPERATION_FAILURE) {
origPermissions.updatePermissionFlags(bp, UserHandle.USER_ALL,
PackageManager.MASK_PERMISSION_FLAGS, 0);
changedInstallPermission = true;
}
- // If the permission is not to be promoted to runtime we ignore it and
- // also its other flags as they are not applicable to install permissions.
- if ((flags & PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE) == 0) {
- for (int userId : currentUserIds) {
+ for (int userId : currentUserIds) {
+ boolean wasChanged = false;
+
+ if (appSupportsRuntimePermissions) {
+ // Remove review flag as it is not necessary anymore
+ if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
+ flags &= ~FLAG_PERMISSION_REVIEW_REQUIRED;
+ wasChanged = true;
+ }
+
+ if ((flags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {
+ flags &= ~FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+ wasChanged = true;
+ } else {
+ if (permissionsState.grantRuntimePermission(bp, userId) !=
+ PERMISSION_OPERATION_FAILURE) {
+ wasChanged = true;
+ }
+ }
+ } else {
if (permissionsState.grantRuntimePermission(bp, userId) !=
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- // Transfer the permission flags.
- permissionsState.updatePermissionFlags(bp, userId,
- flags, flags);
- // If we granted the permission, we have to write.
- updatedUserIds = ArrayUtils.appendInt(
- updatedUserIds, userId);
+ PERMISSION_OPERATION_FAILURE) {
+ flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
+ wasChanged = true;
}
}
+
+ if (wasChanged) {
+ updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
+ }
+
+ permissionsState.updatePermissionFlags(bp, userId, flags, flags);
}
} break;
@@ -1011,7 +1098,7 @@
}
} else {
if (permissionsState.revokeInstallPermission(bp) !=
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ PERMISSION_OPERATION_FAILURE) {
// Also drop the permission flags.
permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
PackageManager.MASK_PERMISSION_FLAGS, 0);
@@ -1094,6 +1181,10 @@
@NonNull int[] updatedUserIds) {
AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
+ if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+ return updatedUserIds;
+ }
+
String pkgName = pkg.packageName;
int[] users = UserManagerService.getInstance().getUserIds();
@@ -1119,26 +1210,14 @@
if ((flags & (FLAG_PERMISSION_GRANTED_BY_DEFAULT
| FLAG_PERMISSION_POLICY_FIXED | FLAG_PERMISSION_SYSTEM_FIXED))
== 0) {
- if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
- if (permissionToOpCode(permission) != OP_NONE) {
- setAppOpMode(permission, pkg, userId, MODE_IGNORED);
+ int revokeResult = ps.revokeRuntimePermission(bp, userId);
+ if (revokeResult
+ != PERMISSION_OPERATION_FAILURE) {
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, "Revoking app-op "
- + permissionToOp(permission) + " for " + pkgName
- + " as it is now requested");
- }
- }
- } else {
- int revokeResult = ps.revokeRuntimePermission(bp, userId);
- if (revokeResult
- != PermissionsState.PERMISSION_OPERATION_FAILURE) {
-
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, "Revoking runtime permission " + permission
- + " for " + pkgName
- + " as it is now requested");
- }
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, "Revoking runtime permission " + permission
+ + " for " + pkgName
+ + " as it is now requested");
}
}
@@ -1925,7 +2004,7 @@
// 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) {
+ PERMISSION_OPERATION_FAILURE) {
if (callback != null) {
callback.onInstallPermissionGranted();
}
@@ -1945,7 +2024,7 @@
final int result = permissionsState.grantRuntimePermission(bp, userId);
switch (result) {
- case PermissionsState.PERMISSION_OPERATION_FAILURE: {
+ case PERMISSION_OPERATION_FAILURE: {
return;
}
@@ -2045,7 +2124,7 @@
// 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) {
+ PERMISSION_OPERATION_FAILURE) {
if (callback != null) {
callback.onInstallPermissionRevoked();
}
@@ -2054,7 +2133,7 @@
}
if (permissionsState.revokeRuntimePermission(bp, userId) ==
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ PERMISSION_OPERATION_FAILURE) {
return;
}
@@ -2522,6 +2601,8 @@
throw new IllegalStateException("Signature|privileged permissions not in "
+ "privapp-permissions whitelist: " + mPrivappPermissionsViolations);
}
+
+ mPermissionControllerManager = mContext.getSystemService(PermissionControllerManager.class);
}
private static String getVolumeUuidForPackage(PackageParser.Package pkg) {
@@ -2574,7 +2655,7 @@
return mBackgroundPermissions;
}
- private class PermissionManagerInternalImpl extends PermissionManagerInternal {
+ private class PermissionManagerServiceInternalImpl extends PermissionManagerServiceInternal {
@Override
public void systemReady() {
PermissionManagerService.this.systemReady();
@@ -2737,5 +2818,21 @@
return mSettings.getPermissionLocked(permName);
}
}
+
+ @Override
+ public @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user) {
+ return PermissionManagerService.this.backupRuntimePermissions(user);
+ }
+
+ @Override
+ public void restoreRuntimePermissions(@NonNull byte[] backup, @NonNull UserHandle user) {
+ PermissionManagerService.this.restoreRuntimePermissions(backup, user);
+ }
+
+ @Override
+ public void restoreDelayedRuntimePermissions(@NonNull String packageName,
+ @NonNull UserHandle user) {
+ PermissionManagerService.this.restoreDelayedRuntimePermissions(packageName, user);
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
similarity index 96%
rename from services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
rename to services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index f4979746..1dd2408 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -18,19 +18,22 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.PackageManager.PermissionInfoFlags;
import android.content.pm.PackageParser;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
-import android.content.pm.PackageManager.PermissionInfoFlags;
+import android.permission.PermissionManagerInternal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
- * Internal interfaces to be used by other components within the system server.
+ * Internal interfaces services.
+ *
+ * TODO: Should be merged into PermissionManagerInternal, but currently uses internal classes.
*/
-public abstract class PermissionManagerInternal {
+public abstract class PermissionManagerServiceInternal extends PermissionManagerInternal {
/**
* Callbacks invoked when interesting actions have been taken on a permission.
* <p>
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index 0892b32..2280d3f 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -16,6 +16,9 @@
},
{
"include-filter": "android.permission.cts.SplitPermissionTest"
+ },
+ {
+ "include-filter": "android.permission.cts.PermissionFlagsTest"
}
]
},
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index edca2e3..4815e5c 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -85,7 +85,9 @@
import android.os.Temperature;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.DiskInfo;
import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
import android.telephony.ModemActivityInfo;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
@@ -1956,6 +1958,27 @@
pulledData.add(e);
}
+ private void pullSDCardInfo(int tagId, long elapsedNanos, long wallClockNanos,
+ List<StatsLogEventWrapper> pulledData) {
+ StorageManager storageManager = mContext.getSystemService(StorageManager.class);
+ if (storageManager != null) {
+ List<VolumeInfo> volumes = storageManager.getVolumes();
+ for (VolumeInfo vol : volumes) {
+ final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
+ final DiskInfo diskInfo = vol.getDisk();
+ if (diskInfo != null && diskInfo.isSd()) {
+ if (envState.equals(Environment.MEDIA_MOUNTED)) {
+ StatsLogEventWrapper e =
+ new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
+ e.writeInt(vol.getType() + 1);
+ e.writeLong(diskInfo.size);
+ pulledData.add(e);
+ }
+ }
+ }
+ }
+ }
+
/**
* Pulls various data.
*/
@@ -2148,6 +2171,10 @@
pullTimeZoneDataInfo(tagId, elapsedNanos, wallClockNanos, ret);
break;
}
+ case StatsLog.SDCARD_INFO: {
+ pullSDCardInfo(tagId, elapsedNanos, wallClockNanos, ret);
+ break;
+ }
default:
Slog.w(TAG, "No such tagId data as " + tagId);
return null;
diff --git a/services/core/java/com/android/server/telecom/TelecomLoaderService.java b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
index 7a3f030..f581bc0 100644
--- a/services/core/java/com/android/server/telecom/TelecomLoaderService.java
+++ b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
@@ -44,7 +44,7 @@
import com.android.server.SystemService;
import com.android.server.pm.UserManagerService;
import com.android.server.pm.permission.DefaultPermissionGrantPolicy;
-import com.android.server.pm.permission.PermissionManagerInternal;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
/**
* Starts the telecom component by binding to its ITelecomService implementation. Telecom is setup
@@ -133,7 +133,7 @@
}
private DefaultPermissionGrantPolicy getDefaultPermissionGrantPolicy() {
- return LocalServices.getService(PermissionManagerInternal.class)
+ return LocalServices.getService(PermissionManagerServiceInternal.class)
.getDefaultPermissionGrantPolicy();
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 168c9ad..899bf7c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5090,11 +5090,7 @@
@Override
public void startWindowTrace(){
- try {
- mWindowTracing.startTrace(null /* printwriter */);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
+ mWindowTracing.startTrace(null /* printwriter */);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowTraceBuffer.java b/services/core/java/com/android/server/wm/WindowTraceBuffer.java
index e4461ea..2ce6e6c 100644
--- a/services/core/java/com/android/server/wm/WindowTraceBuffer.java
+++ b/services/core/java/com/android/server/wm/WindowTraceBuffer.java
@@ -20,7 +20,6 @@
import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_H;
import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_L;
-import android.os.Trace;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
@@ -36,24 +35,30 @@
/**
* Buffer used for window tracing.
*/
-abstract class WindowTraceBuffer {
+class WindowTraceBuffer {
private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
- final Object mBufferLock = new Object();
- final Queue<ProtoOutputStream> mBuffer = new ArrayDeque<>();
- final File mTraceFile;
- int mBufferSize;
- private final int mBufferCapacity;
+ private final Object mBufferLock = new Object();
- WindowTraceBuffer(int size, File traceFile) throws IOException {
- mBufferCapacity = size;
- mTraceFile = traceFile;
+ private final Queue<ProtoOutputStream> mBuffer = new ArrayDeque<>();
+ private int mBufferUsedSize;
+ private int mBufferCapacity;
- initTraceFile();
+ WindowTraceBuffer(int bufferCapacity) {
+ mBufferCapacity = bufferCapacity;
+ resetBuffer();
}
int getAvailableSpace() {
- return mBufferCapacity - mBufferSize;
+ return mBufferCapacity - mBufferUsedSize;
+ }
+
+ int size() {
+ return mBuffer.size();
+ }
+
+ void setCapacity(int capacity) {
+ mBufferCapacity = capacity;
}
/**
@@ -70,42 +75,37 @@
+ mBufferCapacity + " Object size: " + protoLength);
}
synchronized (mBufferLock) {
- boolean canAdd = canAdd(protoLength);
- if (canAdd) {
- mBuffer.add(proto);
- mBufferSize += protoLength;
- }
+ discardOldest(protoLength);
+ mBuffer.add(proto);
+ mBufferUsedSize += protoLength;
mBufferLock.notify();
}
}
- /**
- * Stops the buffer execution and flush all buffer content to the disk.
- *
- * @throws IOException if the buffer cannot write its contents to the {@link #mTraceFile}
- */
- void dump() throws IOException, InterruptedException {
- try {
- Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeTraceToFile");
- writeTraceToFile();
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
- }
- }
-
- @VisibleForTesting
boolean contains(byte[] other) {
return mBuffer.stream()
.anyMatch(p -> Arrays.equals(p.getBytes(), other));
}
- private void initTraceFile() throws IOException {
- mTraceFile.delete();
- try (OutputStream os = new FileOutputStream(mTraceFile)) {
- mTraceFile.setReadable(true, false);
- ProtoOutputStream proto = new ProtoOutputStream(os);
- proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
- proto.flush();
+ /**
+ * Writes the trace buffer to disk.
+ */
+ void writeTraceToFile(File traceFile) throws IOException {
+ synchronized (mBufferLock) {
+ traceFile.delete();
+ traceFile.setReadable(true, false);
+ try (OutputStream os = new FileOutputStream(traceFile)) {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
+ os.write(proto.getBytes());
+ while (!mBuffer.isEmpty()) {
+ proto = mBuffer.poll();
+ mBufferUsedSize -= proto.getRawSize();
+ byte[] protoBytes = proto.getBytes();
+ os.write(protoBytes);
+ }
+ os.flush();
+ }
}
}
@@ -114,59 +114,48 @@
* smaller than the overall buffer size.
*
* @param protoLength byte array representation of the Proto object to add
- * @return {@code true} if the element can be added to the buffer or not
*/
- abstract boolean canAdd(int protoLength);
+ private void discardOldest(int protoLength) {
+ long availableSpace = getAvailableSpace();
+
+ while (availableSpace < protoLength) {
+
+ ProtoOutputStream item = mBuffer.poll();
+ if (item == null) {
+ throw new IllegalStateException("No element to discard from buffer");
+ }
+ mBufferUsedSize -= item.getRawSize();
+ availableSpace = getAvailableSpace();
+ }
+ }
/**
- * Flush all buffer content to the disk.
- *
- * @throws IOException if the buffer cannot write its contents to the {@link #mTraceFile}
+ * Removes all elements form the buffer
*/
- abstract void writeTraceToFile() throws IOException, InterruptedException;
-
- /**
- * Builder for a {@code WindowTraceBuffer} which creates a {@link WindowTraceRingBuffer} for
- * continuous mode or a {@link WindowTraceQueueBuffer} otherwise
- */
- static class Builder {
- private boolean mContinuous;
- private File mTraceFile;
- private int mBufferCapacity;
-
- Builder setContinuousMode(boolean continuous) {
- mContinuous = continuous;
- return this;
+ void resetBuffer() {
+ synchronized (mBufferLock) {
+ mBuffer.clear();
+ mBufferUsedSize = 0;
}
+ }
- Builder setTraceFile(File traceFile) {
- mTraceFile = traceFile;
- return this;
- }
+ @VisibleForTesting
+ int getBufferSize() {
+ return mBufferUsedSize;
+ }
- Builder setBufferCapacity(int size) {
- mBufferCapacity = size;
- return this;
- }
-
- File getFile() {
- return mTraceFile;
- }
-
- WindowTraceBuffer build() throws IOException {
- if (mBufferCapacity <= 0) {
- throw new IllegalStateException("Buffer capacity must be greater than 0.");
- }
-
- if (mTraceFile == null) {
- throw new IllegalArgumentException("A valid trace file must be specified.");
- }
-
- if (mContinuous) {
- return new WindowTraceRingBuffer(mBufferCapacity, mTraceFile);
- } else {
- return new WindowTraceQueueBuffer(mBufferCapacity, mTraceFile);
- }
+ String getStatus() {
+ synchronized (mBufferLock) {
+ return "Buffer size: "
+ + mBufferCapacity
+ + " bytes"
+ + "\n"
+ + "Buffer usage: "
+ + mBufferUsedSize
+ + " bytes"
+ + "\n"
+ + "Elements in the buffer: "
+ + mBuffer.size();
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java b/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java
deleted file mode 100644
index 5888b7a..0000000
--- a/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2019 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.wm;
-
-import static android.os.Build.IS_USER;
-
-import android.util.Log;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * A buffer structure backed by a {@link java.util.concurrent.BlockingQueue} to store the first
- * {@code #size size} bytes of window trace elements.
- * Once the buffer is full it will no longer accepts new elements.
- */
-class WindowTraceQueueBuffer extends WindowTraceBuffer {
- private static final String TAG = "WindowTracing";
-
- private Thread mConsumerThread;
- private boolean mCancel;
-
- @VisibleForTesting
- WindowTraceQueueBuffer(int size, File traceFile, boolean startConsumerThread)
- throws IOException {
- super(size, traceFile);
- if (startConsumerThread) {
- initializeConsumerThread();
- }
- }
-
- WindowTraceQueueBuffer(int size, File traceFile) throws IOException {
- this(size, traceFile, !IS_USER);
- }
-
- private void initializeConsumerThread() {
- mCancel = false;
- mConsumerThread = new Thread(() -> {
- try {
- loop();
- } catch (InterruptedException e) {
- Log.i(TAG, "Interrupting trace consumer thread");
- } catch (IOException e) {
- Log.e(TAG, "Failed to execute trace consumer thread", e);
- }
- }, "window_tracing");
- mConsumerThread.start();
- }
-
- private void loop() throws IOException, InterruptedException {
- while (!mCancel) {
- ProtoOutputStream proto;
- synchronized (mBufferLock) {
- mBufferLock.wait();
- proto = mBuffer.poll();
- if (proto != null) {
- mBufferSize -= proto.getRawSize();
- }
- }
- if (proto != null) {
- try (OutputStream os = new FileOutputStream(mTraceFile, true)) {
- byte[] protoBytes = proto.getBytes();
- os.write(protoBytes);
- }
- }
- }
- }
-
- @Override
- boolean canAdd(int protoLength) {
- long availableSpace = getAvailableSpace();
- return availableSpace >= protoLength;
- }
-
- @Override
- void writeTraceToFile() throws InterruptedException {
- synchronized (mBufferLock) {
- mCancel = true;
- mBufferLock.notify();
- }
- if (mConsumerThread != null) {
- mConsumerThread.join();
- mConsumerThread = null;
- }
- }
-}
diff --git a/services/core/java/com/android/server/wm/WindowTraceRingBuffer.java b/services/core/java/com/android/server/wm/WindowTraceRingBuffer.java
deleted file mode 100644
index 77d30be..0000000
--- a/services/core/java/com/android/server/wm/WindowTraceRingBuffer.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2019 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.wm;
-
-import android.util.proto.ProtoOutputStream;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * A ring buffer to store the {@code #size size} bytes of window trace data.
- * The buffer operates on a trace entry level, that is, if the new trace data is larger than the
- * available buffer space, the buffer will discard as many full trace entries as necessary to fit
- * the new trace.
- */
-class WindowTraceRingBuffer extends WindowTraceBuffer {
- WindowTraceRingBuffer(int size, File traceFile) throws IOException {
- super(size, traceFile);
- }
-
- @Override
- boolean canAdd(int protoLength) {
- long availableSpace = getAvailableSpace();
-
- while (availableSpace < protoLength) {
- discardOldest();
- availableSpace = getAvailableSpace();
- }
-
- return true;
- }
-
- @Override
- void writeTraceToFile() throws IOException {
- synchronized (mBufferLock) {
- try (OutputStream os = new FileOutputStream(mTraceFile, true)) {
- while (!mBuffer.isEmpty()) {
- ProtoOutputStream proto = mBuffer.poll();
- mBufferSize -= proto.getRawSize();
- byte[] protoBytes = proto.getBytes();
- os.write(protoBytes);
- }
- }
- }
- }
-
- private void discardOldest() {
- ProtoOutputStream item = mBuffer.poll();
- if (item == null) {
- throw new IllegalStateException("No element to discard from buffer");
- }
- mBufferSize -= item.getRawSize();
- }
-}
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index abc474d..0ce215c 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -31,8 +31,6 @@
import android.util.proto.ProtoOutputStream;
import android.view.Choreographer;
-import com.android.internal.annotations.VisibleForTesting;
-
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
@@ -47,139 +45,191 @@
* Maximum buffer size, currently defined as 512 KB
* Size was experimentally defined to fit between 100 to 150 elements.
*/
- private static final int WINDOW_TRACE_BUFFER_SIZE = 512 * 1024;
+ private static final int BUFFER_CAPACITY_CRITICAL = 512 * 1024;
+ private static final int BUFFER_CAPACITY_TRIM = 2048 * 1024;
+ private static final int BUFFER_CAPACITY_ALL = 4096 * 1024;
+ private static final String TRACE_FILENAME = "/data/misc/wmtrace/wm_trace.pb";
private static final String TAG = "WindowTracing";
private final WindowManagerService mService;
private final Choreographer mChoreographer;
private final WindowManagerGlobalLock mGlobalLock;
- private final Object mLock = new Object();
- private final WindowTraceBuffer.Builder mBufferBuilder;
+ private final Object mEnabledLock = new Object();
+ private final File mTraceFile;
+ private final WindowTraceBuffer mBuffer;
+ private final Choreographer.FrameCallback mFrameCallback = (frameTimeNanos) ->
+ log("onFrame" /* where */);
- private WindowTraceBuffer mTraceBuffer;
-
- private @WindowTraceLogLevel int mWindowTraceLogLevel = WindowTraceLogLevel.TRIM;
- private boolean mContinuousMode;
+ private @WindowTraceLogLevel int mLogLevel = WindowTraceLogLevel.TRIM;
+ private boolean mLogOnFrame = false;
private boolean mEnabled;
private volatile boolean mEnabledLockFree;
private boolean mScheduled;
- private Choreographer.FrameCallback mFrameCallback = (frameTimeNanos) ->
- log("onFrame" /* where */);
- private WindowTracing(File file, WindowManagerService service, Choreographer choreographer) {
- this(file, service, choreographer, service.mGlobalLock);
+ static WindowTracing createDefaultAndStartLooper(WindowManagerService service,
+ Choreographer choreographer) {
+ File file = new File(TRACE_FILENAME);
+ return new WindowTracing(file, service, choreographer, BUFFER_CAPACITY_TRIM);
}
- @VisibleForTesting
- WindowTracing(File file, WindowManagerService service, Choreographer choreographer,
- WindowManagerGlobalLock globalLock) {
- mBufferBuilder = new WindowTraceBuffer.Builder()
- .setTraceFile(file)
- .setBufferCapacity(WINDOW_TRACE_BUFFER_SIZE);
+ private WindowTracing(File file, WindowManagerService service, Choreographer choreographer,
+ int bufferCapacity) {
+ this(file, service, choreographer, service.mGlobalLock, bufferCapacity);
+ }
+ WindowTracing(File file, WindowManagerService service, Choreographer choreographer,
+ WindowManagerGlobalLock globalLock, int bufferCapacity) {
mChoreographer = choreographer;
mService = service;
mGlobalLock = globalLock;
+ mTraceFile = file;
+ mBuffer = new WindowTraceBuffer(bufferCapacity);
+ setLogLevel(WindowTraceLogLevel.TRIM, null /* pw */);
}
- void startTrace(@Nullable PrintWriter pw) throws IOException {
+ void startTrace(@Nullable PrintWriter pw) {
if (IS_USER) {
logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
return;
}
- synchronized (mLock) {
- logAndPrintln(pw, "Start tracing to " + mBufferBuilder.getFile() + ".");
- if (mTraceBuffer != null) {
- writeTraceToFileLocked();
- }
- mTraceBuffer = mBufferBuilder
- .setContinuousMode(mContinuousMode)
- .build();
+ synchronized (mEnabledLock) {
+ logAndPrintln(pw, "Start tracing to " + mTraceFile + ".");
+ mBuffer.resetBuffer();
mEnabled = mEnabledLockFree = true;
}
}
- private void logAndPrintln(@Nullable PrintWriter pw, String msg) {
- Log.i(TAG, msg);
- if (pw != null) {
- pw.println(msg);
- pw.flush();
- }
- }
-
void stopTrace(@Nullable PrintWriter pw) {
if (IS_USER) {
logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
return;
}
- synchronized (mLock) {
- logAndPrintln(pw, "Stop tracing to " + mBufferBuilder.getFile()
- + ". Waiting for traces to flush.");
+ synchronized (mEnabledLock) {
+ logAndPrintln(pw, "Stop tracing to " + mTraceFile + ". Waiting for traces to flush.");
mEnabled = mEnabledLockFree = false;
- synchronized (mLock) {
- if (mEnabled) {
- logAndPrintln(pw, "ERROR: tracing was re-enabled while waiting for flush.");
- throw new IllegalStateException("tracing enabled while waiting for flush.");
- }
- writeTraceToFileLocked();
- mTraceBuffer = null;
+ if (mEnabled) {
+ logAndPrintln(pw, "ERROR: tracing was re-enabled while waiting for flush.");
+ throw new IllegalStateException("tracing enabled while waiting for flush.");
}
- logAndPrintln(pw, "Trace written to " + mBufferBuilder.getFile() + ".");
+ writeTraceToFileLocked();
+ logAndPrintln(pw, "Trace written to " + mTraceFile + ".");
}
}
- @VisibleForTesting
- void setContinuousMode(boolean continuous, PrintWriter pw) {
- logAndPrintln(pw, "Setting window tracing continuous mode to " + continuous);
+ private void setLogLevel(@WindowTraceLogLevel int logLevel, PrintWriter pw) {
+ logAndPrintln(pw, "Setting window tracing log level to " + logLevel);
+ mLogLevel = logLevel;
- if (mEnabled) {
- logAndPrintln(pw, "Trace is currently active, change will take effect once the "
- + "trace is restarted.");
+ switch (logLevel) {
+ case WindowTraceLogLevel.ALL: {
+ setBufferCapacity(BUFFER_CAPACITY_ALL, pw);
+ break;
+ }
+ case WindowTraceLogLevel.TRIM: {
+ setBufferCapacity(BUFFER_CAPACITY_TRIM, pw);
+ break;
+ }
+ case WindowTraceLogLevel.CRITICAL: {
+ setBufferCapacity(BUFFER_CAPACITY_CRITICAL, pw);
+ break;
+ }
}
- mContinuousMode = continuous;
- mWindowTraceLogLevel = (continuous) ? WindowTraceLogLevel.CRITICAL :
- WindowTraceLogLevel.TRIM;
+ }
+
+ private void setLogFrequency(boolean onFrame, PrintWriter pw) {
+ logAndPrintln(pw, "Setting window tracing log frequency to "
+ + ((onFrame) ? "frame" : "transaction"));
+ mLogOnFrame = onFrame;
+ }
+
+ private void setBufferCapacity(int capacity, PrintWriter pw) {
+ logAndPrintln(pw, "Setting window tracing buffer capacity to " + capacity + "bytes");
+ mBuffer.setCapacity(capacity);
}
boolean isEnabled() {
return mEnabledLockFree;
}
- static WindowTracing createDefaultAndStartLooper(WindowManagerService service,
- Choreographer choreographer) {
- File file = new File("/data/misc/wmtrace/wm_trace.pb");
- return new WindowTracing(file, service, choreographer);
- }
-
int onShellCommand(ShellCommand shell) {
PrintWriter pw = shell.getOutPrintWriter();
- try {
- String cmd = shell.getNextArgRequired();
- switch (cmd) {
- case "start":
- startTrace(pw);
- return 0;
- case "stop":
- stopTrace(pw);
- return 0;
- case "continuous":
- setContinuousMode(Boolean.valueOf(shell.getNextArgRequired()), pw);
- return 0;
- default:
- pw.println("Unknown command: " + cmd);
- return -1;
- }
- } catch (IOException e) {
- logAndPrintln(pw, e.toString());
- throw new RuntimeException(e);
+ String cmd = shell.getNextArgRequired();
+ switch (cmd) {
+ case "start":
+ startTrace(pw);
+ return 0;
+ case "stop":
+ stopTrace(pw);
+ return 0;
+ case "status":
+ logAndPrintln(pw, getStatus());
+ return 0;
+ case "frame":
+ setLogFrequency(true /* onFrame */, pw);
+ mBuffer.resetBuffer();
+ return 0;
+ case "transaction":
+ setLogFrequency(false /* onFrame */, pw);
+ mBuffer.resetBuffer();
+ return 0;
+ case "level":
+ String logLevelStr = shell.getNextArgRequired().toLowerCase();
+ switch (logLevelStr) {
+ case "all": {
+ setLogLevel(WindowTraceLogLevel.ALL, pw);
+ break;
+ }
+ case "trim": {
+ setLogLevel(WindowTraceLogLevel.TRIM, pw);
+ break;
+ }
+ case "critical": {
+ setLogLevel(WindowTraceLogLevel.CRITICAL, pw);
+ break;
+ }
+ default: {
+ setLogLevel(WindowTraceLogLevel.TRIM, pw);
+ break;
+ }
+ }
+ mBuffer.resetBuffer();
+ return 0;
+ case "size":
+ setBufferCapacity(Integer.parseInt(shell.getNextArgRequired()) * 1024, pw);
+ mBuffer.resetBuffer();
+ return 0;
+ default:
+ pw.println("Unknown command: " + cmd);
+ pw.println("Window manager trace options:");
+ pw.println(" start: Start logging");
+ pw.println(" stop: Stop logging");
+ pw.println(" frame: Log trace once per frame");
+ pw.println(" transaction: Log each transaction");
+ pw.println(" size: Set the maximum log size (in KB)");
+ pw.println(" level [lvl]: Set the log level between");
+ pw.println(" lvl may be one of:");
+ pw.println(" critical: Only visible windows with reduced information");
+ pw.println(" trim: All windows with reduced");
+ pw.println(" all: All window and information");
+ return -1;
}
}
+ private String getStatus() {
+ return "Status: "
+ + ((isEnabled()) ? "Enabled" : "Disabled")
+ + "\n"
+ + "Log level: "
+ + mLogLevel
+ + "\n"
+ + mBuffer.getStatus();
+ }
+
/**
* If tracing is enabled, log the current state or schedule the next frame to be logged,
- * according to {@link #mContinuousMode}.
+ * according to {@link #mLogOnFrame}.
*
* @param where Logging point descriptor
*/
@@ -188,7 +238,7 @@
return;
}
- if (mContinuousMode) {
+ if (mLogOnFrame) {
schedule();
} else {
log(where);
@@ -215,25 +265,24 @@
private void log(String where) {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "traceStateLocked");
try {
- synchronized (mGlobalLock) {
- ProtoOutputStream os = new ProtoOutputStream();
- long tokenOuter = os.start(ENTRY);
- os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
- os.write(WHERE, where);
+ ProtoOutputStream os = new ProtoOutputStream();
+ long tokenOuter = os.start(ENTRY);
+ os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
+ os.write(WHERE, where);
+ long tokenInner = os.start(WINDOW_MANAGER_SERVICE);
+ synchronized (mGlobalLock) {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToProtoLocked");
try {
- long tokenInner = os.start(WINDOW_MANAGER_SERVICE);
- mService.writeToProtoLocked(os, mWindowTraceLogLevel);
- os.end(tokenInner);
+ mService.writeToProtoLocked(os, mLogLevel);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
- os.end(tokenOuter);
- mTraceBuffer.add(os);
-
- mScheduled = false;
}
+ os.end(tokenInner);
+ os.end(tokenOuter);
+ mBuffer.add(os);
+ mScheduled = false;
} catch (Exception e) {
Log.wtf(TAG, "Exception while tracing state", e);
} finally {
@@ -242,31 +291,37 @@
}
/**
- * Writes the trace buffer to disk. This method has no internal synchronization and should be
- * externally synchronized
- */
- private void writeTraceToFileLocked() {
- if (mTraceBuffer == null) {
- return;
- }
-
- try {
- mTraceBuffer.dump();
- } catch (IOException e) {
- Log.e(TAG, "Unable to write buffer to file", e);
- } catch (InterruptedException e) {
- Log.e(TAG, "Unable to interrupt window tracing file write thread", e);
- }
- }
-
- /**
- * Writes the trace buffer to disk and clones it into a new file for the bugreport.
+ * Writes the trace buffer to new file for the bugreport.
+ *
* This method is synchronized with {@code #startTrace(PrintWriter)} and
* {@link #stopTrace(PrintWriter)}.
*/
void writeTraceToFile() {
- synchronized (mLock) {
+ synchronized (mEnabledLock) {
writeTraceToFileLocked();
}
}
-}
+
+ private void logAndPrintln(@Nullable PrintWriter pw, String msg) {
+ Log.i(TAG, msg);
+ if (pw != null) {
+ pw.println(msg);
+ pw.flush();
+ }
+ }
+
+ /**
+ * Writes the trace buffer to disk. This method has no internal synchronization and should be
+ * externally synchronized
+ */
+ private void writeTraceToFileLocked() {
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeTraceToFileLocked");
+ mBuffer.writeTraceToFile(mTraceFile);
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to write buffer to file", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ }
+ }
+}
\ No newline at end of file
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 9946cc3..8ad4d76 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -3,6 +3,7 @@
srcs: ["java/**/*.java"],
static_libs: [
"netd_aidl_interface-java",
+ "networkstack-aidl-interfaces-java",
]
}
diff --git a/core/java/android/net/dhcp/DhcpServerCallbacks.java b/services/net/java/android/net/dhcp/DhcpServerCallbacks.java
similarity index 100%
rename from core/java/android/net/dhcp/DhcpServerCallbacks.java
rename to services/net/java/android/net/dhcp/DhcpServerCallbacks.java
diff --git a/core/java/android/net/ip/IpClientCallbacks.java b/services/net/java/android/net/ip/IpClientCallbacks.java
similarity index 100%
rename from core/java/android/net/ip/IpClientCallbacks.java
rename to services/net/java/android/net/ip/IpClientCallbacks.java
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
index 0355e84..5cb6cbb 100644
--- a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
+++ b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
@@ -556,16 +556,6 @@
}
@Override
- public byte[] getPermissionGrantBackup(int userId) throws RemoteException {
- return new byte[0];
- }
-
- @Override
- public void restorePermissionGrants(byte[] backup, int userId) throws RemoteException {
-
- }
-
- @Override
public ComponentName getHomeActivities(List<ResolveInfo> outHomeCandidates)
throws RemoteException {
return null;
diff --git a/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
index 5900fc5..01759d2 100644
--- a/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
@@ -98,6 +98,8 @@
mColorDisplayService = new ColorDisplayService(mContext);
mBinderService = mColorDisplayService.new BinderService();
+ LocalServices.addService(ColorDisplayService.ColorDisplayServiceInternal.class,
+ mColorDisplayService.new ColorDisplayServiceInternal());
}
@After
@@ -110,6 +112,8 @@
mUserId = UserHandle.USER_NULL;
mContext = null;
+
+ LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class);
}
@AfterClass
@@ -979,6 +983,99 @@
assertActiveColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
}
+ @Test
+ public void displayWhiteBalance_enable() {
+ setWhiteBalance(true /* Enable DWB Setting */);
+ setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+ mBinderService.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+ startService();
+ assertDwbActive(true);
+ }
+
+ @Test
+ public void displayWhiteBalance_disableAfterNightDisplayEnable() {
+ setWhiteBalance(true /* Enable DWB Setting */);
+
+ startService();
+ /* Enable nightlight */
+ setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+ setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+ /* Since we are using FakeSettingsProvider which could not trigger observer change,
+ * force an update here.*/
+ mColorDisplayService.updateDisplayWhiteBalanceStatus();
+ assertDwbActive(false);
+ }
+
+ @Test
+ public void displayWhiteBalance_enableAfterNightDisplayDisable() {
+ setWhiteBalance(true /* Enable DWB Setting */);
+ startService();
+ /* Enable nightlight */
+ setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+ setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+ mColorDisplayService.updateDisplayWhiteBalanceStatus();
+ assertDwbActive(false);
+
+ /* Disable nightlight */
+ setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+ mColorDisplayService.updateDisplayWhiteBalanceStatus();
+ assertDwbActive(true);
+ }
+
+ @Test
+ public void displayWhiteBalance_enableAfterLinearColorMode() {
+ setWhiteBalance(true /* Enable DWB Setting */);
+ setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+ startService();
+ mBinderService.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
+
+ mColorDisplayService.updateDisplayWhiteBalanceStatus();
+ assertDwbActive(true);
+ }
+
+ @Test
+ public void displayWhiteBalance_setTemperatureOverMax() {
+ int max = mColorDisplayService.mDisplayWhiteBalanceTintController.mTemperatureMax;
+
+ ColorDisplayService.ColorDisplayServiceInternal cdsInternal = LocalServices.getService(
+ ColorDisplayService.ColorDisplayServiceInternal.class);
+ cdsInternal.setDisplayWhiteBalanceColorTemperature(max+1);
+
+ assertWithMessage("Unexpected temperature set")
+ .that(mColorDisplayService.mDisplayWhiteBalanceTintController.mCurrentColorTemperature)
+ .isEqualTo(max);
+ }
+
+ @Test
+ public void displayWhiteBalance_setTemperatureBelowMin() {
+ int min = mColorDisplayService.mDisplayWhiteBalanceTintController.mTemperatureMin;
+
+ ColorDisplayService.ColorDisplayServiceInternal cdsInternal = LocalServices.getService(
+ ColorDisplayService.ColorDisplayServiceInternal.class);
+ cdsInternal.setDisplayWhiteBalanceColorTemperature(min - 1);
+
+ assertWithMessage("Unexpected temperature set")
+ .that(mColorDisplayService.mDisplayWhiteBalanceTintController.mCurrentColorTemperature)
+ .isEqualTo(min);
+ }
+
+ @Test
+ public void displayWhiteBalance_setValidTemperature() {
+ int min = mColorDisplayService.mDisplayWhiteBalanceTintController.mTemperatureMin;
+ int max = mColorDisplayService.mDisplayWhiteBalanceTintController.mTemperatureMax;
+ int valToSet = (min + max) / 2;
+
+ ColorDisplayService.ColorDisplayServiceInternal cdsInternal = LocalServices.getService(
+ ColorDisplayService.ColorDisplayServiceInternal.class);
+ cdsInternal.setDisplayWhiteBalanceColorTemperature(valToSet);
+
+ assertWithMessage("Unexpected temperature set")
+ .that(mColorDisplayService.mDisplayWhiteBalanceTintController.mCurrentColorTemperature)
+ .isEqualTo(valToSet);
+ }
+
/**
* Configures Night display to use a custom schedule.
*
@@ -1041,6 +1138,16 @@
}
/**
+ * Configures the Display White Balance setting state.
+ *
+ * @param state {@code true} if display white balance should be enabled
+ */
+ private void setWhiteBalance(boolean state) {
+ Secure.putIntForUser(mContext.getContentResolver(),
+ Secure.DISPLAY_WHITE_BALANCE_ENABLED, state ? 1 : 0, mUserId);
+ }
+
+ /**
* Configures color mode.
*/
private void setColorMode(int colorMode) {
@@ -1111,6 +1218,17 @@
}
/**
+ * Convenience method for asserting that the DWB active status matches expectation.
+ *
+ * @param enabled the expected active status.
+ */
+ private void assertDwbActive(boolean enabled) {
+ assertWithMessage("Incorrect Display White Balance state")
+ .that(mColorDisplayService.mDisplayWhiteBalanceTintController.isActivated())
+ .isEqualTo(enabled);
+ }
+
+ /**
* Convenience for making a {@link LocalTime} instance with an offset relative to now.
*
* @param offsetMinutes the offset relative to now (in minutes)
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 6d28ed1..50734ef 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -55,8 +55,8 @@
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.PermissionManagerServiceInternal;
import org.junit.After;
import org.junit.Before;
@@ -88,7 +88,8 @@
writeOldFiles();
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+ PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+ lock);
Settings settings =
new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
@@ -103,7 +104,8 @@
writeOldFiles();
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+ PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+ lock);
Settings settings =
new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
@@ -120,7 +122,8 @@
writeOldFiles();
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+ PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+ lock);
Settings settings =
new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
@@ -143,7 +146,8 @@
writeOldFiles();
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+ PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+ lock);
Settings settings =
new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
@@ -313,7 +317,8 @@
writeOldFiles();
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+ PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+ lock);
Settings settings =
new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
@@ -507,7 +512,8 @@
public void testUpdatePackageSetting03() {
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+ PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+ lock);
final Settings testSettings01 =
new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
final SharedUserSetting testUserSetting01 = createSharedUserSetting(
@@ -625,7 +631,8 @@
public void testCreateNewSetting03() {
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- PermissionManagerInternal pmInt = PermissionManagerService.create(context, null, lock);
+ PermissionManagerServiceInternal pmInt = PermissionManagerService.create(context, null,
+ lock);
final Settings testSettings01 =
new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
final SharedUserSetting testUserSetting01 = createSharedUserSetting(
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java
index 2b8e307..b299f0d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java
@@ -36,11 +36,10 @@
import org.junit.Test;
import java.io.File;
-import java.io.IOException;
/**
- * Test class for {@link WindowTraceBuffer} and {@link WindowTraceQueueBuffer}.
+ * Test class for {@link WindowTraceBuffer}.
*
* Build/Install/Run:
* atest WmTests:WindowTraceBufferTest
@@ -49,12 +48,15 @@
@Presubmit
public class WindowTraceBufferTest {
private File mFile;
+ private WindowTraceBuffer mBuffer;
@Before
public void setUp() throws Exception {
final Context testContext = getInstrumentation().getContext();
mFile = testContext.getFileStreamPath("tracing_test.dat");
mFile.delete();
+
+ mBuffer = new WindowTraceBuffer(10);
}
@After
@@ -63,145 +65,112 @@
}
@Test
- public void testTraceQueueBuffer_addItem() throws Exception {
- ProtoOutputStream toWrite1 = getDummy(1);
- ProtoOutputStream toWrite2 = getDummy(2);
- ProtoOutputStream toWrite3 = getDummy(3);
- final int objectSize = toWrite1.getRawSize();
- final int bufferCapacity = objectSize * 2;
-
- final WindowTraceBuffer buffer = buildQueueBuffer(bufferCapacity);
-
- buffer.add(toWrite1);
- byte[] toWrite1Bytes = toWrite1.getBytes();
- assertTrue("First element should be in the list",
- buffer.contains(toWrite1Bytes));
-
- buffer.add(toWrite2);
- byte[] toWrite2Bytes = toWrite2.getBytes();
- assertTrue("First element should be in the list",
- buffer.contains(toWrite1Bytes));
- assertTrue("Second element should be in the list",
- buffer.contains(toWrite2Bytes));
-
- buffer.add(toWrite3);
- byte[] toWrite3Bytes = toWrite3.getBytes();
- assertTrue("First element should be in the list",
- buffer.contains(toWrite1Bytes));
- assertTrue("Second element should be in the list",
- buffer.contains(toWrite2Bytes));
- assertTrue("Third element should not be in the list",
- !buffer.contains(toWrite3Bytes));
-
- assertEquals("Buffer should have 2 elements", buffer.mBuffer.size(), 2);
- assertEquals(String.format("Buffer is full, used space should be %d", bufferCapacity),
- buffer.mBufferSize, bufferCapacity);
- assertEquals("Buffer is full, available space should be 0",
- buffer.getAvailableSpace(), 0);
- }
-
- @Test
- public void testTraceRingBuffer_addItem() throws Exception {
+ public void test_addItem() {
ProtoOutputStream toWrite = getDummy(1);
final int objectSize = toWrite.getRawSize();
+ mBuffer.setCapacity(objectSize);
+ mBuffer.resetBuffer();
- final WindowTraceBuffer buffer = buildRingBuffer(objectSize);
+ Preconditions.checkArgument(mBuffer.size() == 0);
- Preconditions.checkArgument(buffer.mBuffer.isEmpty());
+ mBuffer.add(toWrite);
- buffer.add(toWrite);
-
- assertEquals("Item was not added to the buffer", buffer.mBuffer.size(), 1);
+ assertEquals("Item was not added to the buffer", 1, mBuffer.size());
assertEquals("Total buffer getSize differs from inserted object",
- buffer.mBufferSize, objectSize);
- assertEquals("Available buffer space does not match used one",
- buffer.getAvailableSpace(), 0);
+ mBuffer.getBufferSize(), objectSize);
+ assertEquals("Available buffer space does not match used one", 0,
+ mBuffer.getAvailableSpace());
}
@Test
- public void testTraceRingBuffer_addItemMustOverwriteOne() throws Exception {
+ public void test_addItemMustOverwriteOne() {
ProtoOutputStream toWrite1 = getDummy(1);
ProtoOutputStream toWrite2 = getDummy(2);
ProtoOutputStream toWrite3 = getDummy(3);
final int objectSize = toWrite1.getRawSize();
-
final int bufferCapacity = objectSize * 2 + 1;
- final WindowTraceBuffer buffer = buildRingBuffer(bufferCapacity);
+ mBuffer.setCapacity(bufferCapacity);
+ mBuffer.resetBuffer();
- buffer.add(toWrite1);
+ mBuffer.add(toWrite1);
byte[] toWrite1Bytes = toWrite1.getBytes();
assertTrue("First element should be in the list",
- buffer.contains(toWrite1Bytes));
+ mBuffer.contains(toWrite1Bytes));
- buffer.add(toWrite2);
+ mBuffer.add(toWrite2);
byte[] toWrite2Bytes = toWrite2.getBytes();
assertTrue("First element should be in the list",
- buffer.contains(toWrite1Bytes));
+ mBuffer.contains(toWrite1Bytes));
assertTrue("Second element should be in the list",
- buffer.contains(toWrite2Bytes));
+ mBuffer.contains(toWrite2Bytes));
- buffer.add(toWrite3);
+ mBuffer.add(toWrite3);
byte[] toWrite3Bytes = toWrite3.getBytes();
assertTrue("First element should not be in the list",
- !buffer.contains(toWrite1Bytes));
+ !mBuffer.contains(toWrite1Bytes));
assertTrue("Second element should be in the list",
- buffer.contains(toWrite2Bytes));
+ mBuffer.contains(toWrite2Bytes));
assertTrue("Third element should be in the list",
- buffer.contains(toWrite3Bytes));
- assertEquals("Buffer should have 2 elements", buffer.mBuffer.size(), 2);
+ mBuffer.contains(toWrite3Bytes));
+ assertEquals("Buffer should have 2 elements", 2, mBuffer.size());
assertEquals(String.format("Buffer is full, used space should be %d", bufferCapacity),
- buffer.mBufferSize, bufferCapacity - 1);
- assertEquals(" Buffer is full, available space should be 0",
- buffer.getAvailableSpace(), 1);
+ mBuffer.getBufferSize(), bufferCapacity - 1);
+ assertEquals(" Buffer is full, available space should be 0", 1,
+ mBuffer.getAvailableSpace());
}
@Test
- public void testTraceRingBuffer_addItemMustOverwriteMultiple() throws Exception {
+ public void test_addItemMustOverwriteMultiple() {
ProtoOutputStream toWriteSmall1 = getDummy(1);
ProtoOutputStream toWriteSmall2 = getDummy(2);
final int objectSize = toWriteSmall1.getRawSize();
-
final int bufferCapacity = objectSize * 2;
- final WindowTraceBuffer buffer = buildRingBuffer(bufferCapacity);
+ mBuffer.setCapacity(bufferCapacity);
+ mBuffer.resetBuffer();
ProtoOutputStream toWriteBig = new ProtoOutputStream();
toWriteBig.write(MAGIC_NUMBER, 1);
toWriteBig.write(MAGIC_NUMBER, 2);
- buffer.add(toWriteSmall1);
+ mBuffer.add(toWriteSmall1);
byte[] toWriteSmall1Bytes = toWriteSmall1.getBytes();
assertTrue("First element should be in the list",
- buffer.contains(toWriteSmall1Bytes));
+ mBuffer.contains(toWriteSmall1Bytes));
- buffer.add(toWriteSmall2);
+ mBuffer.add(toWriteSmall2);
byte[] toWriteSmall2Bytes = toWriteSmall2.getBytes();
assertTrue("First element should be in the list",
- buffer.contains(toWriteSmall1Bytes));
+ mBuffer.contains(toWriteSmall1Bytes));
assertTrue("Second element should be in the list",
- buffer.contains(toWriteSmall2Bytes));
+ mBuffer.contains(toWriteSmall2Bytes));
- buffer.add(toWriteBig);
+ mBuffer.add(toWriteBig);
byte[] toWriteBigBytes = toWriteBig.getBytes();
assertTrue("Third element should overwrite all others",
- !buffer.contains(toWriteSmall1Bytes));
+ !mBuffer.contains(toWriteSmall1Bytes));
assertTrue("Third element should overwrite all others",
- !buffer.contains(toWriteSmall2Bytes));
+ !mBuffer.contains(toWriteSmall2Bytes));
assertTrue("Third element should overwrite all others",
- buffer.contains(toWriteBigBytes));
+ mBuffer.contains(toWriteBigBytes));
- assertEquals(" Buffer should have only 1 big element", buffer.mBuffer.size(), 1);
+ assertEquals(" Buffer should have only 1 big element", 1, mBuffer.size());
assertEquals(String.format(" Buffer is full, used space should be %d", bufferCapacity),
- buffer.mBufferSize, bufferCapacity);
- assertEquals(" Buffer is full, available space should be 0",
- buffer.getAvailableSpace(), 0);
+ mBuffer.getBufferSize(), bufferCapacity);
+ assertEquals(" Buffer is full, available space should be 0", 0,
+ mBuffer.getAvailableSpace());
}
- private WindowTraceBuffer buildRingBuffer(int capacity) throws IOException {
- return new WindowTraceBuffer.Builder()
- .setContinuousMode(true)
- .setBufferCapacity(capacity)
- .setTraceFile(mFile)
- .build();
+ @Test
+ public void test_startResetsBuffer() {
+ ProtoOutputStream toWrite = getDummy(1);
+ mBuffer.resetBuffer();
+ Preconditions.checkArgument(mBuffer.size() == 0);
+
+ mBuffer.add(toWrite);
+ assertEquals("Item was not added to the buffer", 1, mBuffer.size());
+ mBuffer.resetBuffer();
+ assertEquals("Buffer should be empty after reset", 0, mBuffer.size());
+ assertEquals("Buffer size should be 0 after reset", 0, mBuffer.getBufferSize());
}
private ProtoOutputStream getDummy(int value) {
@@ -212,7 +181,4 @@
return toWrite;
}
- private WindowTraceBuffer buildQueueBuffer(int size) throws IOException {
- return new WindowTraceQueueBuffer(size, mFile, false);
- }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
index 3c6e240..8358fdd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
@@ -88,8 +88,7 @@
mFile.delete();
mWindowTracing = new WindowTracing(mFile, mWmMock, mChoreographer,
- new WindowManagerGlobalLock());
- mWindowTracing.setContinuousMode(false /* continuous */, null /* pw */);
+ new WindowManagerGlobalLock(), 1024);
}
@After
@@ -103,13 +102,13 @@
}
@Test
- public void isEnabled_returnsTrueAfterStart() throws Exception {
+ public void isEnabled_returnsTrueAfterStart() {
mWindowTracing.startTrace(mock(PrintWriter.class));
assertTrue(mWindowTracing.isEnabled());
}
@Test
- public void isEnabled_returnsFalseAfterStop() throws Exception {
+ public void isEnabled_returnsFalseAfterStop() {
mWindowTracing.startTrace(mock(PrintWriter.class));
mWindowTracing.stopTrace(mock(PrintWriter.class));
assertFalse(mWindowTracing.isEnabled());
@@ -133,6 +132,8 @@
mWindowTracing.startTrace(mock(PrintWriter.class));
mWindowTracing.stopTrace(mock(PrintWriter.class));
+ assertTrue("Trace file should exist", mFile.exists());
+
byte[] header = new byte[MAGIC_HEADER.length];
try (InputStream is = new FileInputStream(mFile)) {
assertEquals(MAGIC_HEADER.length, is.read(header));
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index f1ddfe4..8feed7f 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -15,7 +15,6 @@
*/
package com.android.server.usage;
-import static android.app.usage.UsageEvents.Event.ACTIVITY_DESTROYED;
import static android.app.usage.UsageEvents.Event.ACTIVITY_PAUSED;
import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED;
import static android.app.usage.UsageEvents.Event.ACTIVITY_STOPPED;
@@ -302,27 +301,6 @@
UsageStats usageStats = packageStats.valueAt(i);
usageStats.update(null, timeStamp, eventType, instanceId);
}
- } else if (eventType == ACTIVITY_DESTROYED) {
- UsageStats usageStats = packageStats.get(packageName);
- if (usageStats != null) {
- // If previous event is not ACTIVITY_STOPPED, convert ACTIVITY_DESTROYED
- // to ACTIVITY_STOPPED and add to event list.
- // Otherwise do not add anything to event list. (Because we want to save space
- // and we do not want a ACTIVITY_STOPPED followed by
- // ACTIVITY_DESTROYED in event list).
- final int index = usageStats.mActivities.indexOfKey(instanceId);
- if (index >= 0) {
- final int type = usageStats.mActivities.valueAt(index);
- if (type != ACTIVITY_STOPPED) {
- Event event = new Event(ACTIVITY_STOPPED, timeStamp);
- event.mPackage = packageName;
- event.mClass = className;
- event.mInstanceId = instanceId;
- addEvent(event);
- }
- }
- usageStats.update(className, timeStamp, ACTIVITY_DESTROYED, instanceId);
- }
} else {
UsageStats usageStats = getOrCreateUsageStats(packageName);
usageStats.update(className, timeStamp, eventType, instanceId);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index af5278f..ebb0210 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -145,8 +145,16 @@
AppTimeLimitController mAppTimeLimit;
final SparseArray<ArraySet<String>> mUsageReporters = new SparseArray();
- final SparseArray<String> mVisibleActivities = new SparseArray();
+ final SparseArray<ActivityData> mVisibleActivities = new SparseArray();
+ private static class ActivityData {
+ private final String mTaskRootPackage;
+ private final String mTaskRootClass;
+ private ActivityData(String taskRootPackage, String taskRootClass) {
+ mTaskRootPackage = taskRootPackage;
+ mTaskRootClass = taskRootClass;
+ }
+ }
private UsageStatsManagerInternal.AppIdleStateChangeListener mStandbyChangeListener =
new UsageStatsManagerInternal.AppIdleStateChangeListener() {
@@ -464,47 +472,57 @@
final long elapsedRealtime = SystemClock.elapsedRealtime();
convertToSystemTimeLocked(event);
- if (event.getPackageName() != null
- && mPackageManagerInternal.isPackageEphemeral(userId, event.getPackageName())) {
+ if (event.mPackage != null
+ && mPackageManagerInternal.isPackageEphemeral(userId, event.mPackage)) {
event.mFlags |= Event.FLAG_IS_PACKAGE_INSTANT_APP;
}
- final UserUsageStatsService service =
- getUserDataAndInitializeIfNeededLocked(userId, timeNow);
- service.reportEvent(event);
-
- mAppStandby.reportEvent(event, elapsedRealtime, userId);
-
- String packageName;
-
- switch(mUsageSource) {
- case USAGE_SOURCE_CURRENT_ACTIVITY:
- packageName = event.getPackageName();
- break;
- case USAGE_SOURCE_TASK_ROOT_ACTIVITY:
- default:
- packageName = event.getTaskRootPackageName();
- if (packageName == null) {
- packageName = event.getPackageName();
- }
- break;
- }
-
switch (event.mEventType) {
case Event.ACTIVITY_RESUMED:
- synchronized (mVisibleActivities) {
- // check if this activity has already been resumed
- if (mVisibleActivities.get(event.mInstanceId) != null) break;
- mVisibleActivities.put(event.mInstanceId, event.getClassName());
- try {
- mAppTimeLimit.noteUsageStart(packageName, userId);
- } catch (IllegalArgumentException iae) {
- Slog.e(TAG, "Failed to note usage start", iae);
+ // check if this activity has already been resumed
+ if (mVisibleActivities.get(event.mInstanceId) != null) break;
+ mVisibleActivities.put(event.mInstanceId,
+ new ActivityData(event.mTaskRootPackage, event.mTaskRootClass));
+ try {
+ switch(mUsageSource) {
+ case USAGE_SOURCE_CURRENT_ACTIVITY:
+ mAppTimeLimit.noteUsageStart(event.mPackage, userId);
+ break;
+ case USAGE_SOURCE_TASK_ROOT_ACTIVITY:
+ default:
+ mAppTimeLimit.noteUsageStart(event.mTaskRootPackage, userId);
+ break;
+ }
+ } catch (IllegalArgumentException iae) {
+ Slog.e(TAG, "Failed to note usage start", iae);
+ }
+ break;
+ case Event.ACTIVITY_PAUSED:
+ if (event.mTaskRootPackage == null) {
+ // Task Root info is missing. Repair the event based on previous data
+ final ActivityData prevData = mVisibleActivities.get(event.mInstanceId);
+ if (prevData == null) {
+ Slog.w(TAG, "Unexpected activity event reported! (" + event.mPackage
+ + "/" + event.mClass + " event : " + event.mEventType
+ + " instanceId : " + event.mInstanceId + ")");
+ } else {
+ event.mTaskRootPackage = prevData.mTaskRootPackage;
+ event.mTaskRootClass = prevData.mTaskRootClass;
}
}
break;
- case Event.ACTIVITY_STOPPED:
case Event.ACTIVITY_DESTROYED:
+ // Treat activity destroys like activity stops.
+ event.mEventType = Event.ACTIVITY_STOPPED;
+ // Fallthrough
+ case Event.ACTIVITY_STOPPED:
+ final ActivityData prevData =
+ mVisibleActivities.removeReturnOld(event.mInstanceId);
+ if (prevData == null) {
+ // The activity stop was already handled.
+ return;
+ }
+
ArraySet<String> tokens;
synchronized (mUsageReporters) {
tokens = mUsageReporters.removeReturnOld(event.mInstanceId);
@@ -517,7 +535,7 @@
final String token = tokens.valueAt(i);
try {
mAppTimeLimit.noteUsageStop(
- buildFullToken(event.getPackageName(), token), userId);
+ buildFullToken(event.mPackage, token), userId);
} catch (IllegalArgumentException iae) {
Slog.w(TAG, "Failed to stop usage for during reporter death: "
+ iae);
@@ -525,18 +543,32 @@
}
}
}
-
- synchronized (mVisibleActivities) {
- if (mVisibleActivities.removeReturnOld(event.mInstanceId) != null) {
- try {
- mAppTimeLimit.noteUsageStop(packageName, userId);
- } catch (IllegalArgumentException iae) {
- Slog.w(TAG, "Failed to note usage stop", iae);
- }
+ if (event.mTaskRootPackage == null) {
+ // Task Root info is missing. Repair the event based on previous data
+ event.mTaskRootPackage = prevData.mTaskRootPackage;
+ event.mTaskRootClass = prevData.mTaskRootClass;
+ }
+ try {
+ switch(mUsageSource) {
+ case USAGE_SOURCE_CURRENT_ACTIVITY:
+ mAppTimeLimit.noteUsageStop(event.mPackage, userId);
+ break;
+ case USAGE_SOURCE_TASK_ROOT_ACTIVITY:
+ default:
+ mAppTimeLimit.noteUsageStop(event.mTaskRootPackage, userId);
+ break;
}
+ } catch (IllegalArgumentException iae) {
+ Slog.w(TAG, "Failed to note usage stop", iae);
}
break;
}
+
+ final UserUsageStatsService service =
+ getUserDataAndInitializeIfNeededLocked(userId, timeNow);
+ service.reportEvent(event);
+
+ mAppStandby.reportEvent(event, elapsedRealtime, userId);
}
}
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index bd0d4ae..ae12a17 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -623,7 +623,7 @@
"android.telecom.event.HANDOVER_FAILED";
/**
- * Connection extra key used to store SIP invite fields for an incoming call for IMS calls
+ * String Connection extra key used to store SIP invite fields for an incoming call for IMS call
*/
public static final String EXTRA_SIP_INVITE = "android.telecom.extra.SIP_INVITE";
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 73f0556..d5c7079 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -266,6 +266,11 @@
public static final String EXTRA_DISPLAY_TEXT = "DisplayText";
public static final String EXTRA_ADDITIONAL_CALL_INFO = "AdditionalCallInfo";
public static final String EXTRA_IS_CALL_PULL = "CallPull";
+
+ /**
+ * String extra property
+ * Containing fields from the SIP INVITE message for an IMS call
+ */
public static final String EXTRA_ADDITIONAL_SIP_INVITE_FIELDS =
"android.telephony.ims.extra.ADDITIONAL_SIP_INVITE_FIELDS";
diff --git a/test-mock/api/test-current.txt b/test-mock/api/test-current.txt
index ab10800..0cb8f22 100644
--- a/test-mock/api/test-current.txt
+++ b/test-mock/api/test-current.txt
@@ -9,10 +9,12 @@
method public java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
method public String[] getNamesForUids(int[]);
method public String getPermissionControllerPackageName();
+ method public int getPermissionFlags(String, String, android.os.UserHandle);
method @NonNull public String getServicesSystemSharedLibraryPackageName();
method @NonNull public String getSharedSystemSharedLibraryPackageName();
method public void grantRuntimePermission(String, String, android.os.UserHandle);
method public void revokeRuntimePermission(String, String, android.os.UserHandle);
+ method public void updatePermissionFlags(String, String, int, int, android.os.UserHandle);
}
}
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 5f664f5..9832485 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -435,7 +435,7 @@
const size_t NS = pool->size();
for (size_t s=0; s<NS; s++) {
String8 str = pool->string8ObjectAt(s);
- printer->Print(StringPrintf("String #%zd: %s\n", s, str.string()));
+ printer->Print(StringPrintf("String #%zd : %s\n", s, str.string()));
}
}
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 2f8ca2d..c188782 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -1084,7 +1084,7 @@
// Create a overlayable entry grouping that represents this <overlayable>
auto overlayable = std::make_shared<Overlayable>(
overlayable_name.value(), (overlayable_actor) ? overlayable_actor.value() : "",
- out_resource->source);
+ source_);
bool error = false;
std::string comment;
@@ -1113,6 +1113,13 @@
const std::string& element_name = parser->element_name();
const std::string& element_namespace = parser->element_namespace();
if (element_namespace.empty() && element_name == "item") {
+ if (current_policies == OverlayableItem::Policy::kNone) {
+ diag_->Error(DiagMessage(element_source)
+ << "<item> within an <overlayable> must be inside a <policy> block");
+ error = true;
+ continue;
+ }
+
// Items specify the name and type of resource that should be overlayable
Maybe<StringPiece> item_name = xml::FindNonEmptyAttribute(parser, "name");
if (!item_name) {
@@ -1169,6 +1176,8 @@
current_policies |= OverlayableItem::Policy::kSystem;
} else if (trimmed_part == "vendor") {
current_policies |= OverlayableItem::Policy::kVendor;
+ } else if (trimmed_part == "signature") {
+ current_policies |= OverlayableItem::Policy::kSignature;
} else {
diag_->Error(DiagMessage(element_source)
<< "<policy> has unsupported type '" << trimmed_part << "'");
@@ -1176,6 +1185,11 @@
continue;
}
}
+ } else {
+ diag_->Error(DiagMessage(element_source)
+ << "<policy> must have a 'type' attribute");
+ error = true;
+ continue;
}
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
diag_->Error(DiagMessage(element_source) << "invalid element <" << element_name << "> "
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 827c7de..25b76b0 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -894,8 +894,10 @@
TEST_F(ResourceParserTest, ParseOverlayable) {
std::string input = R"(
<overlayable name="Name" actor="overlay://theme">
- <item type="string" name="foo" />
- <item type="drawable" name="bar" />
+ <policy type="signature">
+ <item type="string" name="foo" />
+ <item type="drawable" name="bar" />
+ </policy>
</overlayable>)";
ASSERT_TRUE(TestParse(input));
@@ -906,7 +908,7 @@
OverlayableItem& result_overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme"));
- EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));
+ EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature));
search_result = table_.FindResource(test::ParseNameOrDie("drawable/bar"));
ASSERT_TRUE(search_result);
@@ -915,7 +917,7 @@
result_overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://theme"));
- EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));
+ EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature));
}
TEST_F(ResourceParserTest, ParseOverlayableRequiresName) {
@@ -931,7 +933,6 @@
TEST_F(ResourceParserTest, ParseOverlayablePolicy) {
std::string input = R"(
<overlayable name="Name">
- <item type="string" name="foo" />
<policy type="product">
<item type="string" name="bar" />
</policy>
@@ -944,23 +945,18 @@
<policy type="public">
<item type="string" name="faz" />
</policy>
+ <policy type="signature">
+ <item type="string" name="foz" />
+ </policy>
</overlayable>)";
ASSERT_TRUE(TestParse(input));
- auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo"));
+ auto search_result = table_.FindResource(test::ParseNameOrDie("string/bar"));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
ASSERT_TRUE(search_result.value().entry->overlayable_item);
OverlayableItem result_overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
- EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kNone));
-
- search_result = table_.FindResource(test::ParseNameOrDie("string/bar"));
- ASSERT_TRUE(search_result);
- ASSERT_THAT(search_result.value().entry, NotNull());
- ASSERT_TRUE(search_result.value().entry->overlayable_item);
- result_overlayable_item = search_result.value().entry->overlayable_item.value();
- EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct));
search_result = table_.FindResource(test::ParseNameOrDie("string/fiz"));
@@ -986,6 +982,30 @@
result_overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic));
+
+ search_result = table_.FindResource(test::ParseNameOrDie("string/foz"));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ ASSERT_TRUE(search_result.value().entry->overlayable_item);
+ result_overlayable_item = search_result.value().entry->overlayable_item.value();
+ EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
+ EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature));
+}
+
+TEST_F(ResourceParserTest, ParseOverlayableNoPolicyError) {
+ std::string input = R"(
+ <overlayable name="Name">
+ <item type="string" name="foo" />
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
+
+ input = R"(
+ <overlayable name="Name">
+ <policy>
+ <item name="foo" />
+ </policy>
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
}
TEST_F(ResourceParserTest, ParseOverlayableBadPolicyError) {
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index 7ca99ea..32dfd26 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -92,6 +92,9 @@
// The resource can be overlaid by any overlay on the product partition.
kProduct = 0x08,
+
+ // The resource can be overlaid by any overlay signed with the same signature as its actor.
+ kSignature = 0x010,
};
std::shared_ptr<Overlayable> overlayable;
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index ab4805f..0032960 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -727,7 +727,7 @@
// This must be a FileReference.
std::unique_ptr<FileReference> file_ref =
util::make_unique<FileReference>(dst_pool->MakeRef(
- str, StringPool::Context(StringPool::Context::kHighPriority, config), data));
+ str, StringPool::Context(StringPool::Context::kHighPriority, config)));
if (type == ResourceType::kRaw) {
file_ref->type = ResourceFile::Type::kUnknown;
} else if (util::EndsWith(*file_ref->path, ".xml")) {
@@ -739,7 +739,7 @@
}
// There are no styles associated with this string, so treat it as a simple string.
- return util::make_unique<String>(dst_pool->MakeRef(str, StringPool::Context(config), data));
+ return util::make_unique<String>(dst_pool->MakeRef(str, StringPool::Context(config)));
}
} break;
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index 9a1d942..a2fd7c6 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -138,10 +138,10 @@
// Represents a set of overlayable resources.
message Overlayable {
- // The name of the <overlyabale>.
+ // The name of the <overlayable>.
string name = 1;
- // The location of the <overlyabale> declaration in the source.
+ // The location of the <overlayable> declaration in the source.
Source source = 2;
// The component responsible for enabling and disabling overlays targeting this <overlayable>.
diff --git a/tools/aapt2/StringPool.cpp b/tools/aapt2/StringPool.cpp
index a8c2666..8eabd32 100644
--- a/tools/aapt2/StringPool.cpp
+++ b/tools/aapt2/StringPool.cpp
@@ -165,13 +165,12 @@
return MakeRefImpl(str, Context{}, true);
}
-StringPool::Ref StringPool::MakeRef(const StringPiece& str, const Context& context,
- Maybe<size_t> index) {
- return MakeRefImpl(str, context, true, index);
+StringPool::Ref StringPool::MakeRef(const StringPiece& str, const Context& context) {
+ return MakeRefImpl(str, context, true);
}
StringPool::Ref StringPool::MakeRefImpl(const StringPiece& str, const Context& context,
- bool unique, Maybe<size_t> index) {
+ bool unique) {
if (unique) {
auto range = indexed_strings_.equal_range(str);
for (auto iter = range.first; iter != range.second; ++iter) {
@@ -181,26 +180,15 @@
}
}
- const size_t size = strings_.size();
- // Insert the string at the end of the string vector if no index is specified
- const size_t insertion_index = index ? index.value() : size;
-
std::unique_ptr<Entry> entry(new Entry());
entry->value = str.to_string();
entry->context = context;
- entry->index_ = insertion_index;
+ entry->index_ = strings_.size();
entry->ref_ = 0;
entry->pool_ = this;
Entry* borrow = entry.get();
- if (insertion_index == size) {
- strings_.emplace_back(std::move(entry));
- } else {
- // Allocate enough space for the string at the index
- strings_.resize(std::max(insertion_index + 1, size));
- strings_[insertion_index] = std::move(entry);
- }
-
+ strings_.emplace_back(std::move(entry));
indexed_strings_.insert(std::make_pair(StringPiece(borrow->value), borrow));
return Ref(borrow);
}
diff --git a/tools/aapt2/StringPool.h b/tools/aapt2/StringPool.h
index 115d5d3..1006ca9 100644
--- a/tools/aapt2/StringPool.h
+++ b/tools/aapt2/StringPool.h
@@ -166,8 +166,7 @@
// Adds a string to the pool, unless it already exists, with a context object that can be used
// when sorting the string pool. Returns a reference to the string in the pool.
- Ref MakeRef(const android::StringPiece& str, const Context& context,
- Maybe<size_t> index = {});
+ Ref MakeRef(const android::StringPiece& str, const Context& context);
// Adds a string from another string pool. Returns a reference to the string in the string pool.
Ref MakeRef(const Ref& ref);
@@ -211,8 +210,7 @@
static bool Flatten(BigBuffer* out, const StringPool& pool, bool utf8, IDiagnostics* diag);
- Ref MakeRefImpl(const android::StringPiece& str, const Context& context, bool unique,
- Maybe<size_t> index = {});
+ Ref MakeRefImpl(const android::StringPiece& str, const Context& context, bool unique);
void ReAssignIndices();
std::vector<std::unique_ptr<Entry>> strings_;
diff --git a/tools/aapt2/StringPool_test.cpp b/tools/aapt2/StringPool_test.cpp
index 648be7d..9a7238b 100644
--- a/tools/aapt2/StringPool_test.cpp
+++ b/tools/aapt2/StringPool_test.cpp
@@ -84,24 +84,6 @@
EXPECT_THAT(ref_c.index(), Eq(2u));
}
-TEST(StringPoolTest, AssignStringIndex) {
- StringPool pool;
-
- StringPool::Ref ref_a = pool.MakeRef("0", StringPool::Context{}, 0u);
- StringPool::Ref ref_b = pool.MakeRef("1", StringPool::Context{}, 1u);
- StringPool::Ref ref_c = pool.MakeRef("5", StringPool::Context{}, 5u);
- StringPool::Ref ref_d = pool.MakeRef("2", StringPool::Context{}, 2u);
- StringPool::Ref ref_e = pool.MakeRef("4", StringPool::Context{}, 4u);
- StringPool::Ref ref_f = pool.MakeRef("3", StringPool::Context{}, 3u);
-
- EXPECT_THAT(ref_a.index(), Eq(0u));
- EXPECT_THAT(ref_b.index(), Eq(1u));
- EXPECT_THAT(ref_d.index(), Eq(2u));
- EXPECT_THAT(ref_f.index(), Eq(3u));
- EXPECT_THAT(ref_e.index(), Eq(4u));
- EXPECT_THAT(ref_c.index(), Eq(5u));
-}
-
TEST(StringPoolTest, PruneStringsWithNoReferences) {
StringPool pool;
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index 7a74ba9..0cf86cc 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -43,7 +43,8 @@
class IApkSerializer {
public:
- IApkSerializer(IAaptContext* context, const Source& source) : context_(context), source_(source) {}
+ IApkSerializer(IAaptContext* context, const Source& source) : context_(context),
+ source_(source) {}
virtual bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
IArchiveWriter* writer, uint32_t compression_flags) = 0;
@@ -167,7 +168,7 @@
std::unique_ptr<io::IData> data = file->file->OpenAsData();
if (!data) {
context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "failed to open file " << *file->path);
+ << "failed to open file " << *file->path);
return false;
}
@@ -175,7 +176,7 @@
std::unique_ptr<xml::XmlResource> xml = xml::Inflate(data->data(), data->size(), &error);
if (xml == nullptr) {
context_->GetDiagnostics()->Error(DiagMessage(source_) << "failed to parse binary XML: "
- << error);
+ << error);
return false;
}
@@ -256,9 +257,6 @@
int Convert(IAaptContext* context, LoadedApk* apk, IArchiveWriter* output_writer,
ApkFormat output_format, TableFlattenerOptions table_flattener_options,
XmlFlattenerOptions xml_flattener_options) {
- // Do not change the ordering of strings in the values string pool
- table_flattener_options.sort_stringpool_entries = false;
-
unique_ptr<IApkSerializer> serializer;
if (output_format == ApkFormat::kBinary) {
serializer.reset(new BinaryApkSerializer(context, apk->GetSource(), table_flattener_options,
@@ -274,7 +272,7 @@
io::IFile* manifest = apk->GetFileCollection()->FindFile(kAndroidManifestPath);
if (!serializer->SerializeXml(apk->GetManifest(), kAndroidManifestPath, true /*utf16*/,
output_writer, (manifest != nullptr && manifest->WasCompressed())
- ? ArchiveEntry::kCompress : 0u)) {
+ ? ArchiveEntry::kCompress : 0u)) {
context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
<< "failed to serialize AndroidManifest.xml");
return 1;
@@ -303,8 +301,7 @@
if (files_written.insert(*file->path).second) {
if (!serializer->SerializeFile(file, output_writer)) {
context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
- << "failed to serialize file "
- << *file->path);
+ << "failed to serialize file " << *file->path);
return 1;
}
}
@@ -338,7 +335,7 @@
if (!io::CopyFileToArchivePreserveCompression(context, file, path, output_writer)) {
context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
- << "failed to copy file " << path);
+ << "failed to copy file " << path);
return 1;
}
}
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 8463046..4961aa5 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -400,7 +400,8 @@
static bool IsVectorElement(const std::string& name) {
return name == "vector" || name == "animated-vector" || name == "pathInterpolator" ||
- name == "objectAnimator" || name == "gradient" || name == "animated-selector";
+ name == "objectAnimator" || name == "gradient" || name == "animated-selector" ||
+ name == "set";
}
template <typename T>
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index 40aaa05..59eb9ec2 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -401,7 +401,6 @@
if (entry->flags & ResTable_entry::FLAG_PUBLIC) {
Visibility visibility;
visibility.level = Visibility::Level::kPublic;
- visibility.source = source_.WithLine(0);
if (!table_->SetVisibilityWithIdMangled(name, visibility, res_id, diag_)) {
return false;
}
@@ -448,7 +447,6 @@
arraysize(header->name)));
overlayable->actor = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->actor,
arraysize(header->name)));
- overlayable->source = source_.WithLine(0);
ResChunkPullParser parser(GetChunkData(chunk),
GetChunkDataLen(chunk));
@@ -473,6 +471,10 @@
& ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION) {
policies |= OverlayableItem::Policy::kProduct;
}
+ if (policy_header->policy_flags
+ & ResTable_overlayable_policy_header::POLICY_SIGNATURE) {
+ policies |= OverlayableItem::Policy::kSignature;
+ }
const ResTable_ref* const ref_begin = reinterpret_cast<const ResTable_ref*>(
((uint8_t *)policy_header) + util::DeviceToHost32(policy_header->header.headerSize));
@@ -491,7 +493,6 @@
}
OverlayableItem overlayable_item(overlayable);
- overlayable_item.source = source_.WithLine(0);
overlayable_item.policies = policies;
if (!table_->SetOverlayable(iter->second, overlayable_item, diag_)) {
return false;
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index 9d341cc..d677317 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -274,7 +274,9 @@
FlattenLibrarySpec(buffer);
}
- FlattenOverlayable(buffer);
+ if (!FlattenOverlayable(buffer)) {
+ return false;
+ }
pkg_writer.Finish();
return true;
@@ -468,23 +470,29 @@
overlayable_chunk = &chunk;
}
+ if (item.policies == 0) {
+ context_->GetDiagnostics()->Error(DiagMessage(item.overlayable->source)
+ << "overlayable "
+ << entry->name
+ << " does not specify policy");
+ return false;
+ }
+
uint32_t policy_flags = 0;
- if (item.policies == OverlayableItem::Policy::kNone) {
- // Encode overlayable entries defined without a policy as publicly overlayable
+ if (item.policies & OverlayableItem::Policy::kPublic) {
policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
- } else {
- if (item.policies & OverlayableItem::Policy::kPublic) {
- policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
- }
- if (item.policies & OverlayableItem::Policy::kSystem) {
- policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION;
- }
- if (item.policies & OverlayableItem::Policy::kVendor) {
- policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION;
- }
- if (item.policies & OverlayableItem::Policy::kProduct) {
- policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION;
- }
+ }
+ if (item.policies & OverlayableItem::Policy::kSystem) {
+ policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION;
+ }
+ if (item.policies & OverlayableItem::Policy::kVendor) {
+ policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION;
+ }
+ if (item.policies & OverlayableItem::Policy::kProduct) {
+ policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION;
+ }
+ if (item.policies & OverlayableItem::Policy::kSignature) {
+ policy_flags |= ResTable_overlayable_policy_header::POLICY_SIGNATURE;
}
auto policy = overlayable_chunk->policy_ids.find(policy_flags);
@@ -702,17 +710,15 @@
} // namespace
bool TableFlattener::Consume(IAaptContext* context, ResourceTable* table) {
- if (options_.sort_stringpool_entries) {
- // We must do this before writing the resources, since the string pool IDs may change.
- table->string_pool.Prune();
- table->string_pool.Sort([](const StringPool::Context &a, const StringPool::Context &b) -> int {
- int diff = util::compare(a.priority, b.priority);
- if (diff == 0) {
- diff = a.config.compare(b.config);
- }
- return diff;
- });
- }
+ // We must do this before writing the resources, since the string pool IDs may change.
+ table->string_pool.Prune();
+ table->string_pool.Sort([](const StringPool::Context& a, const StringPool::Context& b) -> int {
+ int diff = util::compare(a.priority, b.priority);
+ if (diff == 0) {
+ diff = a.config.compare(b.config);
+ }
+ return diff;
+ });
// Write the ResTable header.
ChunkWriter table_writer(buffer_);
diff --git a/tools/aapt2/format/binary/TableFlattener.h b/tools/aapt2/format/binary/TableFlattener.h
index 71330e3..73c1729 100644
--- a/tools/aapt2/format/binary/TableFlattener.h
+++ b/tools/aapt2/format/binary/TableFlattener.h
@@ -44,9 +44,6 @@
// Set of whitelisted resource names to avoid altering in key stringpool
std::set<std::string> whitelisted_resources;
- // When true, sort the entries in the values string pool by priority and configuration.
- bool sort_stringpool_entries = true;
-
// Map from original resource paths to shortened resource paths.
std::map<std::string, std::string> shortened_path_map;
};
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index ddc1173..4c5dbec 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -671,9 +671,6 @@
overlayable_item_two.policies |= OverlayableItem::Policy::kSystem;
overlayable_item_two.policies |= OverlayableItem::Policy::kVendor;
- std::string name_three = "com.app.test:integer/overlayable_three_item";
- OverlayableItem overlayable_item_three(overlayable);
-
std::unique_ptr<ResourceTable> table =
test::ResourceTableBuilder()
.SetPackageId("com.app.test", 0x7f)
@@ -683,8 +680,6 @@
.SetOverlayable(name_one, overlayable_item_one)
.AddSimple(name_two, ResourceId(0x7f020002))
.SetOverlayable(name_two, overlayable_item_two)
- .AddSimple(name_three, ResourceId(0x7f020003))
- .SetOverlayable(name_three, overlayable_item_three)
.Build();
ResourceTable output_table;
@@ -713,16 +708,6 @@
EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kSystem
| OverlayableItem::Policy::kProduct
| OverlayableItem::Policy::kVendor);
-
- search_result = output_table.FindResource(test::ParseNameOrDie(name_three));
- ASSERT_TRUE(search_result);
- ASSERT_THAT(search_result.value().entry, NotNull());
- ASSERT_TRUE(search_result.value().entry->overlayable_item);
- overlayable_item = search_result.value().entry->overlayable_item.value();
- EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic);
- EXPECT_EQ(overlayable_item.overlayable->name, "TestName");
- EXPECT_EQ(overlayable_item.overlayable->actor, "overlay://theme");
- EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic);
}
TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) {
@@ -745,6 +730,8 @@
std::string name_three = "com.app.test:integer/overlayable_three";
OverlayableItem overlayable_item_three(group_one);
+ overlayable_item_three.policies |= OverlayableItem::Policy::kSignature;
+
std::unique_ptr<ResourceTable> table =
test::ResourceTableBuilder()
.SetPackageId("com.app.test", 0x7f)
@@ -793,7 +780,22 @@
result_overlayable = search_result.value().entry->overlayable_item.value();
EXPECT_EQ(result_overlayable.overlayable->name, "OtherName");
EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization");
- EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic);
+ EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSignature);
+}
+
+TEST_F(TableFlattenerTest, FlattenOverlayableNoPolicyFails) {
+ auto group = std::make_shared<Overlayable>("TestName", "overlay://theme");
+ std::string name_zero = "com.app.test:integer/overlayable_zero";
+ OverlayableItem overlayable_item_zero(group);
+
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.test", 0x7f)
+ .AddSimple(name_zero, ResourceId(0x7f020000))
+ .SetOverlayable(name_zero, overlayable_item_zero)
+ .Build();
+ ResourceTable output_table;
+ ASSERT_FALSE(Flatten(context_.get(), {}, table.get(), &output_table));
}
} // namespace aapt
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index aff1b39..06f1bf7 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -390,6 +390,9 @@
case pb::OverlayableItem::PRODUCT:
out_overlayable->policies |= OverlayableItem::Policy::kProduct;
break;
+ case pb::OverlayableItem::SIGNATURE:
+ out_overlayable->policies |= OverlayableItem::Policy::kSignature;
+ break;
default:
*out_error = "unknown overlayable policy";
return false;
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index b549e23..eb2b1a2 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -309,6 +309,9 @@
if (overlayable_item.policies & OverlayableItem::Policy::kVendor) {
pb_overlayable_item->add_policy(pb::OverlayableItem::VENDOR);
}
+ if (overlayable_item.policies & OverlayableItem::Policy::kSignature) {
+ pb_overlayable_item->add_policy(pb::OverlayableItem::SIGNATURE);
+ }
SerializeSourceToPb(overlayable_item.source, source_pool,
pb_overlayable_item->mutable_source());
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index cce3939..d369ac4 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -526,6 +526,10 @@
"FontPack", "overlay://theme"));
overlayable_item_baz.policies |= OverlayableItem::Policy::kPublic;
+ OverlayableItem overlayable_item_boz(std::make_shared<Overlayable>(
+ "IconPack", "overlay://theme"));
+ overlayable_item_boz.policies |= OverlayableItem::Policy::kSignature;
+
OverlayableItem overlayable_item_biz(std::make_shared<Overlayable>(
"Other", "overlay://customization"));
overlayable_item_biz.comment ="comment";
@@ -536,6 +540,7 @@
.SetOverlayable("com.app.a:bool/foo", overlayable_item_foo)
.SetOverlayable("com.app.a:bool/bar", overlayable_item_bar)
.SetOverlayable("com.app.a:bool/baz", overlayable_item_baz)
+ .SetOverlayable("com.app.a:bool/boz", overlayable_item_boz)
.SetOverlayable("com.app.a:bool/biz", overlayable_item_biz)
.AddValue("com.app.a:bool/fiz", ResourceUtils::TryParseBool("true"))
.Build();
@@ -576,6 +581,14 @@
EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic));
+ search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/boz"));
+ ASSERT_TRUE(search_result);
+ ASSERT_TRUE(search_result.value().entry->overlayable_item);
+ overlayable_item = search_result.value().entry->overlayable_item.value();
+ EXPECT_THAT(overlayable_item.overlayable->name, Eq("IconPack"));
+ EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
+ EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kSignature));
+
search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/biz"));
ASSERT_TRUE(search_result);
ASSERT_TRUE(search_result.value().entry->overlayable_item);