Merge "Properly catch ServiceSpecificException if IMS isn't available"
diff --git a/Android.bp b/Android.bp
index 4c983be..0e3d374 100644
--- a/Android.bp
+++ b/Android.bp
@@ -221,7 +221,6 @@
":framework-sax-sources",
":framework-telecomm-sources",
":framework-telephony-common-sources",
- ":framework-telephony-sources",
":framework-wifi-annotations",
":framework-wifi-non-updatable-sources",
":PacProcessor-aidl-sources",
@@ -256,6 +255,9 @@
// etc.
":framework-javastream-protos",
":framework-statslog-gen",
+
+ // telephony annotations
+ ":framework-telephony-annotations",
],
}
@@ -270,6 +272,7 @@
":framework-mediaprovider-sources",
":framework-permission-sources",
":framework-wifi-updatable-sources",
+ ":framework-telephony-sources",
":ike-srcs",
]
}
@@ -303,7 +306,6 @@
"rs/java",
"sax/java",
"telecomm/java",
- "telephony/java",
"wifi/java",
],
},
@@ -383,6 +385,7 @@
"updatable_media_stubs",
"framework_mediaprovider_stubs",
"framework-tethering",
+ "framework-telephony-stubs",
],
jarjar_rules: ":framework-jarjar-rules",
@@ -469,6 +472,7 @@
"//frameworks/base/apex/jobscheduler/framework",
"//frameworks/base/apex/permission/framework",
"//frameworks/base/apex/statsd/service",
+ "//frameworks/base/telephony",
"//frameworks/base/wifi",
"//frameworks/opt/net/wifi/service",
],
@@ -501,6 +505,9 @@
"ike-stubs",
// TODO(b/147200698): should be the stub of framework-tethering
"framework-tethering",
+ // TODO (b/147688669) should be framework-telephony-stubs
+ "framework-telephony",
+ // TODO(jiyong): add stubs for APEXes here
],
sdk_version: "core_platform",
apex_available: ["//apex_available:platform"],
@@ -1182,6 +1189,7 @@
"core/java/com/android/internal/util/Protocol.java",
"core/java/com/android/internal/util/Preconditions.java",
"telephony/java/android/telephony/Annotation.java",
+ ":net-utils-framework-wifi-common-srcs",
],
libs: [
"framework-annotations-lib",
@@ -1226,3 +1234,82 @@
"StubLibraries.bp",
"ApiDocs.bp",
]
+
+// TODO(b/147699819): move to frameworks/base/telephony/ folder
+droidstubs {
+ name: "framework-telephony-stubs-srcs",
+ srcs: [
+ ":framework-telephony-sources",
+ ":framework_native_aidl",
+ ":framework-javastream-protos",
+ ],
+ aidl: {
+ local_include_dirs: [
+ "core/java",
+ "telecomm/java"
+ ],
+ },
+ libs: [
+ "framework-annotations-lib",
+ "android.hardware.radio-V1.5-java",
+ ],
+ defaults: ["framework-module-stubs-defaults-systemapi"],
+ filter_packages: ["android.telephony"],
+ sdk_version: "system_current",
+}
+
+java_library {
+ name: "framework-telephony-stubs",
+ srcs: [":framework-telephony-stubs-srcs"],
+ // TODO(b/147699819): move public aidls to a separate folder and potentially remove
+ // below aidl exports.
+ aidl: {
+ export_include_dirs: ["telephony/java"],
+ },
+ sdk_version: "system_current",
+}
+
+java_library {
+ name: "framework-telephony",
+ srcs: [
+ ":framework-telephony-sources",
+ ],
+ // TODO: change to framework-system-stub to build against system APIs.
+ libs: [
+ "framework-minus-apex",
+ "unsupportedappusage",
+ ],
+ static_libs: [
+ "libphonenumber-platform",
+ "app-compat-annotations",
+ ],
+ sdk_version: "core_platform",
+ aidl: {
+ export_include_dirs: ["telephony/java"],
+ include_dirs: [
+ "frameworks/native/aidl/binder",
+ "frameworks/native/aidl/gui",
+ ]
+ },
+ jarjar_rules: ":telephony-framework-jarjar-rules",
+ dxflags: [
+ "--core-library",
+ "--multi-dex",
+ ],
+ // This is to break the dependency from boot jars.
+ dex_preopt: {
+ enabled: false,
+ },
+ installable: true,
+}
+
+filegroup {
+ // TODO (b/147690217): move to frameworks/base/telephony/common.
+ name: "framework-telephony-annotations",
+ srcs: ["telephony/java/android/telephony/Annotation.java"],
+}
+
+filegroup {
+ name: "telephony-framework-jarjar-rules",
+ srcs: ["telephony/framework-telephony-jarjar-rules.txt"],
+}
diff --git a/StubLibraries.bp b/StubLibraries.bp
index baa3c61..cdc0d32 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -51,6 +51,10 @@
":core_public_api_files",
":ike-api-srcs",
],
+ // TODO(b/147699819): remove below aidl includes.
+ aidl: {
+ local_include_dirs: ["telephony/java"],
+ },
libs: ["framework-internal-utils"],
installable: false,
annotations_enabled: true,
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index 8bc14d7..17573bb 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -24,11 +24,11 @@
import static android.os.storage.VolumeInfo.TYPE_PUBLIC;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
-import static com.android.server.stats.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
-import static com.android.server.stats.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
-import static com.android.server.stats.ProcfsMemoryUtil.forEachPid;
-import static com.android.server.stats.ProcfsMemoryUtil.readCmdlineFromProcfs;
-import static com.android.server.stats.ProcfsMemoryUtil.readMemorySnapshotFromProcfs;
+import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
+import static com.android.server.stats.pull.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
+import static com.android.server.stats.pull.ProcfsMemoryUtil.forEachPid;
+import static com.android.server.stats.pull.ProcfsMemoryUtil.readCmdlineFromProcfs;
+import static com.android.server.stats.pull.ProcfsMemoryUtil.readMemorySnapshotFromProcfs;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -135,8 +135,8 @@
import com.android.server.am.MemoryStatUtil.MemoryStat;
import com.android.server.notification.NotificationManagerService;
import com.android.server.role.RoleManagerInternal;
-import com.android.server.stats.IonMemoryUtil.IonAllocations;
-import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot;
+import com.android.server.stats.pull.IonMemoryUtil.IonAllocations;
+import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot;
import com.android.server.storage.DiskStatsFileLogger;
import com.android.server.storage.DiskStatsLoggingService;
@@ -722,207 +722,6 @@
pulledData.add(e);
}
- private void pullProcessMemoryState(
- int tagId, long elapsedNanos, long wallClockNanos,
- List<StatsLogEventWrapper> pulledData) {
- List<ProcessMemoryState> processMemoryStates =
- LocalServices.getService(
- ActivityManagerInternal.class).getMemoryStateForProcesses();
- for (ProcessMemoryState processMemoryState : processMemoryStates) {
- final MemoryStat memoryStat = readMemoryStatFromFilesystem(processMemoryState.uid,
- processMemoryState.pid);
- if (memoryStat == null) {
- continue;
- }
- StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
- e.writeInt(processMemoryState.uid);
- e.writeString(processMemoryState.processName);
- e.writeInt(processMemoryState.oomScore);
- e.writeLong(memoryStat.pgfault);
- e.writeLong(memoryStat.pgmajfault);
- e.writeLong(memoryStat.rssInBytes);
- e.writeLong(memoryStat.cacheInBytes);
- e.writeLong(memoryStat.swapInBytes);
- e.writeLong(-1); // unused
- e.writeLong(-1); // unused
- e.writeInt(-1); // unsed
- pulledData.add(e);
- }
- }
-
- private void pullProcessMemoryHighWaterMark(
- int tagId, long elapsedNanos, long wallClockNanos,
- List<StatsLogEventWrapper> pulledData) {
- List<ProcessMemoryState> managedProcessList =
- LocalServices.getService(
- ActivityManagerInternal.class).getMemoryStateForProcesses();
- for (ProcessMemoryState managedProcess : managedProcessList) {
- final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(managedProcess.pid);
- if (snapshot == null) {
- continue;
- }
- StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
- e.writeInt(managedProcess.uid);
- e.writeString(managedProcess.processName);
- // RSS high-water mark in bytes.
- e.writeLong((long) snapshot.rssHighWaterMarkInKilobytes * 1024L);
- e.writeInt(snapshot.rssHighWaterMarkInKilobytes);
- pulledData.add(e);
- }
- forEachPid((pid, cmdLine) -> {
- if (!MEMORY_INTERESTING_NATIVE_PROCESSES.contains(cmdLine)) {
- return;
- }
- final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(pid);
- if (snapshot == null) {
- return;
- }
- // Sometimes we get here a process that is not included in the whitelist. It comes
- // from forking the zygote for an app. We can ignore that sample because this process
- // is collected by ProcessMemoryState.
- if (isAppUid(snapshot.uid)) {
- return;
- }
- StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
- e.writeInt(snapshot.uid);
- e.writeString(cmdLine);
- // RSS high-water mark in bytes.
- e.writeLong((long) snapshot.rssHighWaterMarkInKilobytes * 1024L);
- e.writeInt(snapshot.rssHighWaterMarkInKilobytes);
- pulledData.add(e);
- });
- // Invoke rss_hwm_reset binary to reset RSS HWM counters for all processes.
- SystemProperties.set("sys.rss_hwm_reset.on", "1");
- }
-
- private void pullProcessMemorySnapshot(
- int tagId, long elapsedNanos, long wallClockNanos,
- List<StatsLogEventWrapper> pulledData) {
- List<ProcessMemoryState> managedProcessList =
- LocalServices.getService(
- ActivityManagerInternal.class).getMemoryStateForProcesses();
- for (ProcessMemoryState managedProcess : managedProcessList) {
- final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(managedProcess.pid);
- if (snapshot == null) {
- continue;
- }
- StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
- e.writeInt(managedProcess.uid);
- e.writeString(managedProcess.processName);
- e.writeInt(managedProcess.pid);
- e.writeInt(managedProcess.oomScore);
- e.writeInt(snapshot.rssInKilobytes);
- e.writeInt(snapshot.anonRssInKilobytes);
- e.writeInt(snapshot.swapInKilobytes);
- e.writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes);
- pulledData.add(e);
- }
- forEachPid((pid, cmdLine) -> {
- if (!MEMORY_INTERESTING_NATIVE_PROCESSES.contains(cmdLine)) {
- return;
- }
- final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(pid);
- if (snapshot == null) {
- return;
- }
- // Sometimes we get here a process that is not included in the whitelist. It comes
- // from forking the zygote for an app. We can ignore that sample because this process
- // is collected by ProcessMemoryState.
- if (isAppUid(snapshot.uid)) {
- return;
- }
- StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
- e.writeInt(snapshot.uid);
- e.writeString(cmdLine);
- e.writeInt(pid);
- e.writeInt(-1001); // Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1.
- e.writeInt(snapshot.rssInKilobytes);
- e.writeInt(snapshot.anonRssInKilobytes);
- e.writeInt(snapshot.swapInKilobytes);
- e.writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes);
- pulledData.add(e);
- });
- }
-
- private static boolean isAppUid(int uid) {
- return uid >= MIN_APP_UID;
- }
-
- private void pullSystemIonHeapSize(
- int tagId, long elapsedNanos, long wallClockNanos,
- List<StatsLogEventWrapper> pulledData) {
- final long systemIonHeapSizeInBytes = readSystemIonHeapSizeFromDebugfs();
- StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
- e.writeLong(systemIonHeapSizeInBytes);
- pulledData.add(e);
- }
-
- private void pullProcessSystemIonHeapSize(
- int tagId, long elapsedNanos, long wallClockNanos,
- List<StatsLogEventWrapper> pulledData) {
- List<IonAllocations> result = readProcessSystemIonHeapSizesFromDebugfs();
- for (IonAllocations allocations : result) {
- StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
- e.writeInt(getUidForPid(allocations.pid));
- e.writeString(readCmdlineFromProcfs(allocations.pid));
- e.writeInt((int) (allocations.totalSizeInBytes / 1024));
- e.writeInt(allocations.count);
- e.writeInt((int) (allocations.maxSizeInBytes / 1024));
- pulledData.add(e);
- }
- }
-
- private void pullBinderCallsStats(
- int tagId, long elapsedNanos, long wallClockNanos,
- List<StatsLogEventWrapper> pulledData) {
- BinderCallsStatsService.Internal binderStats =
- LocalServices.getService(BinderCallsStatsService.Internal.class);
- if (binderStats == null) {
- throw new IllegalStateException("binderStats is null");
- }
-
- List<ExportedCallStat> callStats = binderStats.getExportedCallStats();
- binderStats.reset();
- for (ExportedCallStat callStat : callStats) {
- StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
- e.writeInt(callStat.workSourceUid);
- e.writeString(callStat.className);
- e.writeString(callStat.methodName);
- e.writeLong(callStat.callCount);
- e.writeLong(callStat.exceptionCount);
- e.writeLong(callStat.latencyMicros);
- e.writeLong(callStat.maxLatencyMicros);
- e.writeLong(callStat.cpuTimeMicros);
- e.writeLong(callStat.maxCpuTimeMicros);
- e.writeLong(callStat.maxReplySizeBytes);
- e.writeLong(callStat.maxRequestSizeBytes);
- e.writeLong(callStat.recordedCallCount);
- e.writeInt(callStat.screenInteractive ? 1 : 0);
- e.writeInt(callStat.callingUid);
- pulledData.add(e);
- }
- }
-
- private void pullBinderCallsStatsExceptions(
- int tagId, long elapsedNanos, long wallClockNanos,
- List<StatsLogEventWrapper> pulledData) {
- BinderCallsStatsService.Internal binderStats =
- LocalServices.getService(BinderCallsStatsService.Internal.class);
- if (binderStats == null) {
- throw new IllegalStateException("binderStats is null");
- }
-
- ArrayMap<String, Integer> exceptionStats = binderStats.getExportedExceptionStats();
- // TODO: decouple binder calls exceptions with the rest of the binder calls data so that we
- // can reset the exception stats.
- for (Entry<String, Integer> entry : exceptionStats.entrySet()) {
- StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
- e.writeString(entry.getKey());
- e.writeInt(entry.getValue());
- pulledData.add(e);
- }
- }
-
private void pullLooperStats(int tagId, long elapsedNanos, long wallClockNanos,
List<StatsLogEventWrapper> pulledData) {
LooperStats looperStats = LocalServices.getService(LooperStats.class);
@@ -1397,49 +1196,6 @@
}
}
- private void pullTemperature(int tagId, long elapsedNanos, long wallClockNanos,
- List<StatsLogEventWrapper> pulledData) {
- long callingToken = Binder.clearCallingIdentity();
- try {
- List<Temperature> temperatures = sThermalService.getCurrentTemperatures();
- for (Temperature temp : temperatures) {
- StatsLogEventWrapper e =
- new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
- e.writeInt(temp.getType());
- e.writeString(temp.getName());
- e.writeInt((int) (temp.getValue() * 10));
- e.writeInt(temp.getStatus());
- pulledData.add(e);
- }
- } catch (RemoteException e) {
- // Should not happen.
- Slog.e(TAG, "Disconnected from thermal service. Cannot pull temperatures.");
- } finally {
- Binder.restoreCallingIdentity(callingToken);
- }
- }
-
- private void pullCoolingDevices(int tagId, long elapsedNanos, long wallClockNanos,
- List<StatsLogEventWrapper> pulledData) {
- long callingToken = Binder.clearCallingIdentity();
- try {
- List<CoolingDevice> devices = sThermalService.getCurrentCoolingDevices();
- for (CoolingDevice device : devices) {
- StatsLogEventWrapper e =
- new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
- e.writeInt(device.getType());
- e.writeString(device.getName());
- e.writeInt((int) (device.getValue()));
- pulledData.add(e);
- }
- } catch (RemoteException e) {
- // Should not happen.
- Slog.e(TAG, "Disconnected from thermal service. Cannot pull temperatures.");
- } finally {
- Binder.restoreCallingIdentity(callingToken);
- }
- }
-
private void pullDebugElapsedClock(int tagId,
long elapsedNanos, final long wallClockNanos, List<StatsLogEventWrapper> pulledData) {
final long elapsedMillis = SystemClock.elapsedRealtime();
@@ -1823,41 +1579,6 @@
break;
}
- case StatsLog.PROCESS_MEMORY_STATE: {
- pullProcessMemoryState(tagId, elapsedNanos, wallClockNanos, ret);
- break;
- }
-
- case StatsLog.PROCESS_MEMORY_HIGH_WATER_MARK: {
- pullProcessMemoryHighWaterMark(tagId, elapsedNanos, wallClockNanos, ret);
- break;
- }
-
- case StatsLog.PROCESS_MEMORY_SNAPSHOT: {
- pullProcessMemorySnapshot(tagId, elapsedNanos, wallClockNanos, ret);
- break;
- }
-
- case StatsLog.SYSTEM_ION_HEAP_SIZE: {
- pullSystemIonHeapSize(tagId, elapsedNanos, wallClockNanos, ret);
- break;
- }
-
- case StatsLog.PROCESS_SYSTEM_ION_HEAP_SIZE: {
- pullProcessSystemIonHeapSize(tagId, elapsedNanos, wallClockNanos, ret);
- break;
- }
-
- case StatsLog.BINDER_CALLS: {
- pullBinderCallsStats(tagId, elapsedNanos, wallClockNanos, ret);
- break;
- }
-
- case StatsLog.BINDER_CALLS_EXCEPTIONS: {
- pullBinderCallsStatsExceptions(tagId, elapsedNanos, wallClockNanos, ret);
- break;
- }
-
case StatsLog.LOOPER_STATS: {
pullLooperStats(tagId, elapsedNanos, wallClockNanos, ret);
break;
@@ -1920,16 +1641,6 @@
break;
}
- case StatsLog.TEMPERATURE: {
- pullTemperature(tagId, elapsedNanos, wallClockNanos, ret);
- break;
- }
-
- case StatsLog.COOLING_DEVICE: {
- pullCoolingDevices(tagId, elapsedNanos, wallClockNanos, ret);
- break;
- }
-
case StatsLog.DEBUG_ELAPSED_CLOCK: {
pullDebugElapsedClock(tagId, elapsedNanos, wallClockNanos, ret);
break;
diff --git a/api/current.txt b/api/current.txt
index 54bfac2..e27c318 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -30811,6 +30811,7 @@
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsAppInteractionRequired(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsEnhancedOpen(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsHiddenSsid(boolean);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsInitialAutoJoinEnabled(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsMetered(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsUserInteractionRequired(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPasspointConfig(@NonNull android.net.wifi.hotspot2.PasspointConfiguration);
diff --git a/api/module-app-current.txt b/api/module-app-current.txt
index d802177..4307e67 100644
--- a/api/module-app-current.txt
+++ b/api/module-app-current.txt
@@ -1 +1,9 @@
// Signature format: 2.0
+package android.app {
+
+ public final class NotificationChannel implements android.os.Parcelable {
+ method public void setBlockableSystem(boolean);
+ }
+
+}
+
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index c8253a0..1cb1c20 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -124,3 +124,11 @@
}
+package android.util {
+
+ public final class Log {
+ method public static int logToRadioBuffer(int, @Nullable String, @Nullable String);
+ }
+
+}
+
diff --git a/api/system-current.txt b/api/system-current.txt
index d00bd84..e532a3a 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6246,6 +6246,7 @@
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveSoftApBackupData();
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMacRandomizationSettingPasspointEnabled(@NonNull String, boolean);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean setSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsConfiguratorInitiator(@NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
@@ -6595,6 +6596,7 @@
public final class PasspointConfiguration implements android.os.Parcelable {
method public boolean isAutoJoinEnabled();
+ method public boolean isMacRandomizationEnabled();
}
public abstract class ProvisioningCallback {
diff --git a/api/test-current.txt b/api/test-current.txt
index 36e2d45..28119e3 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2514,10 +2514,12 @@
method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static float getFloat(@NonNull String, @NonNull String, float);
method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static int getInt(@NonNull String, @NonNull String, int);
method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static long getLong(@NonNull String, @NonNull String, long);
+ method @NonNull @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static android.provider.DeviceConfig.Properties getProperties(@NonNull String, @NonNull java.lang.String...);
method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getProperty(@NonNull String, @NonNull String);
method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getString(@NonNull String, @NonNull String, @Nullable String);
method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String);
+ method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperties(@NonNull android.provider.DeviceConfig.Properties) throws android.provider.DeviceConfig.BadConfigException;
method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean);
field public static final String NAMESPACE_ANDROID = "android";
field public static final String NAMESPACE_AUTOFILL = "autofill";
@@ -2529,6 +2531,10 @@
field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
}
+ public static class DeviceConfig.BadConfigException extends java.lang.Exception {
+ ctor public DeviceConfig.BadConfigException();
+ }
+
public static interface DeviceConfig.OnPropertiesChangedListener {
method public void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties);
}
diff --git a/cmds/incident_helper/Android.bp b/cmds/incident_helper/Android.bp
index d7b6d69..64f4c66 100644
--- a/cmds/incident_helper/Android.bp
+++ b/cmds/incident_helper/Android.bp
@@ -1,3 +1,28 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_binary {
+ name: "incident-helper-cmd",
+ wrapper: "incident_helper_cmd",
+ srcs: [
+ "java/**/*.java",
+ ],
+ proto: {
+ plugin: "javastream",
+ },
+}
+
cc_defaults {
name: "incident_helper_defaults",
diff --git a/cmds/incident_helper/incident_helper_cmd b/cmds/incident_helper/incident_helper_cmd
new file mode 100644
index 0000000..d45f7df
--- /dev/null
+++ b/cmds/incident_helper/incident_helper_cmd
@@ -0,0 +1,6 @@
+#!/system/bin/sh
+# Script to start "incident_helper_cmd" on the device
+#
+base=/system
+export CLASSPATH=$base/framework/incident-helper-cmd.jar
+exec app_process $base/bin com.android.commands.incident.IncidentHelper "$@"
diff --git a/cmds/incident_helper/java/com/android/commands/incident/ExecutionException.java b/cmds/incident_helper/java/com/android/commands/incident/ExecutionException.java
new file mode 100644
index 0000000..d97b17e
--- /dev/null
+++ b/cmds/incident_helper/java/com/android/commands/incident/ExecutionException.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 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.commands.incident;
+
+/**
+ * Thrown when there is an error executing a section.
+ */
+public class ExecutionException extends Exception {
+ /**
+ * Constructs a ExecutionException.
+ *
+ * @param msg the message
+ */
+ public ExecutionException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs a ExecutionException from another exception.
+ *
+ * @param e the exception
+ */
+ public ExecutionException(Exception e) {
+ super(e);
+ }
+}
diff --git a/cmds/incident_helper/java/com/android/commands/incident/IncidentHelper.java b/cmds/incident_helper/java/com/android/commands/incident/IncidentHelper.java
new file mode 100644
index 0000000..e5874e0
--- /dev/null
+++ b/cmds/incident_helper/java/com/android/commands/incident/IncidentHelper.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 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.commands.incident;
+
+import android.util.Log;
+
+import com.android.commands.incident.sections.PersistLogSection;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * Helper command runner for incidentd to run customized command to gather data for a non-standard
+ * section.
+ */
+public class IncidentHelper {
+ private static final String TAG = "IncidentHelper";
+ private static boolean sLog = false;
+ private final List<String> mArgs;
+ private ListIterator<String> mArgsIterator;
+
+ private IncidentHelper(String[] args) {
+ mArgs = Collections.unmodifiableList(Arrays.asList(args));
+ mArgsIterator = mArgs.listIterator();
+ }
+
+ private static void showUsage(PrintStream out) {
+ out.println("This command is not designed to be run manually.");
+ out.println("Usage:");
+ out.println(" run [sectionName]");
+ }
+
+ private void run(String[] args) throws ExecutionException {
+ Section section = null;
+ List<String> sectionArgs = new ArrayList<>();
+ while (mArgsIterator.hasNext()) {
+ String arg = mArgsIterator.next();
+ if ("-l".equals(arg)) {
+ sLog = true;
+ Log.i(TAG, "Args: [" + String.join(",", args) + "]");
+ } else if ("run".equals(arg)) {
+ section = getSection(nextArgRequired());
+ mArgsIterator.forEachRemaining(sectionArgs::add);
+ break;
+ } else {
+ log(Log.WARN, TAG, "Error: Unknown argument: " + arg);
+ return;
+ }
+ }
+ section.run(System.in, System.out, sectionArgs);
+ }
+
+ private static Section getSection(String name) throws IllegalArgumentException {
+ if ("persisted_logs".equals(name)) {
+ return new PersistLogSection();
+ }
+ throw new IllegalArgumentException("Section not found: " + name);
+ }
+
+ private String nextArgRequired() {
+ if (!mArgsIterator.hasNext()) {
+ throw new IllegalArgumentException(
+ "Arg required after \"" + mArgs.get(mArgsIterator.previousIndex()) + "\"");
+ }
+ return mArgsIterator.next();
+ }
+
+ /**
+ * Print the given message to stderr, also log it if asked to (set by -l cmd arg).
+ */
+ public static void log(int priority, String tag, String msg) {
+ System.err.println(tag + ": " + msg);
+ if (sLog) {
+ Log.println(priority, tag, msg);
+ }
+ }
+
+ /**
+ * Command-line entry point.
+ *
+ * @param args The command-line arguments
+ */
+ public static void main(String[] args) {
+ if (args.length == 0) {
+ showUsage(System.err);
+ System.exit(0);
+ }
+ IncidentHelper incidentHelper = new IncidentHelper(args);
+ try {
+ incidentHelper.run(args);
+ } catch (IllegalArgumentException e) {
+ showUsage(System.err);
+ System.err.println();
+ e.printStackTrace(System.err);
+ if (sLog) {
+ Log.e(TAG, "Error: ", e);
+ }
+ } catch (Exception e) {
+ e.printStackTrace(System.err);
+ if (sLog) {
+ Log.e(TAG, "Error: ", e);
+ }
+ System.exit(1);
+ }
+ }
+}
diff --git a/cmds/incident_helper/java/com/android/commands/incident/Section.java b/cmds/incident_helper/java/com/android/commands/incident/Section.java
new file mode 100644
index 0000000..1c8c657
--- /dev/null
+++ b/cmds/incident_helper/java/com/android/commands/incident/Section.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 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.commands.incident;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+
+/** Section interface used by {@link IncidentHelper}. */
+public interface Section {
+ /**
+ * Writes protobuf wire format to out, optionally reads data from in, with supplied args.
+ */
+ void run(InputStream in, OutputStream out, List<String> args) throws ExecutionException;
+}
diff --git a/cmds/incident_helper/java/com/android/commands/incident/sections/PersistLogSection.java b/cmds/incident_helper/java/com/android/commands/incident/sections/PersistLogSection.java
new file mode 100644
index 0000000..f9d2e79
--- /dev/null
+++ b/cmds/incident_helper/java/com/android/commands/incident/sections/PersistLogSection.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2020 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.commands.incident.sections;
+
+import android.util.Log;
+import android.util.PersistedLogProto;
+import android.util.TextLogEntry;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.commands.incident.ExecutionException;
+import com.android.commands.incident.IncidentHelper;
+import com.android.commands.incident.Section;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Comparator;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+/** PersistLogSection reads persisted logs and parses them into a PersistedLogProto. */
+public class PersistLogSection implements Section {
+ private static final String TAG = "IH_PersistLog";
+ private static final String LOG_DIR = "/data/misc/logd/";
+ // Persist log files are named logcat, logcat.001, logcat.002, logcat.003, ...
+ private static final Pattern LOG_FILE_RE = Pattern.compile("logcat(\\.\\d+)?");
+ private static final Pattern BUFFER_BEGIN_RE =
+ Pattern.compile("--------- (?:beginning of|switch to) (.*)");
+ private static final Map<String, Long> SECTION_NAME_TO_ID = new HashMap<>();
+ private static final Map<Character, Integer> LOG_PRIORITY_MAP = new HashMap<>();
+ private static final String DEFAULT_BUFFER = "main";
+
+ static {
+ SECTION_NAME_TO_ID.put("main", PersistedLogProto.MAIN_LOGS);
+ SECTION_NAME_TO_ID.put("radio", PersistedLogProto.RADIO_LOGS);
+ SECTION_NAME_TO_ID.put("events", PersistedLogProto.EVENTS_LOGS);
+ SECTION_NAME_TO_ID.put("system", PersistedLogProto.SYSTEM_LOGS);
+ SECTION_NAME_TO_ID.put("crash", PersistedLogProto.CRASH_LOGS);
+ SECTION_NAME_TO_ID.put("kernel", PersistedLogProto.KERNEL_LOGS);
+ }
+
+ static {
+ LOG_PRIORITY_MAP.put('V', TextLogEntry.LOG_VERBOSE);
+ LOG_PRIORITY_MAP.put('D', TextLogEntry.LOG_DEBUG);
+ LOG_PRIORITY_MAP.put('I', TextLogEntry.LOG_INFO);
+ LOG_PRIORITY_MAP.put('W', TextLogEntry.LOG_WARN);
+ LOG_PRIORITY_MAP.put('E', TextLogEntry.LOG_ERROR);
+ LOG_PRIORITY_MAP.put('F', TextLogEntry.LOG_FATAL);
+ LOG_PRIORITY_MAP.put('S', TextLogEntry.LOG_SILENT);
+ }
+
+ /**
+ * Caches dates at 00:00:00 to epoch second elapsed conversion. There are only a few different
+ * dates in persisted logs in one device, and constructing DateTime object is relatively
+ * expensive.
+ */
+ private Map<Integer, Long> mEpochTimeCache = new HashMap<>();
+ private ProtoOutputStream mProto;
+ private long mCurrFieldId;
+ private long mMaxBytes = Long.MAX_VALUE;
+
+ @Override
+ public void run(InputStream in, OutputStream out, List<String> args) throws ExecutionException {
+ parseArgs(args);
+ Path logDirPath = Paths.get(LOG_DIR);
+ if (!Files.exists(logDirPath)) {
+ IncidentHelper.log(Log.WARN, TAG, "Skip dump. " + logDirPath + " does not exist.");
+ return;
+ }
+ if (!Files.isReadable(logDirPath)) {
+ IncidentHelper.log(Log.WARN, TAG, "Skip dump. " + logDirPath + " is not readable.");
+ return;
+ }
+ mProto = new ProtoOutputStream(out);
+ setCurrentSection(DEFAULT_BUFFER);
+ final Matcher logFileRe = LOG_FILE_RE.matcher("");
+ // Need to process older log files first and write logs to proto in chronological order
+ // But we want to process only the latest ones if there is a size limit
+ try (Stream<File> stream = Files.list(logDirPath).map(Path::toFile)
+ .filter(f -> !f.isDirectory() && match(logFileRe, f.getName()) != null)
+ .sorted(Comparator.comparingLong(File::lastModified).reversed())) {
+ Iterator<File> iter = stream.iterator();
+ List<File> filesToProcess = new ArrayList<>();
+ long sumBytes = 0;
+ while (iter.hasNext()) {
+ File file = iter.next();
+ sumBytes += file.length();
+ if (sumBytes > mMaxBytes) {
+ break;
+ }
+ filesToProcess.add(file);
+ }
+ IncidentHelper.log(Log.INFO, TAG, "Limit # log files to " + filesToProcess.size());
+ filesToProcess.stream()
+ .sorted(Comparator.comparingLong(File::lastModified))
+ .forEachOrdered(this::processFile);
+ } catch (IOException e) {
+ throw new ExecutionException(e);
+ } finally {
+ mProto.flush();
+ }
+ IncidentHelper.log(Log.DEBUG, TAG, "Bytes written: " + mProto.getBytes().length);
+ }
+
+ private void parseArgs(List<String> args) {
+ Iterator<String> iter = args.iterator();
+ while (iter.hasNext()) {
+ String arg = iter.next();
+ if ("--limit".equals(arg) && iter.hasNext()) {
+ String sizeStr = iter.next().toLowerCase();
+ if (sizeStr.endsWith("mb")) {
+ mMaxBytes = Long.parseLong(sizeStr.replace("mb", "")) * 1024 * 1024;
+ } else if (sizeStr.endsWith("kb")) {
+ mMaxBytes = Long.parseLong(sizeStr.replace("kb", "")) * 1024;
+ } else {
+ mMaxBytes = Long.parseLong(sizeStr);
+ }
+ } else {
+ throw new IllegalArgumentException("Unknown argument: " + arg);
+ }
+ }
+ }
+
+ private void processFile(File file) {
+ final Matcher bufferBeginRe = BUFFER_BEGIN_RE.matcher("");
+ try (BufferedReader reader = Files.newBufferedReader(file.toPath(),
+ StandardCharsets.UTF_8)) {
+ String line;
+ Matcher m;
+ while ((line = reader.readLine()) != null) {
+ if ((m = match(bufferBeginRe, line)) != null) {
+ setCurrentSection(m.group(1));
+ continue;
+ }
+ parseLine(line);
+ }
+ } catch (IOException e) {
+ // Non-fatal error. We can skip and still process other files.
+ IncidentHelper.log(Log.WARN, TAG, "Error reading \"" + file + "\": " + e.getMessage());
+ }
+ IncidentHelper.log(Log.DEBUG, TAG, "Finished reading " + file);
+ }
+
+ private void setCurrentSection(String sectionName) {
+ Long sectionId = SECTION_NAME_TO_ID.get(sectionName);
+ if (sectionId == null) {
+ IncidentHelper.log(Log.WARN, TAG, "Section does not exist: " + sectionName);
+ sectionId = SECTION_NAME_TO_ID.get(DEFAULT_BUFFER);
+ }
+ mCurrFieldId = sectionId;
+ }
+
+ /**
+ * Parse a log line in the following format:
+ * 01-01 15:01:47.723501 2738 2895 I Exp_TAG: example log line
+ *
+ * It does not use RegExp for performance reasons. Using this RegExp "(\\d{2})-(\\d{2})\\s
+ * (\\d{2}):(\\d{2}):(\\d{2}).(\\d{6})\\s+(\\d+)\\s+(\\d+)\\s+(.)\\s+(.*?):\\s(.*)" is twice as
+ * slow as the current approach.
+ */
+ private void parseLine(String line) {
+ long token = mProto.start(mCurrFieldId);
+ try {
+ mProto.write(TextLogEntry.SEC, getEpochSec(line));
+ // Nanosec is 15th to 20th digits of "10-01 02:57:27.710652" times 1000
+ mProto.write(TextLogEntry.NANOSEC, parseInt(line, 15, 21) * 1000L);
+
+ int start = nextNonBlank(line, 21);
+ int end = line.indexOf(' ', start + 1);
+ mProto.write(TextLogEntry.PID, parseInt(line, start, end));
+
+ start = nextNonBlank(line, end);
+ end = line.indexOf(' ', start + 1);
+ mProto.write(TextLogEntry.TID, parseInt(line, start, end));
+
+ start = nextNonBlank(line, end);
+ char priority = line.charAt(start);
+ mProto.write(TextLogEntry.PRIORITY,
+ LOG_PRIORITY_MAP.getOrDefault(priority, TextLogEntry.LOG_DEFAULT));
+
+ start = nextNonBlank(line, start + 1);
+ end = line.indexOf(": ", start);
+ mProto.write(TextLogEntry.TAG, line.substring(start, end).trim());
+ mProto.write(TextLogEntry.LOG, line.substring(Math.min(end + 2, line.length())));
+ } catch (RuntimeException e) {
+ // Error reporting is likely piped to /dev/null. Inserting it into the proto to make
+ // it more useful.
+ mProto.write(TextLogEntry.SEC, System.currentTimeMillis() / 1000);
+ mProto.write(TextLogEntry.PRIORITY, TextLogEntry.LOG_ERROR);
+ mProto.write(TextLogEntry.TAG, TAG);
+ mProto.write(TextLogEntry.LOG,
+ "Error parsing \"" + line + "\"" + ": " + e.getMessage());
+ }
+ mProto.end(token);
+ }
+
+ // ============== Below are util methods to parse log lines ==============
+
+ private static int nextNonBlank(String line, int start) {
+ for (int i = start; i < line.length(); i++) {
+ if (line.charAt(i) != ' ') {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Gets the epoch second from the line string. Line starts with a fixed-length timestamp like
+ * "10-01 02:57:27.710652"
+ */
+ private long getEpochSec(String line) {
+ int month = getDigit(line, 0) * 10 + getDigit(line, 1);
+ int day = getDigit(line, 3) * 10 + getDigit(line, 4);
+
+ int mmdd = month * 100 + day;
+ long epochSecBase = mEpochTimeCache.computeIfAbsent(mmdd, (key) -> {
+ final GregorianCalendar calendar = new GregorianCalendar();
+ calendar.set(Calendar.MONTH, (month + 12 - 1) % 12);
+ calendar.set(Calendar.DAY_OF_MONTH, day);
+ calendar.set(Calendar.HOUR_OF_DAY, 0);
+ calendar.set(Calendar.MINUTE, 0);
+ calendar.set(Calendar.SECOND, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
+ // Date in log entries can never be in the future. If it happens, it means we are off
+ // by one year.
+ if (calendar.getTimeInMillis() > System.currentTimeMillis()) {
+ calendar.roll(Calendar.YEAR, /*amount=*/-1);
+ }
+ return calendar.getTimeInMillis() / 1000;
+ });
+
+ int hh = getDigit(line, 6) * 10 + getDigit(line, 7);
+ int mm = getDigit(line, 9) * 10 + getDigit(line, 10);
+ int ss = getDigit(line, 12) * 10 + getDigit(line, 13);
+ return epochSecBase + hh * 3600 + mm * 60 + ss;
+ }
+
+ private static int parseInt(String line, /*inclusive*/ int start, /*exclusive*/ int end) {
+ int num = 0;
+ for (int i = start; i < end; i++) {
+ num = num * 10 + getDigit(line, i);
+ }
+ return num;
+ }
+
+ private static int getDigit(String str, int pos) {
+ int digit = str.charAt(pos) - '0';
+ if (digit < 0 || digit > 9) {
+ throw new NumberFormatException("'" + str.charAt(pos) + "' is not a digit.");
+ }
+ return digit;
+ }
+
+ private static Matcher match(Matcher matcher, String text) {
+ matcher.reset(text);
+ return matcher.matches() ? matcher : null;
+ }
+}
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 591d727..d5cda85 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -95,45 +95,6 @@
{{.atomTag = android::util::BATTERY_CYCLE_COUNT},
{.puller = new ResourceHealthManagerPuller(android::util::BATTERY_CYCLE_COUNT)}},
- // process_memory_state
- {{.atomTag = android::util::PROCESS_MEMORY_STATE},
- {.additiveFields = {4, 5, 6, 7, 8},
- .puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}},
-
- // process_memory_high_water_mark
- {{.atomTag = android::util::PROCESS_MEMORY_HIGH_WATER_MARK},
- {.puller =
- new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_HIGH_WATER_MARK)}},
-
- // process_memory_snapshot
- {{.atomTag = android::util::PROCESS_MEMORY_SNAPSHOT},
- {.puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_SNAPSHOT)}},
-
- // system_ion_heap_size
- {{.atomTag = android::util::SYSTEM_ION_HEAP_SIZE},
- {.puller = new StatsCompanionServicePuller(android::util::SYSTEM_ION_HEAP_SIZE)}},
-
- // process_system_ion_heap_size
- {{.atomTag = android::util::PROCESS_SYSTEM_ION_HEAP_SIZE},
- {.puller = new StatsCompanionServicePuller(android::util::PROCESS_SYSTEM_ION_HEAP_SIZE)}},
-
- // temperature
- {{.atomTag = android::util::TEMPERATURE},
- {.puller = new StatsCompanionServicePuller(android::util::TEMPERATURE)}},
-
- // cooling_device
- {{.atomTag = android::util::COOLING_DEVICE},
- {.puller = new StatsCompanionServicePuller(android::util::COOLING_DEVICE)}},
-
- // binder_calls
- {{.atomTag = android::util::BINDER_CALLS},
- {.additiveFields = {4, 5, 6, 8, 12},
- .puller = new StatsCompanionServicePuller(android::util::BINDER_CALLS)}},
-
- // binder_calls_exceptions
- {{.atomTag = android::util::BINDER_CALLS_EXCEPTIONS},
- {.puller = new StatsCompanionServicePuller(android::util::BINDER_CALLS_EXCEPTIONS)}},
-
// looper_stats
{{.atomTag = android::util::LOOPER_STATS},
{.additiveFields = {5, 6, 7, 8, 9},
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 78f9cc8..5a4622e 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -15,6 +15,8 @@
*/
package android.app;
+import static android.annotation.SystemApi.Client.MODULE_APPS;
+
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
@@ -354,9 +356,13 @@
}
/**
+ * Allows users to block notifications sent through this channel, if this channel belongs to
+ * a package that is signed with the system signature. If the channel does not belong to a
+ * package that is signed with the system signature, this method does nothing.
+ * @param blockableSystem if {@code true}, allows users to block notifications on this channel.
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi(client = MODULE_APPS)
@TestApi
public void setBlockableSystem(boolean blockableSystem) {
mBlockableSystem = blockableSystem;
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 6650cf2..53f4615 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -424,6 +424,7 @@
* @hide
*/
@SystemApi
+ @TestApi
@NonNull
@RequiresPermission(READ_DEVICE_CONFIG)
public static Properties getProperties(@NonNull String namespace, @NonNull String ... names) {
@@ -593,6 +594,7 @@
* @hide
*/
@SystemApi
+ @TestApi
@RequiresPermission(WRITE_DEVICE_CONFIG)
public static boolean setProperties(@NonNull Properties properties) throws BadConfigException {
ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
@@ -817,6 +819,7 @@
* @hide
*/
@SystemApi
+ @TestApi
public static class BadConfigException extends Exception {}
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 96a4a2f..f663320 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2746,6 +2746,8 @@
public ArrayMap<String, String> getStringsForPrefix(ContentResolver cr, String prefix,
List<String> names) {
+ String namespace = prefix.substring(0, prefix.length() - 1);
+ DeviceConfig.enforceReadPermission(ActivityThread.currentApplication(), namespace);
ArrayMap<String, String> keyValues = new ArrayMap<>();
int currentGeneration = -1;
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index c9d3b92..a4fe6aa 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -985,7 +985,7 @@
* TS 24.301 9.9.4.4. Integer.MAX_VALUE if this value is unused.
*/
public void onRegistrationFailed(@NonNull CellIdentity cellIdentity, @NonNull String chosenPlmn,
- @NetworkRegistrationInfo.Domain int domain, int causeCode, int additionalCauseCode) {
+ int domain, int causeCode, int additionalCauseCode) {
// default implementation empty
}
@@ -1277,7 +1277,7 @@
}
public void onRegistrationFailed(@NonNull CellIdentity cellIdentity,
- @NonNull String chosenPlmn, @NetworkRegistrationInfo.Domain int domain,
+ @NonNull String chosenPlmn, int domain,
int causeCode, int additionalCauseCode) {
PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
if (psl == null) return;
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 4dffa62..e25826c 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -701,7 +701,7 @@
*/
public void notifyRegistrationFailed(int slotIndex, int subId,
@NonNull CellIdentity cellIdentity, @NonNull String chosenPlmn,
- @NetworkRegistrationInfo.Domain int domain, int causeCode, int additionalCauseCode) {
+ int domain, int causeCode, int additionalCauseCode) {
try {
sRegistry.notifyRegistrationFailed(slotIndex, subId, cellIdentity,
chosenPlmn, domain, causeCode, additionalCauseCode);
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index f324113..9921bf0 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.DeadSystemException;
@@ -400,7 +401,7 @@
* @param message The message you would like logged.
* @hide
*/
- // @SystemApi(client= SystemApi.Client.MODULE_LIBRARIES) // TODO Uncomment once http://ag/9956147 is in.
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static int logToRadioBuffer(@Level int priority, @Nullable String tag,
@Nullable String message) {
return println_native(LOG_ID_RADIO, priority, tag, message);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 562ed0e..6724e9d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -12602,11 +12602,10 @@
return findViewInsideOutShouldExist(root, mNextFocusForwardId);
case FOCUS_BACKWARD: {
if (mID == View.NO_ID) return null;
- final int id = mID;
return root.findViewByPredicateInsideOut(this, new Predicate<View>() {
@Override
public boolean test(View t) {
- return t.mNextFocusForwardId == id;
+ return t.findViewById(t.mNextFocusForwardId) == View.this;
}
});
}
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 39ea45a..05b573a 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -174,6 +174,8 @@
static constexpr const uint64_t UPPER_HALF_WORD_MASK = 0xFFFF'FFFF'0000'0000;
static constexpr const uint64_t LOWER_HALF_WORD_MASK = 0x0000'0000'FFFF'FFFF;
+static constexpr const char* kCurProfileDirPath = "/data/misc/profiles/cur";
+
/**
* The maximum value that the gUSAPPoolSizeMax variable may take. This value
* is a mirror of ZygoteServer.USAP_POOL_SIZE_MAX_LIMIT
@@ -1382,6 +1384,49 @@
freecon(dataDataContext);
}
+/**
+ * Like isolateAppData(), isolate jit profile directories, so apps don't see what
+ * other apps are installed by reading content inside /data/misc/profiles/cur.
+ *
+ * The implementation is similar to isolateAppData(), it creates a tmpfs
+ * on /data/misc/profiles/cur, and bind mounts related package profiles to it.
+ */
+static void isolateJitProfile(JNIEnv* env, jobjectArray pkg_data_info_list,
+ uid_t uid, const char* process_name, jstring managed_nice_name,
+ fail_fn_t fail_fn) {
+
+ auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
+ const userid_t user_id = multiuser_get_user_id(uid);
+
+ int size = (pkg_data_info_list != nullptr) ? env->GetArrayLength(pkg_data_info_list) : 0;
+ // Size should be a multiple of 3, as it contains list of <package_name, volume_uuid, inode>
+ if ((size % 3) != 0) {
+ fail_fn(CREATE_ERROR("Wrong pkg_inode_list size %d", size));
+ }
+
+ // Mount (namespace) tmpfs on profile directory, so apps no longer access
+ // the original profile directory anymore.
+ MountAppDataTmpFs(kCurProfileDirPath, fail_fn);
+
+ // Create profile directory for this user.
+ std::string actualCurUserProfile = StringPrintf("%s/%d", kCurProfileDirPath, user_id);
+ PrepareDir(actualCurUserProfile.c_str(), DEFAULT_DATA_DIR_PERMISSION, AID_ROOT, AID_ROOT,
+ fail_fn);
+
+ for (int i = 0; i < size; i += 3) {
+ jstring package_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i));
+ std::string packageName = extract_fn(package_str).value();
+
+ std::string actualCurPackageProfile = StringPrintf("%s/%s", actualCurUserProfile.c_str(),
+ packageName.c_str());
+ std::string mirrorCurPackageProfile = StringPrintf("/data_mirror/cur_profiles/%d/%s",
+ user_id, packageName.c_str());
+
+ PrepareDir(actualCurPackageProfile, DEFAULT_DATA_DIR_PERMISSION, uid, uid, fail_fn);
+ BindMount(mirrorCurPackageProfile, actualCurPackageProfile, fail_fn);
+ }
+}
+
// Utility routine to specialize a zygote child process.
static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
jint runtime_flags, jobjectArray rlimits,
@@ -1432,8 +1477,8 @@
// so they can't even traverse CE / DE directories.
if (pkg_data_info_list != nullptr
&& GetBoolProperty(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, true)) {
- isolateAppData(env, pkg_data_info_list, uid, process_name, managed_nice_name,
- fail_fn);
+ isolateAppData(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
+ isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
}
// If this zygote isn't root, it won't be able to create a process group,
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 8f9c041..da8c944 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -165,6 +165,11 @@
(section).args = "security -L"
];
+ optional android.util.PersistedLogProto persisted_logs = 1116 [
+ (section).type = SECTION_COMMAND,
+ (section).args = "/system/bin/sh /system/bin/incident-helper-cmd -l run persisted_logs --limit 10MB"
+ ];
+
// Stack dumps
optional android.os.BackTraceProto native_traces = 1200 [
(section).type = SECTION_TOMBSTONE,
diff --git a/core/proto/android/util/log.proto b/core/proto/android/util/log.proto
index 09870ae..a214a1a 100644
--- a/core/proto/android/util/log.proto
+++ b/core/proto/android/util/log.proto
@@ -94,3 +94,16 @@
repeated BinaryLogEntry binary_logs = 2;
}
+message PersistedLogProto {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ repeated TextLogEntry main_logs = 1;
+ repeated TextLogEntry radio_logs = 2;
+ repeated TextLogEntry events_logs = 3;
+ repeated TextLogEntry system_logs = 4;
+ repeated TextLogEntry crash_logs = 5;
+ repeated TextLogEntry stats_logs = 6;
+ repeated TextLogEntry security_logs = 7;
+ repeated TextLogEntry kernel_logs = 8;
+}
+
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0bc16a3..f8c5166 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -362,7 +362,6 @@
<protected-broadcast android:name="android.net.wifi.WIFI_STATE_CHANGED" />
<protected-broadcast android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
<protected-broadcast android:name="android.net.wifi.WIFI_CREDENTIAL_CHANGED" />
- <protected-broadcast android:name="android.net.wifi.WIFI_SCAN_AVAILABLE" />
<protected-broadcast android:name="android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED" />
<protected-broadcast android:name="android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED" />
<protected-broadcast android:name="android.net.wifi.SCAN_RESULTS" />
@@ -377,6 +376,7 @@
<protected-broadcast android:name="android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION" />
<protected-broadcast android:name="android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW" />
<protected-broadcast android:name="android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION" />
+ <protected-broadcast android:name="android.net.wifi.action.WIFI_SCAN_AVAILABLE" />
<protected-broadcast android:name="android.net.wifi.supplicant.CONNECTION_CHANGE" />
<protected-broadcast android:name="android.net.wifi.supplicant.STATE_CHANGE" />
<protected-broadcast android:name="android.net.wifi.p2p.STATE_CHANGED" />
diff --git a/core/tests/overlaytests/remount/host/AndroidTest.xml b/core/tests/overlaytests/remount/host/AndroidTest.xml
index 11eadf1a..087b731 100644
--- a/core/tests/overlaytests/remount/host/AndroidTest.xml
+++ b/core/tests/overlaytests/remount/host/AndroidTest.xml
@@ -19,9 +19,6 @@
<option name="test-tag" value="OverlayRemountedTest" />
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
- <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="remount" />
- </target_preparer>
<test class="com.android.tradefed.testtype.HostTest">
<option name="jar" value="OverlayRemountedTest.jar" />
diff --git a/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/OverlayHostTest.java b/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/OverlayHostTest.java
deleted file mode 100644
index 84af187..0000000
--- a/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/OverlayHostTest.java
+++ /dev/null
@@ -1,114 +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.overlaytest.remounted;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-
-import org.junit.Rule;
-import org.junit.rules.RuleChain;
-import org.junit.rules.TemporaryFolder;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class OverlayHostTest extends BaseHostJUnit4Test {
- private static final long TIME_OUT_MS = 30000;
- private static final String RES_INSTRUMENTATION_ARG = "res";
- private static final String OVERLAY_INSTRUMENTATION_ARG = "overlays";
- private static final String RESOURCES_TYPE_SUFFIX = "_type";
- private static final String RESOURCES_DATA_SUFFIX = "_data";
-
- public final TemporaryFolder mTemporaryFolder = new TemporaryFolder();
- public final SystemPreparer mPreparer = new SystemPreparer(mTemporaryFolder, this::getDevice);
-
- @Rule
- public final RuleChain ruleChain = RuleChain.outerRule(mTemporaryFolder).around(mPreparer);
- private Map<String, String> mLastResults;
-
- /**
- * Retrieves the values of the resources in the test package. The test package must use the
- * {@link com.android.overlaytest.remounted.target.ResourceRetrievalRunner} instrumentation.
- **/
- void retrieveResource(String testPackageName, List<String> requiredOverlayPaths,
- String... resourceNames) throws DeviceNotAvailableException {
- final HashMap<String, String> args = new HashMap<>();
- if (!requiredOverlayPaths.isEmpty()) {
- // Enclose the require overlay paths in quotes so the arguments will be string arguments
- // rather than file arguments.
- args.put(OVERLAY_INSTRUMENTATION_ARG,
- String.format("\"%s\"", String.join(" ", requiredOverlayPaths)));
- }
-
- if (resourceNames.length == 0) {
- throw new IllegalArgumentException("Must specify at least one resource to retrieve.");
- }
-
- // Pass the names of the resources to retrieve into the test as one string.
- args.put(RES_INSTRUMENTATION_ARG,
- String.format("\"%s\"", String.join(" ", resourceNames)));
-
- runDeviceTests(getDevice(), null, testPackageName, null, null, null, TIME_OUT_MS,
- TIME_OUT_MS, TIME_OUT_MS, false, false, args);
-
- // Retrieve the results of the most recently run test.
- mLastResults = (getLastDeviceRunResults().getRunMetrics() == mLastResults) ? null :
- getLastDeviceRunResults().getRunMetrics();
- }
-
- /** Returns the base resource directories of the specified packages. */
- List<String> getPackagePaths(String... packageNames)
- throws DeviceNotAvailableException {
- final ArrayList<String> paths = new ArrayList<>();
- for (String packageName : packageNames) {
- // Use the package manager shell command to find the path of the package.
- final String result = getDevice().executeShellCommand(
- String.format("pm dump %s | grep \"resourcePath=\"", packageName));
- assertNotNull("Failed to find path for package " + packageName, result);
- int splitIndex = result.indexOf('=');
- assertTrue(splitIndex >= 0);
- paths.add(result.substring(splitIndex + 1).trim());
- }
- return paths;
- }
-
- /** Builds the full name of a resource in the form package:type/entry. */
- String resourceName(String pkg, String type, String entry) {
- return String.format("%s:%s/%s", pkg, type, entry);
- }
-
- /**
- * Asserts that the type and data of a a previously retrieved is the same as expected.
- * @param resourceName the full name of the resource in the form package:type/entry
- * @param type the expected {@link android.util.TypedValue} type of the resource
- * @param data the expected value of the resource when coerced to a string using
- * {@link android.util.TypedValue#coerceToString()}
- **/
- void assertResource(String resourceName, int type, String data) {
- assertNotNull("Failed to get test results", mLastResults);
- assertNotEquals("No resource values were retrieved", mLastResults.size(), 0);
- assertEquals("" + type, mLastResults.get(resourceName + RESOURCES_TYPE_SUFFIX));
- assertEquals("" + data, mLastResults.get(resourceName + RESOURCES_DATA_SUFFIX));
- }
-}
diff --git a/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/OverlaySharedLibraryTest.java b/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/OverlaySharedLibraryTest.java
index 4939e16..06b2ac8 100644
--- a/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/OverlaySharedLibraryTest.java
+++ b/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/OverlaySharedLibraryTest.java
@@ -16,17 +16,21 @@
package com.android.overlaytest.remounted;
+import static org.junit.Assert.assertTrue;
+
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
-import java.util.Collections;
-import java.util.List;
-
@RunWith(DeviceJUnit4ClassRunner.class)
-public class OverlaySharedLibraryTest extends OverlayHostTest {
+public class OverlaySharedLibraryTest extends BaseHostJUnit4Test {
private static final String TARGET_APK = "OverlayRemountedTest_Target.apk";
private static final String TARGET_PACKAGE = "com.android.overlaytest.remounted.target";
private static final String SHARED_LIBRARY_APK =
@@ -38,6 +42,17 @@
private static final String SHARED_LIBRARY_OVERLAY_PACKAGE =
"com.android.overlaytest.remounted.shared_library.overlay";
+ public final TemporaryFolder temporaryFolder = new TemporaryFolder();
+ public final SystemPreparer preparer = new SystemPreparer(temporaryFolder, this::getDevice);
+
+ @Rule
+ public final RuleChain ruleChain = RuleChain.outerRule(temporaryFolder).around(preparer);
+
+ @Before
+ public void startBefore() throws DeviceNotAvailableException {
+ getDevice().waitForDeviceAvailable();
+ }
+
@Test
public void testSharedLibrary() throws Exception {
final String targetResource = resourceName(TARGET_PACKAGE, "bool",
@@ -45,23 +60,20 @@
final String libraryResource = resourceName(SHARED_LIBRARY_PACKAGE, "bool",
"shared_library_overlaid");
- mPreparer.pushResourceFile(SHARED_LIBRARY_APK, "/product/app/SharedLibrary.apk")
+ preparer.pushResourceFile(SHARED_LIBRARY_APK, "/product/app/SharedLibrary.apk")
.installResourceApk(SHARED_LIBRARY_OVERLAY_APK, SHARED_LIBRARY_OVERLAY_PACKAGE)
.reboot()
.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, false)
.installResourceApk(TARGET_APK, TARGET_PACKAGE);
// The shared library resource is not currently overlaid.
- retrieveResource(Collections.emptyList(), targetResource, libraryResource);
- assertResource(targetResource, 0x12 /* TYPE_INT_BOOLEAN */, "false");
- assertResource(libraryResource, 0x12 /* TYPE_INT_BOOLEAN */, "false");
+ assertResource(targetResource, "false");
+ assertResource(libraryResource, "false");
// Overlay the shared library resource.
- mPreparer.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, true);
- retrieveResource(getPackagePaths(SHARED_LIBRARY_OVERLAY_PACKAGE), targetResource,
- libraryResource);
- assertResource(targetResource, 0x12 /* TYPE_INT_BOOLEAN */, "true");
- assertResource(libraryResource, 0x12 /* TYPE_INT_BOOLEAN */, "true");
+ preparer.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, true);
+ assertResource(targetResource, "true");
+ assertResource(libraryResource, "true");
}
@Test
@@ -71,20 +83,27 @@
final String libraryResource = resourceName(SHARED_LIBRARY_PACKAGE, "bool",
"shared_library_overlaid");
- mPreparer.pushResourceFile(SHARED_LIBRARY_APK, "/product/app/SharedLibrary.apk")
+ preparer.pushResourceFile(SHARED_LIBRARY_APK, "/product/app/SharedLibrary.apk")
.installResourceApk(SHARED_LIBRARY_OVERLAY_APK, SHARED_LIBRARY_OVERLAY_PACKAGE)
.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, true)
.reboot()
.installResourceApk(TARGET_APK, TARGET_PACKAGE);
- retrieveResource(getPackagePaths(SHARED_LIBRARY_OVERLAY_PACKAGE), targetResource,
- libraryResource);
- assertResource(targetResource, 0x12 /* TYPE_INT_BOOLEAN */, "true");
- assertResource(libraryResource, 0x12 /* TYPE_INT_BOOLEAN */, "true");
+ assertResource(targetResource, "true");
+ assertResource(libraryResource, "true");
}
- private void retrieveResource(List<String> requiredOverlayPaths, String... resourceNames)
+ /** Builds the full name of a resource in the form package:type/entry. */
+ String resourceName(String pkg, String type, String entry) {
+ return String.format("%s:%s/%s", pkg, type, entry);
+ }
+
+ void assertResource(String resourceName, String expectedValue)
throws DeviceNotAvailableException {
- retrieveResource(TARGET_PACKAGE, requiredOverlayPaths, resourceNames);
+ final String result = getDevice().executeShellCommand(
+ String.format("cmd overlay lookup %s %s", TARGET_PACKAGE, resourceName));
+ assertTrue(String.format("expected: <[%s]> in: <[%s]>", expectedValue, result),
+ result.equals(expectedValue + "\n") ||
+ result.endsWith("-> " + expectedValue + "\n"));
}
}
diff --git a/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/SystemPreparer.java b/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/SystemPreparer.java
index 7028f2f..8696091 100644
--- a/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/SystemPreparer.java
+++ b/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/SystemPreparer.java
@@ -38,8 +38,7 @@
import java.util.concurrent.TimeoutException;
class SystemPreparer extends ExternalResource {
- private static final long REBOOT_SLEEP_MS = 30000;
- private static final long OVERLAY_ENABLE_TIMEOUT_MS = 20000;
+ private static final long OVERLAY_ENABLE_TIMEOUT_MS = 30000;
// The paths of the files pushed onto the device through this rule.
private ArrayList<String> mPushedFiles = new ArrayList<>();
@@ -59,6 +58,7 @@
SystemPreparer pushResourceFile(String resourcePath,
String outputPath) throws DeviceNotAvailableException, IOException {
final ITestDevice device = mDeviceProvider.getDevice();
+ device.executeAdbCommand("remount");
assertTrue(device.pushFile(copyResourceToTemp(resourcePath), outputPath));
mPushedFiles.add(outputPath);
return this;
@@ -77,7 +77,7 @@
/** Sets the enable state of an overlay pacakage. */
SystemPreparer setOverlayEnabled(String packageName, boolean enabled)
- throws ExecutionException, TimeoutException {
+ throws ExecutionException, DeviceNotAvailableException {
final ITestDevice device = mDeviceProvider.getDevice();
// Wait for the overlay to change its enabled state.
@@ -86,8 +86,10 @@
device.executeShellCommand(String.format("cmd overlay %s %s",
enabled ? "enable" : "disable", packageName));
- final String pattern = (enabled ? "[x]" : "[ ]") + " " + packageName;
- if (device.executeShellCommand("cmd overlay list").contains(pattern)) {
+ final String result = device.executeShellCommand("cmd overlay dump " + packageName);
+ final int startIndex = result.indexOf("mIsEnabled");
+ final int endIndex = result.indexOf('\n', startIndex);
+ if (result.substring(startIndex, endIndex).contains((enabled) ? "true" : "false")) {
return true;
}
}
@@ -98,6 +100,8 @@
try {
enabledListener.get(OVERLAY_ENABLE_TIMEOUT_MS, MILLISECONDS);
} catch (InterruptedException ignored) {
+ } catch (TimeoutException e) {
+ throw new IllegalStateException(device.executeShellCommand("cmd overlay list"));
}
return this;
@@ -106,14 +110,7 @@
/** Restarts the device and waits until after boot is completed. */
SystemPreparer reboot() throws DeviceNotAvailableException {
final ITestDevice device = mDeviceProvider.getDevice();
- device.executeShellCommand("stop");
- device.executeShellCommand("start");
- try {
- // Sleep until the device is ready for test execution.
- Thread.sleep(REBOOT_SLEEP_MS);
- } catch (InterruptedException ignored) {
- }
-
+ device.reboot();
return this;
}
@@ -141,12 +138,14 @@
protected void after() {
final ITestDevice device = mDeviceProvider.getDevice();
try {
+ device.executeAdbCommand("remount");
for (final String file : mPushedFiles) {
device.deleteFile(file);
}
for (final String packageName : mInstalledPackages) {
device.uninstallPackage(packageName);
}
+ device.reboot();
} catch (DeviceNotAvailableException e) {
Assert.fail(e.toString());
}
diff --git a/core/tests/overlaytests/remount/target/AndroidManifest.xml b/core/tests/overlaytests/remount/target/AndroidManifest.xml
index 32fec43..dc07dca 100644
--- a/core/tests/overlaytests/remount/target/AndroidManifest.xml
+++ b/core/tests/overlaytests/remount/target/AndroidManifest.xml
@@ -23,8 +23,4 @@
<uses-library android:name="com.android.overlaytest.remounted.shared_library"
android:required="true" />
</application>
-
- <instrumentation android:name="com.android.overlaytest.remounted.target.ResourceRetrievalRunner"
- android:targetPackage="com.android.overlaytest.remounted.target"
- android:label="Remounted system RRO tests" />
</manifest>
diff --git a/core/tests/overlaytests/remount/target/src/com/android/overlaytest/remounted/target/ResourceRetrievalRunner.java b/core/tests/overlaytests/remount/target/src/com/android/overlaytest/remounted/target/ResourceRetrievalRunner.java
deleted file mode 100644
index 2e4c211..0000000
--- a/core/tests/overlaytests/remount/target/src/com/android/overlaytest/remounted/target/ResourceRetrievalRunner.java
+++ /dev/null
@@ -1,140 +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.overlaytest.remounted.target;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.util.Log;
-import android.util.TypedValue;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.concurrent.Executor;
-import java.util.concurrent.FutureTask;
-import java.util.concurrent.TimeUnit;
-
-/**
- * An {@link Instrumentation} that retrieves the value of specified resources within the
- * application.
- **/
-public class ResourceRetrievalRunner extends Instrumentation {
- private static final String TAG = ResourceRetrievalRunner.class.getSimpleName();
-
- // A list of whitespace separated resource names of which to retrieve the resource values.
- private static final String RESOURCE_LIST_TAG = "res";
-
- // A list of whitespace separated overlay package paths that must be present before retrieving
- // resource values.
- private static final String REQUIRED_OVERLAYS_LIST_TAG = "overlays";
-
- // The suffixes of the keys returned from the instrumentation. To retrieve the type of a
- // resource looked up with the instrumentation, append the {@link #RESOURCES_TYPE_SUFFIX} suffix
- // to the end of the name of the resource. For the value of a resource, use
- // {@link #RESOURCES_DATA_SUFFIX} instead.
- private static final String RESOURCES_TYPE_SUFFIX = "_type";
- private static final String RESOURCES_DATA_SUFFIX = "_data";
-
- // The amount of time in seconds to wait for the overlays to be present in the AssetManager.
- private static final int OVERLAY_PATH_TIMEOUT = 60;
-
- private final ArrayList<String> mResourceNames = new ArrayList<>();
- private final ArrayList<String> mOverlayPaths = new ArrayList<>();
- private final Bundle mResult = new Bundle();
-
- /**
- * Receives the instrumentation arguments and runs the resource retrieval.
- * The entry with key {@link #RESOURCE_LIST_TAG} in the {@link Bundle} arguments is a
- * whitespace separated string of resource names of which to retrieve the resource values.
- * The entry with key {@link #REQUIRED_OVERLAYS_LIST_TAG} in the {@link Bundle} arguments is a
- * whitespace separated string of overlay package paths prefixes that must be present before
- * retrieving the resource values.
- */
- @Override
- public void onCreate(Bundle arguments) {
- super.onCreate(arguments);
- mResourceNames.addAll(Arrays.asList(arguments.getString(RESOURCE_LIST_TAG).split(" ")));
- if (arguments.containsKey(REQUIRED_OVERLAYS_LIST_TAG)) {
- mOverlayPaths.addAll(Arrays.asList(
- arguments.getString(REQUIRED_OVERLAYS_LIST_TAG).split(" ")));
- }
- start();
- }
-
- @Override
- public void onStart() {
- final Resources res = getContext().getResources();
- res.getAssets().setResourceResolutionLoggingEnabled(true);
-
- if (!mOverlayPaths.isEmpty()) {
- Log.d(TAG, String.format("Waiting for overlay paths [%s]",
- String.join(",", mOverlayPaths)));
-
- // Wait for all required overlays to be present in the AssetManager.
- final FutureTask<Boolean> overlayListener = new FutureTask<>(() -> {
- while (!mOverlayPaths.isEmpty()) {
- final String[] apkPaths = res.getAssets().getApkPaths();
- for (String path : apkPaths) {
- for (String overlayPath : mOverlayPaths) {
- if (path.startsWith(overlayPath)) {
- mOverlayPaths.remove(overlayPath);
- break;
- }
- }
- }
- }
- return true;
- });
-
- try {
- final Executor executor = (t) -> new Thread(t).start();
- executor.execute(overlayListener);
- overlayListener.get(OVERLAY_PATH_TIMEOUT, TimeUnit.SECONDS);
- } catch (Exception e) {
- Log.e(TAG, String.format("Failed to wait for required overlays [%s]",
- String.join(",", mOverlayPaths)), e);
- finish(Activity.RESULT_CANCELED, mResult);
- }
- }
-
- // Retrieve the values for each resource passed in.
- final TypedValue typedValue = new TypedValue();
- for (final String resourceName : mResourceNames) {
- try {
- final int resId = res.getIdentifier(resourceName, null, null);
- res.getValue(resId, typedValue, true);
- Log.d(TAG, String.format("Resolution for 0x%s: %s", Integer.toHexString(resId),
- res.getAssets().getLastResourceResolution()));
- } catch (Resources.NotFoundException e) {
- Log.e(TAG, "Failed to retrieve value for resource " + resourceName, e);
- finish(Activity.RESULT_CANCELED, mResult);
- }
-
- putValue(resourceName, typedValue);
- }
-
- finish(Activity.RESULT_OK, mResult);
- }
-
- private void putValue(String resourceName, TypedValue value) {
- mResult.putInt(resourceName + RESOURCES_TYPE_SUFFIX, value.type);
- final CharSequence textValue = value.coerceToString();
- mResult.putString(resourceName + RESOURCES_DATA_SUFFIX,
- textValue == null ? "null" : textValue.toString());
- }
-}
diff --git a/media/java/android/media/IMediaRoute2Provider.aidl b/media/java/android/media/IMediaRoute2Provider.aidl
index 5dd0b1c..aa38e51 100644
--- a/media/java/android/media/IMediaRoute2Provider.aidl
+++ b/media/java/android/media/IMediaRoute2Provider.aidl
@@ -24,8 +24,7 @@
*/
oneway interface IMediaRoute2Provider {
void setClient(IMediaRoute2ProviderClient client);
- void requestCreateSession(String packageName, String routeId,
- String routeFeature, long requestId);
+ void requestCreateSession(String packageName, String routeId, long requestId);
void releaseSession(String sessionId);
void selectRoute(String sessionId, String routeId);
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index 3cdaa07..2d3e185 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -47,12 +47,12 @@
List<MediaRoute2Info> getSystemRoutes();
void registerClient2(IMediaRouter2Client client, String packageName);
void unregisterClient2(IMediaRouter2Client client);
- void sendControlRequest(IMediaRouter2Client client, in MediaRoute2Info route, in Intent request);
+ void sendControlRequest(IMediaRouter2Client client, in MediaRoute2Info route,
+ in Intent request);
void requestSetVolume2(IMediaRouter2Client client, in MediaRoute2Info route, int volume);
void requestUpdateVolume2(IMediaRouter2Client client, in MediaRoute2Info route, int direction);
- void requestCreateSession(IMediaRouter2Client client, in MediaRoute2Info route,
- String routeFeature, int requestId);
+ void requestCreateSession(IMediaRouter2Client client, in MediaRoute2Info route, int requestId);
void setDiscoveryRequest2(IMediaRouter2Client client, in RouteDiscoveryPreference preference);
void selectRoute(IMediaRouter2Client client, String sessionId, in MediaRoute2Info route);
void deselectRoute(IMediaRouter2Client client, String sessionId, in MediaRoute2Info route);
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 6d9aea5..5a3de6d 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -161,8 +161,8 @@
* @param sessionInfo information of the new session.
* The {@link RoutingSessionInfo#getId() id} of the session must be unique.
* @param requestId id of the previous request to create this session provided in
- * {@link #onCreateSession(String, String, String, long)}
- * @see #onCreateSession(String, String, String, long)
+ * {@link #onCreateSession(String, String, long)}
+ * @see #onCreateSession(String, String, long)
* @hide
*/
public final void notifySessionCreated(@NonNull RoutingSessionInfo sessionInfo,
@@ -196,8 +196,8 @@
* Notifies clients of that the session could not be created.
*
* @param requestId id of the previous request to create the session provided in
- * {@link #onCreateSession(String, String, String, long)}.
- * @see #onCreateSession(String, String, String, long)
+ * {@link #onCreateSession(String, String, long)}.
+ * @see #onCreateSession(String, String, long)
* @hide
*/
public final void notifySessionCreationFailed(long requestId) {
@@ -289,16 +289,15 @@
*
* @param packageName the package name of the application that selected the route
* @param routeId the id of the route initially being connected
- * @param routeFeature the route feature of the new session
* @param requestId the id of this session creation request
*
- * @see RoutingSessionInfo.Builder#Builder(String, String, String)
+ * @see RoutingSessionInfo.Builder#Builder(String, String)
* @see RoutingSessionInfo.Builder#addSelectedRoute(String)
* @see RoutingSessionInfo.Builder#setControlHints(Bundle)
* @hide
*/
public abstract void onCreateSession(@NonNull String packageName, @NonNull String routeId,
- @NonNull String routeFeature, long requestId);
+ long requestId);
/**
* Called when the session should be released. A client of the session or system can request
@@ -433,14 +432,12 @@
}
@Override
- public void requestCreateSession(String packageName, String routeId,
- String routeFeature, long requestId) {
+ public void requestCreateSession(String packageName, String routeId, long requestId) {
if (!checkCallerisSystem()) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onCreateSession,
- MediaRoute2ProviderService.this, packageName, routeId, routeFeature,
- requestId));
+ MediaRoute2ProviderService.this, packageName, routeId, requestId));
}
@Override
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index bc4da10..971b08d 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -284,26 +284,20 @@
* Requests the media route provider service to create a session with the given route.
*
* @param route the route you want to create a session with.
- * @param routeFeature the route feature of the session. Should not be empty.
*
* @see SessionCallback#onSessionCreated
* @see SessionCallback#onSessionCreationFailed
* @hide
*/
@NonNull
- public void requestCreateSession(@NonNull MediaRoute2Info route,
- @NonNull String routeFeature) {
+ public void requestCreateSession(@NonNull MediaRoute2Info route) {
Objects.requireNonNull(route, "route must not be null");
- if (TextUtils.isEmpty(routeFeature)) {
- throw new IllegalArgumentException("routeFeature must not be empty");
- }
// TODO: Check the given route exists
- // TODO: Check the route supports the given routeFeature
final int requestId;
requestId = mSessionCreationRequestCnt.getAndIncrement();
- SessionCreationRequest request = new SessionCreationRequest(requestId, route, routeFeature);
+ SessionCreationRequest request = new SessionCreationRequest(requestId, route);
mSessionCreationRequests.add(request);
Client2 client;
@@ -312,7 +306,7 @@
}
if (client != null) {
try {
- mMediaRouterService.requestCreateSession(client, route, routeFeature, requestId);
+ mMediaRouterService.requestCreateSession(client, route, requestId);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to request to create session.", ex);
mHandler.sendMessage(obtainMessage(MediaRouter2::createControllerOnHandler,
@@ -468,27 +462,18 @@
mSessionCreationRequests.remove(matchingRequest);
MediaRoute2Info requestedRoute = matchingRequest.mRoute;
- String requestedRouteFeature = matchingRequest.mRouteFeature;
if (sessionInfo == null) {
// TODO: We may need to distinguish between failure and rejection.
// One way can be introducing 'reason'.
- notifySessionCreationFailed(requestedRoute, requestedRouteFeature);
- return;
- } else if (!TextUtils.equals(requestedRouteFeature,
- sessionInfo.getRouteFeature())) {
- Log.w(TAG, "The session has different route feature from what we requested. "
- + "(requested=" + requestedRouteFeature
- + ", actual=" + sessionInfo.getRouteFeature()
- + ")");
- notifySessionCreationFailed(requestedRoute, requestedRouteFeature);
+ notifySessionCreationFailed(requestedRoute);
return;
} else if (!sessionInfo.getSelectedRoutes().contains(requestedRoute.getId())) {
Log.w(TAG, "The session does not contain the requested route. "
+ "(requestedRouteId=" + requestedRoute.getId()
+ ", actualRoutes=" + sessionInfo.getSelectedRoutes()
+ ")");
- notifySessionCreationFailed(requestedRoute, requestedRouteFeature);
+ notifySessionCreationFailed(requestedRoute);
return;
} else if (!TextUtils.equals(requestedRoute.getProviderId(),
sessionInfo.getProviderId())) {
@@ -496,7 +481,7 @@
+ "(requested route's providerId=" + requestedRoute.getProviderId()
+ ", actual providerId=" + sessionInfo.getProviderId()
+ ")");
- notifySessionCreationFailed(requestedRoute, requestedRouteFeature);
+ notifySessionCreationFailed(requestedRoute);
return;
}
}
@@ -617,10 +602,10 @@
}
}
- private void notifySessionCreationFailed(MediaRoute2Info route, String routeFeature) {
+ private void notifySessionCreationFailed(MediaRoute2Info route) {
for (SessionCallbackRecord record: mSessionCallbackRecords) {
record.mExecutor.execute(
- () -> record.mSessionCallback.onSessionCreationFailed(route, routeFeature));
+ () -> record.mSessionCallback.onSessionCreationFailed(route));
}
}
@@ -688,10 +673,8 @@
* Called when the session creation request failed.
*
* @param requestedRoute the route info which was used for the request
- * @param requestedRouteFeature the route feature which was used for the request
*/
- public void onSessionCreationFailed(@NonNull MediaRoute2Info requestedRoute,
- @NonNull String requestedRouteFeature) {}
+ public void onSessionCreationFailed(@NonNull MediaRoute2Info requestedRoute) {}
/**
* Called when the session info has changed.
@@ -753,16 +736,6 @@
}
/**
- * @return the feature which is used by the session mainly.
- */
- @NonNull
- public String getRouteFeature() {
- synchronized (mControllerLock) {
- return mSessionInfo.getRouteFeature();
- }
- }
-
- /**
* @return the control hints used to control routing session if available.
*/
@Nullable
@@ -1012,7 +985,6 @@
StringBuilder result = new StringBuilder()
.append("RoutingController{ ")
.append("sessionId=").append(getSessionId())
- .append(", routeFeature=").append(getRouteFeature())
.append(", selectedRoutes={")
.append(selectedRoutes)
.append("}")
@@ -1122,13 +1094,10 @@
final class SessionCreationRequest {
public final MediaRoute2Info mRoute;
- public final String mRouteFeature;
public final int mRequestId;
- SessionCreationRequest(int requestId, @NonNull MediaRoute2Info route,
- @NonNull String routeFeature) {
+ SessionCreationRequest(int requestId, @NonNull MediaRoute2Info route) {
mRoute = route;
- mRouteFeature = routeFeature;
mRequestId = requestId;
}
}
diff --git a/media/java/android/media/RoutingSessionInfo.java b/media/java/android/media/RoutingSessionInfo.java
index 96acf6c..228adde 100644
--- a/media/java/android/media/RoutingSessionInfo.java
+++ b/media/java/android/media/RoutingSessionInfo.java
@@ -51,7 +51,6 @@
final String mId;
final String mClientPackageName;
- final String mRouteFeature;
@Nullable
final String mProviderId;
final List<String> mSelectedRoutes;
@@ -66,7 +65,6 @@
mId = builder.mId;
mClientPackageName = builder.mClientPackageName;
- mRouteFeature = builder.mRouteFeature;
mProviderId = builder.mProviderId;
// TODO: Needs to check that the routes already have unique IDs.
@@ -87,7 +85,6 @@
mId = ensureString(src.readString());
mClientPackageName = ensureString(src.readString());
- mRouteFeature = ensureString(src.readString());
mProviderId = src.readString();
mSelectedRoutes = ensureList(src.createStringArrayList());
@@ -119,7 +116,7 @@
* In order to ensure uniqueness in {@link MediaRouter2} side, the value of this method
* can be different from what was set in {@link MediaRoute2ProviderService}.
*
- * @see Builder#Builder(String, String, String)
+ * @see Builder#Builder(String, String)
*/
@NonNull
public String getId() {
@@ -131,7 +128,7 @@
}
/**
- * Gets the original id set by {@link Builder#Builder(String, String, String)}.
+ * Gets the original id set by {@link Builder#Builder(String, String)}.
* @hide
*/
@NonNull
@@ -148,15 +145,6 @@
}
/**
- * Gets the route feature of the session.
- * Routes that don't have the feature can't be selected into the session.
- */
- @NonNull
- public String getRouteFeature() {
- return mRouteFeature;
- }
-
- /**
* Gets the provider id of the session.
* @hide
*/
@@ -214,7 +202,6 @@
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(mId);
dest.writeString(mClientPackageName);
- dest.writeString(mRouteFeature);
dest.writeString(mProviderId);
dest.writeStringList(mSelectedRoutes);
dest.writeStringList(mSelectableRoutes);
@@ -235,7 +222,6 @@
RoutingSessionInfo other = (RoutingSessionInfo) obj;
return Objects.equals(mId, other.mId)
&& Objects.equals(mClientPackageName, other.mClientPackageName)
- && Objects.equals(mRouteFeature, other.mRouteFeature)
&& Objects.equals(mProviderId, other.mProviderId)
&& Objects.equals(mSelectedRoutes, other.mSelectedRoutes)
&& Objects.equals(mSelectableRoutes, other.mSelectableRoutes)
@@ -245,7 +231,7 @@
@Override
public int hashCode() {
- return Objects.hash(mId, mClientPackageName, mRouteFeature, mProviderId,
+ return Objects.hash(mId, mClientPackageName, mProviderId,
mSelectedRoutes, mSelectableRoutes, mDeselectableRoutes, mTransferrableRoutes);
}
@@ -254,7 +240,6 @@
StringBuilder result = new StringBuilder()
.append("RoutingSessionInfo{ ")
.append("sessionId=").append(mId)
- .append(", routeFeature=").append(mRouteFeature)
.append(", selectedRoutes={")
.append(String.join(",", mSelectedRoutes))
.append("}")
@@ -295,7 +280,6 @@
public static final class Builder {
final String mId;
final String mClientPackageName;
- final String mRouteFeature;
String mProviderId;
final List<String> mSelectedRoutes;
final List<String> mSelectableRoutes;
@@ -314,22 +298,16 @@
* @param id ID of the session. Must not be empty.
* @param clientPackageName package name of the client app which uses this session.
* If is is unknown, then just use an empty string.
- * @param routeFeature the route feature of session. Must not be empty.
* @see MediaRoute2Info#getId()
*/
- public Builder(@NonNull String id, @NonNull String clientPackageName,
- @NonNull String routeFeature) {
+ public Builder(@NonNull String id, @NonNull String clientPackageName) {
if (TextUtils.isEmpty(id)) {
throw new IllegalArgumentException("id must not be empty");
}
Objects.requireNonNull(clientPackageName, "clientPackageName must not be null");
- if (TextUtils.isEmpty(routeFeature)) {
- throw new IllegalArgumentException("routeFeature must not be empty");
- }
mId = id;
mClientPackageName = clientPackageName;
- mRouteFeature = routeFeature;
mSelectedRoutes = new ArrayList<>();
mSelectableRoutes = new ArrayList<>();
mDeselectableRoutes = new ArrayList<>();
@@ -347,7 +325,6 @@
mId = sessionInfo.mId;
mClientPackageName = sessionInfo.mClientPackageName;
- mRouteFeature = sessionInfo.mRouteFeature;
mProviderId = sessionInfo.mProviderId;
mSelectedRoutes = new ArrayList<>(sessionInfo.mSelectedRoutes);
diff --git a/media/java/android/media/tv/tuner/Descrambler.java b/media/java/android/media/tv/tuner/Descrambler.java
index 0143582..23016e9 100644
--- a/media/java/android/media/tv/tuner/Descrambler.java
+++ b/media/java/android/media/tv/tuner/Descrambler.java
@@ -34,7 +34,7 @@
*/
public class Descrambler implements AutoCloseable {
/** @hide */
- @IntDef(prefix = "PID_TYPE_", value = {PID_TYPE_T, PID_TYPE_MMPT})
+ @IntDef(prefix = "PID_TYPE_", value = {PID_TYPE_T, PID_TYPE_MMTP})
@Retention(RetentionPolicy.SOURCE)
public @interface PidType {}
@@ -45,7 +45,7 @@
/**
* Packet ID is used to specify packets in MMTP.
*/
- public static final int PID_TYPE_MMPT = 2;
+ public static final int PID_TYPE_MMTP = 2;
private long mNativeContext;
diff --git a/media/java/android/media/tv/tuner/Lnb.java b/media/java/android/media/tv/tuner/Lnb.java
index 8e579bf..a9a15d9 100644
--- a/media/java/android/media/tv/tuner/Lnb.java
+++ b/media/java/android/media/tv/tuner/Lnb.java
@@ -40,7 +40,8 @@
@SystemApi
public class Lnb implements AutoCloseable {
/** @hide */
- @IntDef({VOLTAGE_NONE, VOLTAGE_5V, VOLTAGE_11V, VOLTAGE_12V, VOLTAGE_13V, VOLTAGE_14V,
+ @IntDef(prefix = "VOLTAGE_",
+ value = {VOLTAGE_NONE, VOLTAGE_5V, VOLTAGE_11V, VOLTAGE_12V, VOLTAGE_13V, VOLTAGE_14V,
VOLTAGE_15V, VOLTAGE_18V, VOLTAGE_19V})
@Retention(RetentionPolicy.SOURCE)
public @interface Voltage {}
@@ -83,7 +84,8 @@
public static final int VOLTAGE_19V = Constants.LnbVoltage.VOLTAGE_19V;
/** @hide */
- @IntDef({TONE_NONE, TONE_CONTINUOUS})
+ @IntDef(prefix = "TONE_",
+ value = {TONE_NONE, TONE_CONTINUOUS})
@Retention(RetentionPolicy.SOURCE)
public @interface Tone {}
@@ -97,7 +99,8 @@
public static final int TONE_CONTINUOUS = Constants.LnbTone.CONTINUOUS;
/** @hide */
- @IntDef({POSITION_UNDEFINED, POSITION_A, POSITION_B})
+ @IntDef(prefix = "POSITION_",
+ value = {POSITION_UNDEFINED, POSITION_A, POSITION_B})
@Retention(RetentionPolicy.SOURCE)
public @interface Position {}
@@ -114,6 +117,37 @@
*/
public static final int POSITION_B = Constants.LnbPosition.POSITION_B;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "EVENT_TYPE_",
+ value = {EVENT_TYPE_DISEQC_RX_OVERFLOW, EVENT_TYPE_DISEQC_RX_TIMEOUT,
+ EVENT_TYPE_DISEQC_RX_PARITY_ERROR, EVENT_TYPE_LNB_OVERLOAD})
+ public @interface EventType {}
+
+ /**
+ * Outgoing Diseqc message overflow.
+ * @hide
+ */
+ public static final int EVENT_TYPE_DISEQC_RX_OVERFLOW =
+ Constants.LnbEventType.DISEQC_RX_OVERFLOW;
+ /**
+ * Outgoing Diseqc message isn't delivered on time.
+ * @hide
+ */
+ public static final int EVENT_TYPE_DISEQC_RX_TIMEOUT =
+ Constants.LnbEventType.DISEQC_RX_TIMEOUT;
+ /**
+ * Incoming Diseqc message has parity error.
+ * @hide
+ */
+ public static final int EVENT_TYPE_DISEQC_RX_PARITY_ERROR =
+ Constants.LnbEventType.DISEQC_RX_PARITY_ERROR;
+ /**
+ * LNB is overload.
+ * @hide
+ */
+ public static final int EVENT_TYPE_LNB_OVERLOAD = Constants.LnbEventType.LNB_OVERLOAD;
+
int mId;
LnbCallback mCallback;
Context mContext;
diff --git a/media/java/android/media/tv/tuner/LnbCallback.java b/media/java/android/media/tv/tuner/LnbCallback.java
index 99bbf86..5155f60 100644
--- a/media/java/android/media/tv/tuner/LnbCallback.java
+++ b/media/java/android/media/tv/tuner/LnbCallback.java
@@ -17,6 +17,8 @@
package android.media.tv.tuner;
+import android.media.tv.tuner.Lnb.EventType;
+
/**
* Callback interface for receiving information from LNBs.
*
@@ -26,7 +28,7 @@
/**
* Invoked when there is a LNB event.
*/
- void onEvent(int lnbEventType);
+ void onEvent(@EventType int lnbEventType);
/**
* Invoked when there is a new DiSEqC message.
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 18969ae..3a8ae92 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -24,13 +24,13 @@
import android.annotation.SystemApi;
import android.content.Context;
import android.media.tv.tuner.TunerConstants.FilterStatus;
-import android.media.tv.tuner.TunerConstants.FilterSubtype;
import android.media.tv.tuner.TunerConstants.FrontendScanType;
import android.media.tv.tuner.TunerConstants.Result;
import android.media.tv.tuner.dvr.Dvr;
import android.media.tv.tuner.dvr.DvrCallback;
import android.media.tv.tuner.dvr.DvrSettings;
-import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
+import android.media.tv.tuner.filter.Filter.Subtype;
+import android.media.tv.tuner.filter.Filter.Type;
import android.media.tv.tuner.filter.FilterEvent;
import android.media.tv.tuner.filter.TimeFilter;
import android.media.tv.tuner.frontend.FrontendCallback;
@@ -102,7 +102,8 @@
* TODO: replace the other constructor
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
- public Tuner(@NonNull Context context, @NonNull String tvInputSessionId, int useCase) {
+ public Tuner(@NonNull Context context, @NonNull String tvInputSessionId, int useCase,
+ @Nullable OnResourceLostListener listener) {
mContext = context;
}
@@ -113,7 +114,8 @@
*
* @hide
*/
- public void shareFrontend(@NonNull Tuner tuner) { }
+ public void shareFrontendFromTuner(@NonNull Tuner tuner) {
+ }
private long mNativeContext; // used by native jMediaTuner
@@ -513,18 +515,18 @@
* @param subType the subtype of the filter.
* @param bufferSize the buffer size of the filter to be opened in bytes. The buffer holds the
* data output from the filter.
- * @param cb the callback to receive notifications from filter.
* @param executor the executor on which callback will be invoked. The default event handler
* executor is used if it's {@code null}.
+ * @param cb the callback to receive notifications from filter.
* @return the opened filter. {@code null} if the operation failed.
*
* @hide
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@Nullable
- public Filter openFilter(@FilterType int mainType, @FilterSubtype int subType,
- @BytesLong long bufferSize, @Nullable FilterCallback cb,
- @CallbackExecutor @Nullable Executor executor) {
+ public Filter openFilter(@Type int mainType, @Subtype int subType,
+ @BytesLong long bufferSize, @CallbackExecutor @Nullable Executor executor,
+ @Nullable FilterCallback cb) {
TunerUtils.checkTunerPermission(mContext);
Filter filter = nativeOpenFilter(
mainType, TunerUtils.getFilterSubtype(mainType, subType), bufferSize);
@@ -540,16 +542,34 @@
/**
* Opens an LNB (low-noise block downconverter) object.
*
- * @param cb the callback to receive notifications from LNB.
* @param executor the executor on which callback will be invoked. The default event handler
* executor is used if it's {@code null}.
+ * @param cb the callback to receive notifications from LNB.
* @return the opened LNB object. {@code null} if the operation failed.
*
* @hide
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@Nullable
- public Lnb openLnb(LnbCallback cb, @CallbackExecutor @Nullable Executor executor) {
+ public Lnb openLnb(@CallbackExecutor @Nullable Executor executor, LnbCallback cb) {
+ return openLnbByName(null, executor, cb);
+ }
+
+ /**
+ * Opens an LNB (low-noise block downconverter) object.
+ *
+ * @param name the LNB name.
+ * @param executor the executor on which callback will be invoked. The default event handler
+ * executor is used if it's {@code null}.
+ * @param cb the callback to receive notifications from LNB.
+ * @return the opened LNB object. {@code null} if the operation failed.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
+ @Nullable
+ public Lnb openLnbByName(@Nullable String name, @CallbackExecutor @Nullable Executor executor,
+ LnbCallback cb) {
TunerUtils.checkTunerPermission(mContext);
// TODO: use resource manager to get LNB ID.
return new Lnb(0);
@@ -608,17 +628,17 @@
* @param type the DVR type to be opened.
* @param bufferSize the buffer size of the output in bytes. It's used to hold output data of
* the attached filters.
- * @param cb the callback to receive notifications from DVR.
* @param executor the executor on which callback will be invoked. The default event handler
* executor is used if it's {@code null}.
+ * @param cb the callback to receive notifications from DVR.
* @return the opened DVR object. {@code null} if the operation failed.
*
* @hide
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@Nullable
- public Dvr openDvr(@DvrSettings.Type int type, @BytesLong long bufferSize, DvrCallback cb,
- @CallbackExecutor @Nullable Executor executor) {
+ public Dvr openDvr(@DvrSettings.Type int type, @BytesLong long bufferSize,
+ @CallbackExecutor @Nullable Executor executor, DvrCallback cb) {
TunerUtils.checkTunerPermission(mContext);
Dvr dvr = nativeOpenDvr(type, bufferSize);
return dvr;
diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java
index fa8f550..fe4c954 100644
--- a/media/java/android/media/tv/tuner/TunerConstants.java
+++ b/media/java/android/media/tv/tuner/TunerConstants.java
@@ -36,69 +36,42 @@
*/
@SystemApi
public final class TunerConstants {
- /** @hide */
+ /**
+ * Invalid TS packet ID.
+ * @hide
+ */
public static final int INVALID_TS_PID = Constants.Constant.INVALID_TS_PID;
- /** @hide */
+ /**
+ * Invalid stream ID.
+ * @hide
+ */
public static final int INVALID_STREAM_ID = Constants.Constant.INVALID_STREAM_ID;
/** @hide */
- @IntDef({FRONTEND_EVENT_TYPE_LOCKED, FRONTEND_EVENT_TYPE_NO_SIGNAL,
- FRONTEND_EVENT_TYPE_LOST_LOCK})
+ @IntDef(prefix = "FRONTEND_EVENT_TYPE_",
+ value = {FRONTEND_EVENT_TYPE_LOCKED, FRONTEND_EVENT_TYPE_NO_SIGNAL,
+ FRONTEND_EVENT_TYPE_LOST_LOCK})
@Retention(RetentionPolicy.SOURCE)
public @interface FrontendEventType {}
- /** @hide */
+ /**
+ * Frontend locked.
+ * @hide
+ */
public static final int FRONTEND_EVENT_TYPE_LOCKED = Constants.FrontendEventType.LOCKED;
- /** @hide */
+ /**
+ * No signal detected.
+ * @hide
+ */
public static final int FRONTEND_EVENT_TYPE_NO_SIGNAL = Constants.FrontendEventType.NO_SIGNAL;
- /** @hide */
+ /**
+ * Frontend lock lost.
+ * @hide
+ */
public static final int FRONTEND_EVENT_TYPE_LOST_LOCK = Constants.FrontendEventType.LOST_LOCK;
/** @hide */
- @IntDef({FILTER_SUBTYPE_UNDEFINED, FILTER_SUBTYPE_SECTION, FILTER_SUBTYPE_PES,
- FILTER_SUBTYPE_AUDIO, FILTER_SUBTYPE_VIDEO, FILTER_SUBTYPE_DOWNLOAD,
- FILTER_SUBTYPE_RECORD, FILTER_SUBTYPE_TS, FILTER_SUBTYPE_PCR, FILTER_SUBTYPE_TEMI,
- FILTER_SUBTYPE_MMPT, FILTER_SUBTYPE_NTP, FILTER_SUBTYPE_IP_PAYLOAD, FILTER_SUBTYPE_IP,
- FILTER_SUBTYPE_PAYLOAD_THROUGH, FILTER_SUBTYPE_TLV, FILTER_SUBTYPE_PTP, })
- @Retention(RetentionPolicy.SOURCE)
- public @interface FilterSubtype {}
- /** @hide */
- public static final int FILTER_SUBTYPE_UNDEFINED = 0;
- /** @hide */
- public static final int FILTER_SUBTYPE_SECTION = 1;
- /** @hide */
- public static final int FILTER_SUBTYPE_PES = 2;
- /** @hide */
- public static final int FILTER_SUBTYPE_AUDIO = 3;
- /** @hide */
- public static final int FILTER_SUBTYPE_VIDEO = 4;
- /** @hide */
- public static final int FILTER_SUBTYPE_DOWNLOAD = 5;
- /** @hide */
- public static final int FILTER_SUBTYPE_RECORD = 6;
- /** @hide */
- public static final int FILTER_SUBTYPE_TS = 7;
- /** @hide */
- public static final int FILTER_SUBTYPE_PCR = 8;
- /** @hide */
- public static final int FILTER_SUBTYPE_TEMI = 9;
- /** @hide */
- public static final int FILTER_SUBTYPE_MMPT = 10;
- /** @hide */
- public static final int FILTER_SUBTYPE_NTP = 11;
- /** @hide */
- public static final int FILTER_SUBTYPE_IP_PAYLOAD = 12;
- /** @hide */
- public static final int FILTER_SUBTYPE_IP = 13;
- /** @hide */
- public static final int FILTER_SUBTYPE_PAYLOAD_THROUGH = 14;
- /** @hide */
- public static final int FILTER_SUBTYPE_TLV = 15;
- /** @hide */
- public static final int FILTER_SUBTYPE_PTP = 16;
-
- /** @hide */
@IntDef(flag = true, prefix = "FILTER_STATUS_", value = {FILTER_STATUS_DATA_READY,
FILTER_STATUS_LOW_WATER, FILTER_STATUS_HIGH_WATER, FILTER_STATUS_OVERFLOW})
@Retention(RetentionPolicy.SOURCE)
@@ -502,23 +475,6 @@
/** @hide */
- @IntDef({FILTER_SETTINGS_TS, FILTER_SETTINGS_MMTP, FILTER_SETTINGS_IP, FILTER_SETTINGS_TLV,
- FILTER_SETTINGS_ALP})
- @Retention(RetentionPolicy.SOURCE)
- public @interface FilterSettingsType {}
- /** @hide */
- public static final int FILTER_SETTINGS_TS = Constants.DemuxFilterMainType.TS;
- /** @hide */
- public static final int FILTER_SETTINGS_MMTP = Constants.DemuxFilterMainType.MMTP;
- /** @hide */
- public static final int FILTER_SETTINGS_IP = Constants.DemuxFilterMainType.IP;
- /** @hide */
- public static final int FILTER_SETTINGS_TLV = Constants.DemuxFilterMainType.TLV;
- /** @hide */
- public static final int FILTER_SETTINGS_ALP = Constants.DemuxFilterMainType.ALP;
-
-
- /** @hide */
@IntDef({RESULT_SUCCESS, RESULT_UNAVAILABLE, RESULT_NOT_INITIALIZED, RESULT_INVALID_STATE,
RESULT_INVALID_ARGUMENT, RESULT_OUT_OF_MEMORY, RESULT_UNKNOWN_ERROR})
@Retention(RetentionPolicy.SOURCE)
diff --git a/media/java/android/media/tv/tuner/TunerUtils.java b/media/java/android/media/tv/tuner/TunerUtils.java
index 8780b72..30aaa02 100644
--- a/media/java/android/media/tv/tuner/TunerUtils.java
+++ b/media/java/android/media/tv/tuner/TunerUtils.java
@@ -19,9 +19,7 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.tv.tuner.V1_0.Constants;
-import android.media.tv.tuner.TunerConstants.FilterSubtype;
-import android.media.tv.tuner.filter.FilterConfiguration;
-import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
+import android.media.tv.tuner.filter.Filter;
/**
* Utility class for tuner framework.
@@ -50,91 +48,91 @@
* @param mainType filter main type.
* @param subtype filter subtype.
*/
- public static int getFilterSubtype(@FilterType int mainType, @FilterSubtype int subtype) {
- if (mainType == FilterConfiguration.FILTER_TYPE_TS) {
+ public static int getFilterSubtype(@Filter.Type int mainType, @Filter.Subtype int subtype) {
+ if (mainType == Filter.TYPE_TS) {
switch (subtype) {
- case TunerConstants.FILTER_SUBTYPE_UNDEFINED:
+ case Filter.SUBTYPE_UNDEFINED:
return Constants.DemuxTsFilterType.UNDEFINED;
- case TunerConstants.FILTER_SUBTYPE_SECTION:
+ case Filter.SUBTYPE_SECTION:
return Constants.DemuxTsFilterType.SECTION;
- case TunerConstants.FILTER_SUBTYPE_PES:
+ case Filter.SUBTYPE_PES:
return Constants.DemuxTsFilterType.PES;
- case TunerConstants.FILTER_SUBTYPE_TS:
+ case Filter.SUBTYPE_TS:
return Constants.DemuxTsFilterType.TS;
- case TunerConstants.FILTER_SUBTYPE_AUDIO:
+ case Filter.SUBTYPE_AUDIO:
return Constants.DemuxTsFilterType.AUDIO;
- case TunerConstants.FILTER_SUBTYPE_VIDEO:
+ case Filter.SUBTYPE_VIDEO:
return Constants.DemuxTsFilterType.VIDEO;
- case TunerConstants.FILTER_SUBTYPE_PCR:
+ case Filter.SUBTYPE_PCR:
return Constants.DemuxTsFilterType.PCR;
- case TunerConstants.FILTER_SUBTYPE_RECORD:
+ case Filter.SUBTYPE_RECORD:
return Constants.DemuxTsFilterType.RECORD;
- case TunerConstants.FILTER_SUBTYPE_TEMI:
+ case Filter.SUBTYPE_TEMI:
return Constants.DemuxTsFilterType.TEMI;
default:
break;
}
- } else if (mainType == FilterConfiguration.FILTER_TYPE_MMTP) {
+ } else if (mainType == Filter.TYPE_MMTP) {
switch (subtype) {
- case TunerConstants.FILTER_SUBTYPE_UNDEFINED:
+ case Filter.SUBTYPE_UNDEFINED:
return Constants.DemuxMmtpFilterType.UNDEFINED;
- case TunerConstants.FILTER_SUBTYPE_SECTION:
+ case Filter.SUBTYPE_SECTION:
return Constants.DemuxMmtpFilterType.SECTION;
- case TunerConstants.FILTER_SUBTYPE_PES:
+ case Filter.SUBTYPE_PES:
return Constants.DemuxMmtpFilterType.PES;
- case TunerConstants.FILTER_SUBTYPE_MMPT:
+ case Filter.SUBTYPE_MMTP:
return Constants.DemuxMmtpFilterType.MMTP;
- case TunerConstants.FILTER_SUBTYPE_AUDIO:
+ case Filter.SUBTYPE_AUDIO:
return Constants.DemuxMmtpFilterType.AUDIO;
- case TunerConstants.FILTER_SUBTYPE_VIDEO:
+ case Filter.SUBTYPE_VIDEO:
return Constants.DemuxMmtpFilterType.VIDEO;
- case TunerConstants.FILTER_SUBTYPE_RECORD:
+ case Filter.SUBTYPE_RECORD:
return Constants.DemuxMmtpFilterType.RECORD;
- case TunerConstants.FILTER_SUBTYPE_DOWNLOAD:
+ case Filter.SUBTYPE_DOWNLOAD:
return Constants.DemuxMmtpFilterType.DOWNLOAD;
default:
break;
}
- } else if (mainType == FilterConfiguration.FILTER_TYPE_IP) {
+ } else if (mainType == Filter.TYPE_IP) {
switch (subtype) {
- case TunerConstants.FILTER_SUBTYPE_UNDEFINED:
+ case Filter.SUBTYPE_UNDEFINED:
return Constants.DemuxIpFilterType.UNDEFINED;
- case TunerConstants.FILTER_SUBTYPE_SECTION:
+ case Filter.SUBTYPE_SECTION:
return Constants.DemuxIpFilterType.SECTION;
- case TunerConstants.FILTER_SUBTYPE_NTP:
+ case Filter.SUBTYPE_NTP:
return Constants.DemuxIpFilterType.NTP;
- case TunerConstants.FILTER_SUBTYPE_IP_PAYLOAD:
+ case Filter.SUBTYPE_IP_PAYLOAD:
return Constants.DemuxIpFilterType.IP_PAYLOAD;
- case TunerConstants.FILTER_SUBTYPE_IP:
+ case Filter.SUBTYPE_IP:
return Constants.DemuxIpFilterType.IP;
- case TunerConstants.FILTER_SUBTYPE_PAYLOAD_THROUGH:
+ case Filter.SUBTYPE_PAYLOAD_THROUGH:
return Constants.DemuxIpFilterType.PAYLOAD_THROUGH;
default:
break;
}
- } else if (mainType == FilterConfiguration.FILTER_TYPE_TLV) {
+ } else if (mainType == Filter.TYPE_TLV) {
switch (subtype) {
- case TunerConstants.FILTER_SUBTYPE_UNDEFINED:
+ case Filter.SUBTYPE_UNDEFINED:
return Constants.DemuxTlvFilterType.UNDEFINED;
- case TunerConstants.FILTER_SUBTYPE_SECTION:
+ case Filter.SUBTYPE_SECTION:
return Constants.DemuxTlvFilterType.SECTION;
- case TunerConstants.FILTER_SUBTYPE_TLV:
+ case Filter.SUBTYPE_TLV:
return Constants.DemuxTlvFilterType.TLV;
- case TunerConstants.FILTER_SUBTYPE_PAYLOAD_THROUGH:
+ case Filter.SUBTYPE_PAYLOAD_THROUGH:
return Constants.DemuxTlvFilterType.PAYLOAD_THROUGH;
default:
break;
}
- } else if (mainType == FilterConfiguration.FILTER_TYPE_ALP) {
+ } else if (mainType == Filter.TYPE_ALP) {
switch (subtype) {
- case TunerConstants.FILTER_SUBTYPE_UNDEFINED:
+ case Filter.SUBTYPE_UNDEFINED:
return Constants.DemuxAlpFilterType.UNDEFINED;
- case TunerConstants.FILTER_SUBTYPE_SECTION:
+ case Filter.SUBTYPE_SECTION:
return Constants.DemuxAlpFilterType.SECTION;
- case TunerConstants.FILTER_SUBTYPE_PTP:
+ case Filter.SUBTYPE_PTP:
return Constants.DemuxAlpFilterType.PTP;
- case TunerConstants.FILTER_SUBTYPE_PAYLOAD_THROUGH:
+ case Filter.SUBTYPE_PAYLOAD_THROUGH:
return Constants.DemuxAlpFilterType.PAYLOAD_THROUGH;
default:
break;
diff --git a/media/java/android/media/tv/tuner/dvr/Dvr.java b/media/java/android/media/tv/tuner/dvr/Dvr.java
index 95508d3..a17773c 100644
--- a/media/java/android/media/tv/tuner/dvr/Dvr.java
+++ b/media/java/android/media/tv/tuner/dvr/Dvr.java
@@ -17,11 +17,16 @@
package android.media.tv.tuner.dvr;
import android.annotation.BytesLong;
+import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.hardware.tv.tuner.V1_0.Constants;
import android.media.tv.tuner.Tuner.Filter;
import android.media.tv.tuner.TunerConstants.Result;
import android.os.ParcelFileDescriptor;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Digital Video Record (DVR) interface provides record control on Demux's output buffer and
* playback control on Demux's input buffer.
@@ -29,6 +34,37 @@
* @hide
*/
public class Dvr {
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "PLAYBACK_STATUS_",
+ value = {PLAYBACK_STATUS_EMPTY, PLAYBACK_STATUS_ALMOST_EMPTY,
+ PLAYBACK_STATUS_ALMOST_FULL, PLAYBACK_STATUS_FULL})
+ @interface PlaybackStatus {}
+
+ /**
+ * The space of the playback is empty.
+ */
+ public static final int PLAYBACK_STATUS_EMPTY = Constants.PlaybackStatus.SPACE_EMPTY;
+ /**
+ * The space of the playback is almost empty.
+ *
+ * <p> the threshold is set in {@link DvrSettings}.
+ */
+ public static final int PLAYBACK_STATUS_ALMOST_EMPTY =
+ Constants.PlaybackStatus.SPACE_ALMOST_EMPTY;
+ /**
+ * The space of the playback is almost full.
+ *
+ * <p> the threshold is set in {@link DvrSettings}.
+ */
+ public static final int PLAYBACK_STATUS_ALMOST_FULL =
+ Constants.PlaybackStatus.SPACE_ALMOST_FULL;
+ /**
+ * The space of the playback is full.
+ */
+ public static final int PLAYBACK_STATUS_FULL = Constants.PlaybackStatus.SPACE_FULL;
+
+
private long mNativeContext;
private DvrCallback mCallback;
diff --git a/media/java/android/media/tv/tuner/dvr/DvrCallback.java b/media/java/android/media/tv/tuner/dvr/DvrCallback.java
index 3d140f0..ee0cfa7 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrCallback.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrCallback.java
@@ -16,6 +16,9 @@
package android.media.tv.tuner.dvr;
+import android.media.tv.tuner.TunerConstants.FilterStatus;
+import android.media.tv.tuner.dvr.Dvr.PlaybackStatus;
+
/**
* Callback interface for receiving information from DVR interfaces.
*
@@ -25,9 +28,9 @@
/**
* Invoked when record status changed.
*/
- void onRecordStatusChanged(int status);
+ void onRecordStatusChanged(@FilterStatus int status);
/**
* Invoked when playback status changed.
*/
- void onPlaybackStatusChanged(int status);
+ void onPlaybackStatusChanged(@PlaybackStatus int status);
}
diff --git a/media/java/android/media/tv/tuner/dvr/DvrSettings.java b/media/java/android/media/tv/tuner/dvr/DvrSettings.java
index 46efd7a..49e875a 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrSettings.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrSettings.java
@@ -19,8 +19,11 @@
import android.annotation.BytesLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.content.Context;
import android.hardware.tv.tuner.V1_0.Constants;
import android.media.tv.tuner.TunerConstants.FilterStatus;
+import android.media.tv.tuner.TunerUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -94,9 +97,13 @@
/**
* Creates a builder for {@link DvrSettings}.
+ *
+ * @param context the context of the caller.
*/
+ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@NonNull
- public static Builder newBuilder() {
+ public static Builder builder(Context context) {
+ TunerUtils.checkTunerPermission(context);
return new Builder();
}
diff --git a/media/java/android/media/tv/tuner/filter/AvSettings.java b/media/java/android/media/tv/tuner/filter/AvSettings.java
index 940b5ae..93eaaa4 100644
--- a/media/java/android/media/tv/tuner/filter/AvSettings.java
+++ b/media/java/android/media/tv/tuner/filter/AvSettings.java
@@ -19,9 +19,7 @@
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.content.Context;
-import android.media.tv.tuner.TunerConstants;
import android.media.tv.tuner.TunerUtils;
-import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
/**
* Filter Settings for a Video and Audio.
@@ -35,8 +33,8 @@
super(TunerUtils.getFilterSubtype(
mainType,
isAudio
- ? TunerConstants.FILTER_SUBTYPE_AUDIO
- : TunerConstants.FILTER_SUBTYPE_VIDEO));
+ ? Filter.SUBTYPE_AUDIO
+ : Filter.SUBTYPE_VIDEO));
mIsPassthrough = isPassthrough;
}
@@ -57,7 +55,7 @@
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@NonNull
public static Builder builder(
- @NonNull Context context, @FilterType int mainType, boolean isAudio) {
+ @NonNull Context context, @Filter.Type int mainType, boolean isAudio) {
TunerUtils.checkTunerPermission(context);
return new Builder(mainType, isAudio);
}
diff --git a/media/java/android/media/tv/tuner/filter/DownloadSettings.java b/media/java/android/media/tv/tuner/filter/DownloadSettings.java
index e3e1df0..fa7744a 100644
--- a/media/java/android/media/tv/tuner/filter/DownloadSettings.java
+++ b/media/java/android/media/tv/tuner/filter/DownloadSettings.java
@@ -19,9 +19,7 @@
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.content.Context;
-import android.media.tv.tuner.TunerConstants;
import android.media.tv.tuner.TunerUtils;
-import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
/**
* Filter Settings for a Download.
@@ -31,7 +29,7 @@
private final int mDownloadId;
private DownloadSettings(int mainType, int downloadId) {
- super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_DOWNLOAD));
+ super(TunerUtils.getFilterSubtype(mainType, Filter.SUBTYPE_DOWNLOAD));
mDownloadId = downloadId;
}
@@ -50,7 +48,7 @@
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@NonNull
- public static Builder builder(@NonNull Context context, @FilterType int mainType) {
+ public static Builder builder(@NonNull Context context, @Filter.Type int mainType) {
TunerUtils.checkTunerPermission(context);
return new Builder(mainType);
}
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index 804c0c5..3f6154b 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -17,9 +17,15 @@
package android.media.tv.tuner.filter;
import android.annotation.BytesLong;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.hardware.tv.tuner.V1_0.Constants;
import android.media.tv.tuner.Tuner.FilterCallback;
+import android.media.tv.tuner.TunerConstants.Result;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* Tuner data filter.
@@ -29,6 +35,128 @@
* @hide
*/
public class Filter implements AutoCloseable {
+ /** @hide */
+ @IntDef(prefix = "TYPE_",
+ value = {TYPE_TS, TYPE_MMTP, TYPE_IP, TYPE_TLV, TYPE_ALP})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {}
+
+ /**
+ * TS filter type.
+ */
+ public static final int TYPE_TS = Constants.DemuxFilterMainType.TS;
+ /**
+ * MMTP filter type.
+ */
+ public static final int TYPE_MMTP = Constants.DemuxFilterMainType.MMTP;
+ /**
+ * IP filter type.
+ */
+ public static final int TYPE_IP = Constants.DemuxFilterMainType.IP;
+ /**
+ * TLV filter type.
+ */
+ public static final int TYPE_TLV = Constants.DemuxFilterMainType.TLV;
+ /**
+ * ALP filter type.
+ */
+ public static final int TYPE_ALP = Constants.DemuxFilterMainType.ALP;
+
+ /** @hide */
+ @IntDef(prefix = "SUBTYPE_",
+ value = {SUBTYPE_UNDEFINED, SUBTYPE_SECTION, SUBTYPE_PES, SUBTYPE_AUDIO, SUBTYPE_VIDEO,
+ SUBTYPE_DOWNLOAD, SUBTYPE_RECORD, SUBTYPE_TS, SUBTYPE_PCR, SUBTYPE_TEMI,
+ SUBTYPE_MMTP, SUBTYPE_NTP, SUBTYPE_IP_PAYLOAD, SUBTYPE_IP,
+ SUBTYPE_PAYLOAD_THROUGH, SUBTYPE_TLV, SUBTYPE_PTP, })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Subtype {}
+ /**
+ * Filter subtype undefined.
+ * @hide
+ */
+ public static final int SUBTYPE_UNDEFINED = 0;
+ /**
+ * Section filter subtype.
+ * @hide
+ */
+ public static final int SUBTYPE_SECTION = 1;
+ /**
+ * PES filter subtype.
+ * @hide
+ */
+ public static final int SUBTYPE_PES = 2;
+ /**
+ * Audio filter subtype.
+ * @hide
+ */
+ public static final int SUBTYPE_AUDIO = 3;
+ /**
+ * Video filter subtype.
+ * @hide
+ */
+ public static final int SUBTYPE_VIDEO = 4;
+ /**
+ * Download filter subtype.
+ * @hide
+ */
+ public static final int SUBTYPE_DOWNLOAD = 5;
+ /**
+ * Record filter subtype.
+ * @hide
+ */
+ public static final int SUBTYPE_RECORD = 6;
+ /**
+ * TS filter subtype.
+ * @hide
+ */
+ public static final int SUBTYPE_TS = 7;
+ /**
+ * PCR filter subtype.
+ * @hide
+ */
+ public static final int SUBTYPE_PCR = 8;
+ /**
+ * TEMI filter subtype.
+ * @hide
+ */
+ public static final int SUBTYPE_TEMI = 9;
+ /**
+ * MMTP filter subtype.
+ * @hide
+ */
+ public static final int SUBTYPE_MMTP = 10;
+ /**
+ * NTP filter subtype.
+ * @hide
+ */
+ public static final int SUBTYPE_NTP = 11;
+ /**
+ * Payload filter subtype.
+ * @hide
+ */
+ public static final int SUBTYPE_IP_PAYLOAD = 12;
+ /**
+ * IP filter subtype.
+ * @hide
+ */
+ public static final int SUBTYPE_IP = 13;
+ /**
+ * Payload through filter subtype.
+ * @hide
+ */
+ public static final int SUBTYPE_PAYLOAD_THROUGH = 14;
+ /**
+ * TLV filter subtype.
+ * @hide
+ */
+ public static final int SUBTYPE_TLV = 15;
+ /**
+ * PTP filter subtype.
+ * @hide
+ */
+ public static final int SUBTYPE_PTP = 16;
+
+
private long mNativeContext;
private FilterCallback mCallback;
private final int mId;
@@ -56,6 +184,7 @@
* @param config the configuration of the filter.
* @return result status of the operation.
*/
+ @Result
public int configure(@NonNull FilterConfiguration config) {
int subType = -1;
Settings s = config.getSettings();
@@ -68,6 +197,7 @@
/**
* Gets the filter Id.
*/
+ @Result
public int getId() {
return nativeGetId();
}
@@ -84,6 +214,7 @@
* use demux as data source if the filter instance is NULL.
* @return result status of the operation.
*/
+ @Result
public int setDataSource(@Nullable Filter source) {
return nativeSetDataSource(source);
}
@@ -93,6 +224,7 @@
*
* @return result status of the operation.
*/
+ @Result
public int start() {
return nativeStartFilter();
}
@@ -103,6 +235,7 @@
*
* @return result status of the operation.
*/
+ @Result
public int stop() {
return nativeStopFilter();
}
@@ -112,6 +245,7 @@
*
* @return result status of the operation.
*/
+ @Result
public int flush() {
return nativeFlushFilter();
}
@@ -124,6 +258,7 @@
* @param size the maximum number of bytes to read.
* @return the number of bytes read.
*/
+ @Result
public int read(@NonNull byte[] buffer, @BytesLong long offset, @BytesLong long size) {
size = Math.min(size, buffer.length - offset);
return nativeRead(buffer, offset, size);
diff --git a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
index 68c722f..c901e2b 100644
--- a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
@@ -32,7 +32,10 @@
@SystemApi
public abstract class FilterConfiguration {
- /** @hide */
+ /**
+ * TODO: moved to Filter. Remove it here.
+ * @hide
+ */
@IntDef(prefix = "FILTER_TYPE_", value =
{FILTER_TYPE_TS, FILTER_TYPE_MMTP, FILTER_TYPE_IP, FILTER_TYPE_TLV, FILTER_TYPE_ALP})
@Retention(RetentionPolicy.SOURCE)
diff --git a/media/java/android/media/tv/tuner/filter/MediaEvent.java b/media/java/android/media/tv/tuner/filter/MediaEvent.java
index 37f94ae..0b5c56b 100644
--- a/media/java/android/media/tv/tuner/filter/MediaEvent.java
+++ b/media/java/android/media/tv/tuner/filter/MediaEvent.java
@@ -16,6 +16,7 @@
package android.media.tv.tuner.filter;
+import android.annotation.BytesLong;
import android.annotation.Nullable;
import android.media.tv.tuner.Tuner.Filter;
@@ -28,23 +29,27 @@
private final int mStreamId;
private final boolean mIsPtsPresent;
private final long mPts;
- private final int mDataLength;
+ private final long mDataLength;
+ private final long mOffset;
private final Object mLinearBuffer;
private final boolean mIsSecureMemory;
+ private final long mDataId;
private final int mMpuSequenceNumber;
private final boolean mIsPrivateData;
private final AudioDescriptor mExtraMetaData;
// This constructor is used by JNI code only
- private MediaEvent(int streamId, boolean isPtsPresent, long pts, int dataLength, Object buffer,
- boolean isSecureMemory, int mpuSequenceNumber, boolean isPrivateData,
- AudioDescriptor extraMetaData) {
+ private MediaEvent(int streamId, boolean isPtsPresent, long pts, long dataLength, long offset,
+ Object buffer, boolean isSecureMemory, long dataId, int mpuSequenceNumber,
+ boolean isPrivateData, AudioDescriptor extraMetaData) {
mStreamId = streamId;
mIsPtsPresent = isPtsPresent;
mPts = pts;
mDataLength = dataLength;
+ mOffset = offset;
mLinearBuffer = buffer;
mIsSecureMemory = isSecureMemory;
+ mDataId = dataId;
mMpuSequenceNumber = mpuSequenceNumber;
mIsPrivateData = isPrivateData;
mExtraMetaData = extraMetaData;
@@ -76,11 +81,20 @@
/**
* Gets data size in bytes of audio or video frame.
*/
- public int getDataLength() {
+ @BytesLong
+ public long getDataLength() {
return mDataLength;
}
/**
+ * The offset in the memory block which is shared among multiple Media Events.
+ */
+ @BytesLong
+ public long getOffset() {
+ return mOffset;
+ }
+
+ /**
* Gets a linear buffer associated to the memory where audio or video data stays.
* TODO: use LinearBuffer when it's ready.
*
@@ -101,6 +115,15 @@
}
/**
+ * Gets the ID which is used by HAL to provide additional information for AV data.
+ *
+ * <p>For secure audio, it's the audio handle used by Audio Track.
+ */
+ public long getAvDataId() {
+ return mDataId;
+ }
+
+ /**
* Gets MPU sequence number of filtered data.
*/
public int getMpuSequenceNumber() {
diff --git a/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
index 83246e5..248f23a 100644
--- a/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
@@ -39,7 +39,7 @@
}
/**
- * Gets MMPT PID.
+ * Gets MMTP PID.
*
* <p>Packet ID is used to specify packets in MMTP.
*/
@@ -69,7 +69,7 @@
}
/**
- * Sets MMPT PID.
+ * Sets MMTP PID.
*/
@NonNull
public Builder setMmtpPid(int mmtpPid) {
diff --git a/media/java/android/media/tv/tuner/filter/PesSettings.java b/media/java/android/media/tv/tuner/filter/PesSettings.java
index bfa1f8c..0f83597 100644
--- a/media/java/android/media/tv/tuner/filter/PesSettings.java
+++ b/media/java/android/media/tv/tuner/filter/PesSettings.java
@@ -20,9 +20,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.Context;
-import android.media.tv.tuner.TunerConstants;
import android.media.tv.tuner.TunerUtils;
-import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
/**
* Filter Settings for a PES Data.
@@ -34,8 +32,8 @@
private final int mStreamId;
private final boolean mIsRaw;
- private PesSettings(@FilterType int mainType, int streamId, boolean isRaw) {
- super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_PES));
+ private PesSettings(@Filter.Type int mainType, int streamId, boolean isRaw) {
+ super(TunerUtils.getFilterSubtype(mainType, Filter.SUBTYPE_PES));
mStreamId = streamId;
mIsRaw = isRaw;
}
@@ -65,7 +63,7 @@
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@NonNull
- public static Builder builder(@NonNull Context context, @FilterType int mainType) {
+ public static Builder builder(@NonNull Context context, @Filter.Type int mainType) {
TunerUtils.checkTunerPermission(context);
return new Builder(mainType);
}
diff --git a/media/java/android/media/tv/tuner/filter/RecordSettings.java b/media/java/android/media/tv/tuner/filter/RecordSettings.java
index 4833709..4e9d67f 100644
--- a/media/java/android/media/tv/tuner/filter/RecordSettings.java
+++ b/media/java/android/media/tv/tuner/filter/RecordSettings.java
@@ -24,7 +24,6 @@
import android.media.tv.tuner.TunerConstants;
import android.media.tv.tuner.TunerConstants.ScIndexType;
import android.media.tv.tuner.TunerUtils;
-import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -151,7 +150,7 @@
private final int mScIndexMask;
private RecordSettings(int mainType, int tsIndexType, int scIndexType, int scIndexMask) {
- super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_RECORD));
+ super(TunerUtils.getFilterSubtype(mainType, Filter.SUBTYPE_RECORD));
mTsIndexMask = tsIndexType;
mScIndexType = scIndexType;
mScIndexMask = scIndexMask;
@@ -187,7 +186,7 @@
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@NonNull
- public static Builder builder(@NonNull Context context, @FilterType int mainType) {
+ public static Builder builder(@NonNull Context context, @Filter.Type int mainType) {
TunerUtils.checkTunerPermission(context);
return new Builder(mainType);
}
diff --git a/media/java/android/media/tv/tuner/filter/SectionSettings.java b/media/java/android/media/tv/tuner/filter/SectionSettings.java
index 36e3d7c..b8d0fad 100644
--- a/media/java/android/media/tv/tuner/filter/SectionSettings.java
+++ b/media/java/android/media/tv/tuner/filter/SectionSettings.java
@@ -16,7 +16,6 @@
package android.media.tv.tuner.filter;
-import android.media.tv.tuner.TunerConstants;
import android.media.tv.tuner.TunerUtils;
/**
@@ -26,6 +25,6 @@
public class SectionSettings extends Settings {
SectionSettings(int mainType) {
- super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_SECTION));
+ super(TunerUtils.getFilterSubtype(mainType, Filter.SUBTYPE_SECTION));
}
}
diff --git a/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java b/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java
index 0fa982e..a2d42d8 100644
--- a/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java
+++ b/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java
@@ -20,7 +20,6 @@
import android.annotation.RequiresPermission;
import android.content.Context;
import android.media.tv.tuner.TunerUtils;
-import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
/**
* Bits Settings for Section Filters.
@@ -73,7 +72,7 @@
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@NonNull
- public static Builder builder(@NonNull Context context, @FilterType int mainType) {
+ public static Builder builder(@NonNull Context context, @Filter.Type int mainType) {
TunerUtils.checkTunerPermission(context);
return new Builder(mainType);
}
diff --git a/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java b/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java
index 6542b89..0c9cd2b 100644
--- a/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java
+++ b/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java
@@ -20,7 +20,6 @@
import android.annotation.RequiresPermission;
import android.content.Context;
import android.media.tv.tuner.TunerUtils;
-import android.media.tv.tuner.filter.FilterConfiguration.FilterType;
/**
* Table information for Section Filter.
@@ -57,7 +56,7 @@
*/
@RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
@NonNull
- public static Builder builder(@NonNull Context context, @FilterType int mainType) {
+ public static Builder builder(@NonNull Context context, @Filter.Type int mainType) {
TunerUtils.checkTunerPermission(context);
return new Builder(mainType);
}
diff --git a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
index 5b3bffc4..44dbcc0 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
@@ -112,31 +112,31 @@
public @interface Rolloff {}
/**
- * Roll Off undefined.
+ * Rolloff range undefined.
*/
public static final int ROLLOFF_UNDEFINED = Constants.FrontendDvbsRolloff.UNDEFINED;
/**
- * Roll Off 0_35.
+ * Rolloff range 0,35.
*/
public static final int ROLLOFF_0_35 = Constants.FrontendDvbsRolloff.ROLLOFF_0_35;
/**
- * Roll Off 0_25.
+ * Rolloff range 0,25.
*/
public static final int ROLLOFF_0_25 = Constants.FrontendDvbsRolloff.ROLLOFF_0_25;
/**
- * Roll Off 0_2.
+ * Rolloff range 0,20.
*/
public static final int ROLLOFF_0_20 = Constants.FrontendDvbsRolloff.ROLLOFF_0_20;
/**
- * Roll Off 0_15.
+ * Rolloff range 0,15.
*/
public static final int ROLLOFF_0_15 = Constants.FrontendDvbsRolloff.ROLLOFF_0_15;
/**
- * Roll Off 0_1.
+ * Rolloff range 0,10.
*/
public static final int ROLLOFF_0_10 = Constants.FrontendDvbsRolloff.ROLLOFF_0_10;
/**
- * Roll Off 0_5.
+ * Rolloff range 0,5.
*/
public static final int ROLLOFF_0_5 = Constants.FrontendDvbsRolloff.ROLLOFF_0_5;
@@ -188,6 +188,25 @@
*/
public static final int STANDARD_S2X = Constants.FrontendDvbsStandard.S2X;
+ /** @hide */
+ @IntDef(prefix = "VCM_MODE_",
+ value = {VCM_MODE_UNDEFINED, VCM_MODE_AUTO, VCM_MODE_MANUAL})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface VcmMode {}
+
+ /**
+ * VCM mode undefined.
+ */
+ public static final int VCM_MODE_UNDEFINED = Constants.FrontendDvbsVcmMode.UNDEFINED;
+ /**
+ * Auto VCM mode.
+ */
+ public static final int VCM_MODE_AUTO = Constants.FrontendDvbsVcmMode.AUTO;
+ /**
+ * Manual VCM mode.
+ */
+ public static final int VCM_MODE_MANUAL = Constants.FrontendDvbsVcmMode.MANUAL;
+
private final int mModulation;
private final DvbsCodeRate mCoderate;
@@ -196,9 +215,10 @@
private final int mPilot;
private final int mInputStreamId;
private final int mStandard;
+ private final int mVcmMode;
private DvbsFrontendSettings(int frequency, int modulation, DvbsCodeRate coderate,
- int symbolRate, int rolloff, int pilot, int inputStreamId, int standard) {
+ int symbolRate, int rolloff, int pilot, int inputStreamId, int standard, int vcm) {
super(frequency);
mModulation = modulation;
mCoderate = coderate;
@@ -207,6 +227,7 @@
mPilot = pilot;
mInputStreamId = inputStreamId;
mStandard = standard;
+ mVcmMode = vcm;
}
/**
@@ -256,6 +277,13 @@
public int getStandard() {
return mStandard;
}
+ /**
+ * Gets VCM mode.
+ */
+ @VcmMode
+ public int getVcmMode() {
+ return mVcmMode;
+ }
/**
* Creates a builder for {@link DvbsFrontendSettings}.
@@ -280,6 +308,7 @@
private int mPilot;
private int mInputStreamId;
private int mStandard;
+ private int mVcmMode;
private Builder() {
}
@@ -340,6 +369,14 @@
mStandard = standard;
return this;
}
+ /**
+ * Sets VCM mode.
+ */
+ @NonNull
+ public Builder setVcmMode(@VcmMode int vcm) {
+ mVcmMode = vcm;
+ return this;
+ }
/**
* Builds a {@link DvbsFrontendSettings} object.
@@ -347,7 +384,7 @@
@NonNull
public DvbsFrontendSettings build() {
return new DvbsFrontendSettings(mFrequency, mModulation, mCoderate, mSymbolRate,
- mRolloff, mPilot, mInputStreamId, mStandard);
+ mRolloff, mPilot, mInputStreamId, mStandard, mVcmMode);
}
@Override
diff --git a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
index f0469b7..9a82de0 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
@@ -110,7 +110,7 @@
*/
public static final int BANDWIDTH_5MHZ = Constants.FrontendDvbtBandwidth.BANDWIDTH_5MHZ;
/**
- * 1.7 MHz bandwidth.
+ * 1,7 MHz bandwidth.
*/
public static final int BANDWIDTH_1_7MHZ = Constants.FrontendDvbtBandwidth.BANDWIDTH_1_7MHZ;
/**
@@ -232,39 +232,39 @@
*/
public static final int CODERATE_AUTO = Constants.FrontendDvbtCoderate.AUTO;
/**
- * 1_2 code rate.
+ * 1/2 code rate.
*/
public static final int CODERATE_1_2 = Constants.FrontendDvbtCoderate.CODERATE_1_2;
/**
- * 2_3 code rate.
+ * 2/3 code rate.
*/
public static final int CODERATE_2_3 = Constants.FrontendDvbtCoderate.CODERATE_2_3;
/**
- * 3_4 code rate.
+ * 3/4 code rate.
*/
public static final int CODERATE_3_4 = Constants.FrontendDvbtCoderate.CODERATE_3_4;
/**
- * 5_6 code rate.
+ * 5/6 code rate.
*/
public static final int CODERATE_5_6 = Constants.FrontendDvbtCoderate.CODERATE_5_6;
/**
- * 7_8 code rate.
+ * 7/8 code rate.
*/
public static final int CODERATE_7_8 = Constants.FrontendDvbtCoderate.CODERATE_7_8;
/**
- * 4_5 code rate.
+ * 4/5 code rate.
*/
public static final int CODERATE_3_5 = Constants.FrontendDvbtCoderate.CODERATE_3_5;
/**
- * 4_5 code rate.
+ * 4/5 code rate.
*/
public static final int CODERATE_4_5 = Constants.FrontendDvbtCoderate.CODERATE_4_5;
/**
- * 6_7 code rate.
+ * 6/7 code rate.
*/
public static final int CODERATE_6_7 = Constants.FrontendDvbtCoderate.CODERATE_6_7;
/**
- * 8_9 code rate.
+ * 8/9 code rate.
*/
public static final int CODERATE_8_9 = Constants.FrontendDvbtCoderate.CODERATE_8_9;
diff --git a/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java
index 7e6f188..a83d771 100644
--- a/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java
@@ -87,47 +87,47 @@
*/
public static final int CODERATE_AUTO = Constants.FrontendIsdbs3Coderate.AUTO;
/**
- * 1_3 code rate.
+ * 1/3 code rate.
*/
public static final int CODERATE_1_3 = Constants.FrontendIsdbs3Coderate.CODERATE_1_3;
/**
- * 2_5 code rate.
+ * 2/5 code rate.
*/
public static final int CODERATE_2_5 = Constants.FrontendIsdbs3Coderate.CODERATE_2_5;
/**
- * 1_2 code rate.
+ * 1/2 code rate.
*/
public static final int CODERATE_1_2 = Constants.FrontendIsdbs3Coderate.CODERATE_1_2;
/**
- * 3_5 code rate.
+ * 3/5 code rate.
*/
public static final int CODERATE_3_5 = Constants.FrontendIsdbs3Coderate.CODERATE_3_5;
/**
- * 2_3 code rate.
+ * 2/3 code rate.
*/
public static final int CODERATE_2_3 = Constants.FrontendIsdbs3Coderate.CODERATE_2_3;
/**
- * 3_4 code rate.
+ * 3/4 code rate.
*/
public static final int CODERATE_3_4 = Constants.FrontendIsdbs3Coderate.CODERATE_3_4;
/**
- * 7_9 code rate.
+ * 7/9 code rate.
*/
public static final int CODERATE_7_9 = Constants.FrontendIsdbs3Coderate.CODERATE_7_9;
/**
- * 4_5 code rate.
+ * 4/5 code rate.
*/
public static final int CODERATE_4_5 = Constants.FrontendIsdbs3Coderate.CODERATE_4_5;
/**
- * 5_6 code rate.
+ * 5/6 code rate.
*/
public static final int CODERATE_5_6 = Constants.FrontendIsdbs3Coderate.CODERATE_5_6;
/**
- * 7_8 code rate.
+ * 7/8 code rate.
*/
public static final int CODERATE_7_8 = Constants.FrontendIsdbs3Coderate.CODERATE_7_8;
/**
- * 9_10 code rate.
+ * 9/10 code rate.
*/
public static final int CODERATE_9_10 = Constants.FrontendIsdbs3Coderate.CODERATE_9_10;
@@ -138,11 +138,11 @@
public @interface Rolloff {}
/**
- * Roll off type undefined.
+ * Rolloff type undefined.
*/
public static final int ROLLOFF_UNDEFINED = Constants.FrontendIsdbs3Rolloff.UNDEFINED;
/**
- * 0.03 roll off type.
+ * 0,03 Rolloff.
*/
public static final int ROLLOFF_0_03 = Constants.FrontendIsdbs3Rolloff.ROLLOFF_0_03;
diff --git a/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java
index fe100f8..bb809bf 100644
--- a/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java
@@ -96,23 +96,23 @@
*/
public static final int CODERATE_AUTO = Constants.FrontendIsdbsCoderate.AUTO;
/**
- * 1_2 code rate.
+ * 1/2 code rate.
*/
public static final int CODERATE_1_2 = Constants.FrontendIsdbsCoderate.CODERATE_1_2;
/**
- * 2_3 code rate.
+ * 2/3 code rate.
*/
public static final int CODERATE_2_3 = Constants.FrontendIsdbsCoderate.CODERATE_2_3;
/**
- * 3_4 code rate.
+ * 3/4 code rate.
*/
public static final int CODERATE_3_4 = Constants.FrontendIsdbsCoderate.CODERATE_3_4;
/**
- * 5_6 code rate.
+ * 5/6 code rate.
*/
public static final int CODERATE_5_6 = Constants.FrontendIsdbsCoderate.CODERATE_5_6;
/**
- * 7_8 code rate.
+ * 7/8 code rate.
*/
public static final int CODERATE_7_8 = Constants.FrontendIsdbsCoderate.CODERATE_7_8;
@@ -123,11 +123,11 @@
public @interface Rolloff {}
/**
- * Roll off type undefined.
+ * Rolloff type undefined.
*/
public static final int ROLLOFF_UNDEFINED = Constants.FrontendIsdbs3Rolloff.UNDEFINED;
/**
- * 0.35 roll off type.
+ * 0,35 rolloff.
*/
public static final int ROLLOFF_0_35 = Constants.FrontendIsdbsRolloff.ROLLOFF_0_35;
diff --git a/media/java/android/media/tv/tuner/frontend/ScanCallback.java b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
index 5e7d218..0479e55 100644
--- a/media/java/android/media/tv/tuner/frontend/ScanCallback.java
+++ b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
@@ -16,6 +16,7 @@
package android.media.tv.tuner.frontend;
+
/**
* Scan callback.
*
@@ -31,11 +32,11 @@
/** scan progress percent (0..100) */
void onProgress(int percent);
- /** Signal frequency in Hertz */
- void onFrequencyReport(int frequency);
+ /** Signal frequencies in Hertz */
+ void onFrequenciesReport(int[] frequency);
/** Symbols per second */
- void onSymbolRate(int rate);
+ void onSymbolRates(int[] rate);
/** Locked Plp Ids for DVBT2 frontend. */
void onPlpIds(int[] plpIds);
@@ -46,15 +47,24 @@
/** Stream Ids. */
void onInputStreamIds(int[] inputStreamIds);
- /** Locked signal standard. */
+ /** Locked signal standard for DVBS. */
void onDvbsStandard(@DvbsFrontendSettings.Standard int dvbsStandandard);
- /** Locked signal standard. */
+ /** Locked signal standard. for DVBT */
void onDvbtStandard(@DvbtFrontendSettings.Standard int dvbtStandard);
+ /** Locked signal SIF standard for Analog. */
+ void onAnalogSifStandard(@AnalogFrontendSettings.SifStandard int sif);
+
/** PLP status in a tuned frequency band for ATSC3 frontend. */
void onAtsc3PlpInfos(Atsc3PlpInfo[] atsc3PlpInfos);
+ /** Frontend hierarchy. */
+ void onHierarchy(@DvbtFrontendSettings.Hierarchy int hierarchy);
+
+ /** Frontend hierarchy. */
+ void onSignalType(@AnalogFrontendSettings.SignalType int signalType);
+
/** PLP information for ATSC3. */
class Atsc3PlpInfo {
private final int mPlpId;
diff --git a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
index ed93112..cc2d1b1 100644
--- a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
@@ -167,8 +167,7 @@
}
@Override
- public void onCreateSession(String packageName, String routeId, String routeFeature,
- long requestId) {
+ public void onCreateSession(String packageName, String routeId, long requestId) {
MediaRoute2Info route = mRoutes.get(routeId);
if (route == null || TextUtils.equals(ROUTE_ID3_SESSION_CREATION_FAILED, routeId)) {
// Tell the router that session cannot be created by passing null as sessionInfo.
@@ -185,8 +184,7 @@
.build());
mRouteIdToSessionId.put(routeId, sessionId);
- RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder(
- sessionId, packageName, routeFeature)
+ RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder(sessionId, packageName)
.addSelectedRoute(routeId)
.addSelectableRoute(ROUTE_ID4_TO_SELECT_AND_DESELECT)
.addTransferrableRoute(ROUTE_ID5_TO_TRANSFER_TO)
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java
index 59e1122..e782aae 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java
@@ -172,21 +172,8 @@
}
@Test
- public void testRequestCreateSessionWithInvalidArguments() {
- String routeFeature = "routeFeature";
- MediaRoute2Info route = new MediaRoute2Info.Builder("id", "name")
- .addFeature(routeFeature)
- .build();
-
- // Tests null route
- assertThrows(NullPointerException.class,
- () -> mRouter2.requestCreateSession(null, routeFeature));
-
- // Tests null or empty route feature
- assertThrows(IllegalArgumentException.class,
- () -> mRouter2.requestCreateSession(route, null));
- assertThrows(IllegalArgumentException.class,
- () -> mRouter2.requestCreateSession(route, ""));
+ public void testRequestCreateSessionWithNullRoute() {
+ assertThrows(NullPointerException.class, () -> mRouter2.requestCreateSession(null));
}
@Test
@@ -208,14 +195,12 @@
public void onSessionCreated(RoutingController controller) {
assertNotNull(controller);
assertTrue(createRouteMap(controller.getSelectedRoutes()).containsKey(ROUTE_ID1));
- assertTrue(TextUtils.equals(FEATURE_SAMPLE, controller.getRouteFeature()));
controllers.add(controller);
successLatch.countDown();
}
@Override
- public void onSessionCreationFailed(MediaRoute2Info requestedRoute,
- String requestedRouteFeature) {
+ public void onSessionCreationFailed(MediaRoute2Info requestedRoute) {
failureLatch.countDown();
}
};
@@ -226,7 +211,7 @@
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(route, FEATURE_SAMPLE);
+ mRouter2.requestCreateSession(route);
assertTrue(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
// onSessionCreationFailed should not be called.
@@ -260,10 +245,8 @@
}
@Override
- public void onSessionCreationFailed(MediaRoute2Info requestedRoute,
- String requestedRouteFeature) {
+ public void onSessionCreationFailed(MediaRoute2Info requestedRoute) {
assertEquals(route, requestedRoute);
- assertTrue(TextUtils.equals(FEATURE_SAMPLE, requestedRouteFeature));
failureLatch.countDown();
}
};
@@ -274,7 +257,7 @@
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(route, FEATURE_SAMPLE);
+ mRouter2.requestCreateSession(route);
assertTrue(failureLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
// onSessionCreated should not be called.
@@ -304,8 +287,7 @@
}
@Override
- public void onSessionCreationFailed(MediaRoute2Info requestedRoute,
- String requestedRouteFeature) {
+ public void onSessionCreationFailed(MediaRoute2Info requestedRoute) {
failureLatch.countDown();
}
};
@@ -322,8 +304,8 @@
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(route1, FEATURE_SAMPLE);
- mRouter2.requestCreateSession(route2, FEATURE_SAMPLE);
+ mRouter2.requestCreateSession(route1);
+ mRouter2.requestCreateSession(route2);
assertTrue(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
// onSessionCreationFailed should not be called.
@@ -337,8 +319,6 @@
assertNotEquals(controller1.getSessionId(), controller2.getSessionId());
assertTrue(createRouteMap(controller1.getSelectedRoutes()).containsKey(ROUTE_ID1));
assertTrue(createRouteMap(controller2.getSelectedRoutes()).containsKey(ROUTE_ID2));
- assertTrue(TextUtils.equals(FEATURE_SAMPLE, controller1.getRouteFeature()));
- assertTrue(TextUtils.equals(FEATURE_SAMPLE, controller2.getRouteFeature()));
} finally {
releaseControllers(createdControllers);
@@ -369,8 +349,7 @@
}
@Override
- public void onSessionCreationFailed(MediaRoute2Info requestedRoute,
- String requestedRouteFeature) {
+ public void onSessionCreationFailed(MediaRoute2Info requestedRoute) {
failureLatch.countDown();
}
};
@@ -381,7 +360,7 @@
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(route, FEATURE_SAMPLE);
+ mRouter2.requestCreateSession(route);
// Unregisters session callback
mRouter2.unregisterSessionCallback(sessionCallback);
@@ -417,7 +396,6 @@
public void onSessionCreated(RoutingController controller) {
assertNotNull(controller);
assertTrue(getRouteIds(controller.getSelectedRoutes()).contains(ROUTE_ID1));
- assertTrue(TextUtils.equals(FEATURE_SAMPLE, controller.getRouteFeature()));
controllers.add(controller);
onSessionCreatedLatch.countDown();
}
@@ -470,7 +448,7 @@
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(routeToCreateSessionWith, FEATURE_SAMPLE);
+ mRouter2.requestCreateSession(routeToCreateSessionWith);
assertTrue(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
assertEquals(1, controllers.size());
@@ -515,7 +493,6 @@
public void onSessionCreated(RoutingController controller) {
assertNotNull(controller);
assertTrue(getRouteIds(controller.getSelectedRoutes()).contains(ROUTE_ID1));
- assertTrue(TextUtils.equals(FEATURE_SAMPLE, controller.getRouteFeature()));
controllers.add(controller);
onSessionCreatedLatch.countDown();
}
@@ -552,7 +529,7 @@
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(routeToCreateSessionWith, FEATURE_SAMPLE);
+ mRouter2.requestCreateSession(routeToCreateSessionWith);
assertTrue(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
assertEquals(1, controllers.size());
@@ -594,7 +571,6 @@
public void onSessionCreated(RoutingController controller) {
assertNotNull(controller);
assertTrue(getRouteIds(controller.getSelectedRoutes()).contains(ROUTE_ID1));
- assertTrue(TextUtils.equals(FEATURE_SAMPLE, controller.getRouteFeature()));
controllers.add(controller);
onSessionCreatedLatch.countDown();
}
@@ -617,7 +593,7 @@
try {
mRouter2.registerSessionCallback(mExecutor, sessionCallback);
- mRouter2.requestCreateSession(routeToCreateSessionWith, FEATURE_SAMPLE);
+ mRouter2.requestCreateSession(routeToCreateSessionWith);
assertTrue(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
assertEquals(1, controllers.size());
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java
index 3f59736..704dca0 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java
@@ -57,65 +57,32 @@
public void testBuilderConstructorWithInvalidValues() {
final String nullId = null;
final String nullClientPackageName = null;
- final String nullRouteFeature = null;
final String emptyId = "";
// Note: An empty string as client package name is valid.
- final String emptyRouteFeature = "";
final String validId = TEST_ID;
final String validClientPackageName = TEST_CLIENT_PACKAGE_NAME;
- final String validRouteFeature = TEST_ROUTE_FEATURE;
// ID is invalid
assertThrows(IllegalArgumentException.class, () -> new RoutingSessionInfo.Builder(
- nullId, validClientPackageName, validRouteFeature));
+ nullId, validClientPackageName));
assertThrows(IllegalArgumentException.class, () -> new RoutingSessionInfo.Builder(
- emptyId, validClientPackageName, validRouteFeature));
+ emptyId, validClientPackageName));
// client package name is invalid (null)
assertThrows(NullPointerException.class, () -> new RoutingSessionInfo.Builder(
- validId, nullClientPackageName, validRouteFeature));
+ validId, nullClientPackageName));
- // route feature is invalid
+ // Both are invalid
assertThrows(IllegalArgumentException.class, () -> new RoutingSessionInfo.Builder(
- validId, validClientPackageName, nullRouteFeature));
+ nullId, nullClientPackageName));
assertThrows(IllegalArgumentException.class, () -> new RoutingSessionInfo.Builder(
- validId, validClientPackageName, emptyRouteFeature));
+ emptyId, nullClientPackageName));
+ }
- // Two arguments are invalid - (1) ID and clientPackageName
- assertThrows(IllegalArgumentException.class, () -> new RoutingSessionInfo.Builder(
- nullId, nullClientPackageName, validRouteFeature));
- assertThrows(IllegalArgumentException.class, () -> new RoutingSessionInfo.Builder(
- emptyId, nullClientPackageName, validRouteFeature));
-
- // Two arguments are invalid - (2) ID and routeFeature
- assertThrows(IllegalArgumentException.class, () -> new RoutingSessionInfo.Builder(
- nullId, validClientPackageName, nullRouteFeature));
- assertThrows(IllegalArgumentException.class, () -> new RoutingSessionInfo.Builder(
- nullId, validClientPackageName, emptyRouteFeature));
- assertThrows(IllegalArgumentException.class, () -> new RoutingSessionInfo.Builder(
- emptyId, validClientPackageName, nullRouteFeature));
- assertThrows(IllegalArgumentException.class, () -> new RoutingSessionInfo.Builder(
- emptyId, validClientPackageName, emptyRouteFeature));
-
- // Two arguments are invalid - (3) clientPackageName and routeFeature
- // Note that this throws NullPointerException.
- assertThrows(NullPointerException.class, () -> new RoutingSessionInfo.Builder(
- validId, nullClientPackageName, nullRouteFeature));
- assertThrows(NullPointerException.class, () -> new RoutingSessionInfo.Builder(
- validId, nullClientPackageName, emptyRouteFeature));
-
- // All arguments are invalid
- assertThrows(IllegalArgumentException.class, () -> new RoutingSessionInfo.Builder(
- nullId, nullClientPackageName, nullRouteFeature));
- assertThrows(IllegalArgumentException.class, () -> new RoutingSessionInfo.Builder(
- nullId, nullClientPackageName, emptyRouteFeature));
- assertThrows(IllegalArgumentException.class, () -> new RoutingSessionInfo.Builder(
- emptyId, nullClientPackageName, nullRouteFeature));
- assertThrows(IllegalArgumentException.class, () -> new RoutingSessionInfo.Builder(
- emptyId, nullClientPackageName, emptyRouteFeature));
-
+ @Test
+ public void testBuilderCopyConstructorWithNull() {
// Null RouteInfo (1-argument constructor)
final RoutingSessionInfo nullRoutingSessionInfo = null;
assertThrows(NullPointerException.class,
@@ -127,13 +94,13 @@
// An empty string for client package name is valid. (for unknown cases)
// Creating builder with it should not throw any exception.
RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder(
- TEST_ID, "" /* clientPackageName*/, TEST_ROUTE_FEATURE);
+ TEST_ID, "" /* clientPackageName*/);
}
@Test
public void testBuilderBuildWithEmptySelectedRoutesThrowsIAE() {
RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder(
- TEST_ID, TEST_CLIENT_PACKAGE_NAME, TEST_ROUTE_FEATURE);
+ TEST_ID, TEST_CLIENT_PACKAGE_NAME);
// Note: Calling build() without adding any selected routes.
assertThrows(IllegalArgumentException.class, () -> builder.build());
}
@@ -141,7 +108,7 @@
@Test
public void testBuilderAddRouteMethodsWithIllegalArgumentsThrowsIAE() {
RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder(
- TEST_ID, TEST_CLIENT_PACKAGE_NAME, TEST_ROUTE_FEATURE);
+ TEST_ID, TEST_CLIENT_PACKAGE_NAME);
final String nullRouteId = null;
final String emptyRouteId = "";
@@ -168,7 +135,7 @@
@Test
public void testBuilderRemoveRouteMethodsWithIllegalArgumentsThrowsIAE() {
RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder(
- TEST_ID, TEST_CLIENT_PACKAGE_NAME, TEST_ROUTE_FEATURE);
+ TEST_ID, TEST_CLIENT_PACKAGE_NAME);
final String nullRouteId = null;
final String emptyRouteId = "";
@@ -198,7 +165,7 @@
controlHints.putString(TEST_KEY, TEST_VALUE);
RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder(
- TEST_ID, TEST_CLIENT_PACKAGE_NAME, TEST_ROUTE_FEATURE)
+ TEST_ID, TEST_CLIENT_PACKAGE_NAME)
.addSelectedRoute(TEST_ROUTE_ID_0)
.addSelectedRoute(TEST_ROUTE_ID_1)
.addSelectableRoute(TEST_ROUTE_ID_2)
@@ -212,7 +179,6 @@
assertEquals(TEST_ID, sessionInfo.getId());
assertEquals(TEST_CLIENT_PACKAGE_NAME, sessionInfo.getClientPackageName());
- assertEquals(TEST_ROUTE_FEATURE, sessionInfo.getRouteFeature());
assertEquals(2, sessionInfo.getSelectedRoutes().size());
assertEquals(TEST_ROUTE_ID_0, sessionInfo.getSelectedRoutes().get(0));
@@ -239,7 +205,7 @@
@Test
public void testBuilderAddRouteMethodsWithBuilderCopyConstructor() {
RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder(
- TEST_ID, TEST_CLIENT_PACKAGE_NAME, TEST_ROUTE_FEATURE)
+ TEST_ID, TEST_CLIENT_PACKAGE_NAME)
.addSelectedRoute(TEST_ROUTE_ID_0)
.addSelectableRoute(TEST_ROUTE_ID_2)
.addDeselectableRoute(TEST_ROUTE_ID_4)
@@ -273,7 +239,7 @@
@Test
public void testBuilderRemoveRouteMethods() {
RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder(
- TEST_ID, TEST_CLIENT_PACKAGE_NAME, TEST_ROUTE_FEATURE)
+ TEST_ID, TEST_CLIENT_PACKAGE_NAME)
.addSelectedRoute(TEST_ROUTE_ID_0)
.addSelectedRoute(TEST_ROUTE_ID_1)
.removeSelectedRoute(TEST_ROUTE_ID_1)
@@ -308,7 +274,7 @@
@Test
public void testBuilderRemoveRouteMethodsWithBuilderCopyConstructor() {
RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder(
- TEST_ID, TEST_CLIENT_PACKAGE_NAME, TEST_ROUTE_FEATURE)
+ TEST_ID, TEST_CLIENT_PACKAGE_NAME)
.addSelectedRoute(TEST_ROUTE_ID_0)
.addSelectedRoute(TEST_ROUTE_ID_1)
.addSelectableRoute(TEST_ROUTE_ID_2)
@@ -342,7 +308,7 @@
@Test
public void testBuilderClearRouteMethods() {
RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder(
- TEST_ID, TEST_CLIENT_PACKAGE_NAME, TEST_ROUTE_FEATURE)
+ TEST_ID, TEST_CLIENT_PACKAGE_NAME)
.addSelectedRoute(TEST_ROUTE_ID_0)
.addSelectedRoute(TEST_ROUTE_ID_1)
.clearSelectedRoutes()
@@ -374,7 +340,7 @@
@Test
public void testBuilderClearRouteMethodsWithBuilderCopyConstructor() {
RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder(
- TEST_ID, TEST_CLIENT_PACKAGE_NAME, TEST_ROUTE_FEATURE)
+ TEST_ID, TEST_CLIENT_PACKAGE_NAME)
.addSelectedRoute(TEST_ROUTE_ID_0)
.addSelectedRoute(TEST_ROUTE_ID_1)
.addSelectableRoute(TEST_ROUTE_ID_2)
@@ -408,7 +374,7 @@
controlHints.putString(TEST_KEY, TEST_VALUE);
RoutingSessionInfo sessionInfo1 = new RoutingSessionInfo.Builder(
- TEST_ID, TEST_CLIENT_PACKAGE_NAME, TEST_ROUTE_FEATURE)
+ TEST_ID, TEST_CLIENT_PACKAGE_NAME)
.addSelectedRoute(TEST_ROUTE_ID_0)
.addSelectedRoute(TEST_ROUTE_ID_1)
.addSelectableRoute(TEST_ROUTE_ID_2)
@@ -421,7 +387,7 @@
.build();
RoutingSessionInfo sessionInfo2 = new RoutingSessionInfo.Builder(
- TEST_ID, TEST_CLIENT_PACKAGE_NAME, TEST_ROUTE_FEATURE)
+ TEST_ID, TEST_CLIENT_PACKAGE_NAME)
.addSelectedRoute(TEST_ROUTE_ID_0)
.addSelectedRoute(TEST_ROUTE_ID_1)
.addSelectableRoute(TEST_ROUTE_ID_2)
@@ -443,7 +409,7 @@
controlHints.putString(TEST_KEY, TEST_VALUE);
RoutingSessionInfo sessionInfo1 = new RoutingSessionInfo.Builder(
- TEST_ID, TEST_CLIENT_PACKAGE_NAME, TEST_ROUTE_FEATURE)
+ TEST_ID, TEST_CLIENT_PACKAGE_NAME)
.addSelectedRoute(TEST_ROUTE_ID_0)
.addSelectedRoute(TEST_ROUTE_ID_1)
.addSelectableRoute(TEST_ROUTE_ID_2)
@@ -467,7 +433,7 @@
controlHints.putString(TEST_KEY, TEST_VALUE);
RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder(
- TEST_ID, TEST_CLIENT_PACKAGE_NAME, TEST_ROUTE_FEATURE)
+ TEST_ID, TEST_CLIENT_PACKAGE_NAME)
.addSelectedRoute(TEST_ROUTE_ID_0)
.addSelectedRoute(TEST_ROUTE_ID_1)
.addSelectableRoute(TEST_ROUTE_ID_2)
@@ -530,7 +496,7 @@
controlHints.putString(TEST_KEY, TEST_VALUE);
RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder(
- TEST_ID, TEST_CLIENT_PACKAGE_NAME, TEST_ROUTE_FEATURE)
+ TEST_ID, TEST_CLIENT_PACKAGE_NAME)
.addSelectedRoute(TEST_ROUTE_ID_0)
.addSelectedRoute(TEST_ROUTE_ID_1)
.addSelectableRoute(TEST_ROUTE_ID_2)
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index dc393d1..e9db9c8 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -16,6 +16,8 @@
package com.android.server;
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
@@ -83,6 +85,7 @@
import com.android.internal.content.PackageMonitor;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
@@ -459,8 +462,10 @@
Log.d(TAG, "[u" + userId + "] location enabled = " + isLocationEnabledForUser(userId));
}
- Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION);
- intent.putExtra(LocationManager.EXTRA_LOCATION_ENABLED, isLocationEnabledForUser(userId));
+ Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION)
+ .putExtra(LocationManager.EXTRA_LOCATION_ENABLED, isLocationEnabledForUser(userId))
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
for (LocationProviderManager manager : mProviderManagers) {
@@ -929,9 +934,11 @@
// update LOCATION_PROVIDERS_ALLOWED for best effort backwards compatibility
mSettingsStore.setLocationProviderAllowed(mName, useable, userId);
- Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION);
- intent.putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName);
- intent.putExtra(LocationManager.EXTRA_PROVIDER_ENABLED, useable);
+ Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION)
+ .putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName)
+ .putExtra(LocationManager.EXTRA_PROVIDER_ENABLED, useable)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
}
@@ -1396,20 +1403,19 @@
private String getResolutionPermission(int resolutionLevel) {
switch (resolutionLevel) {
case RESOLUTION_LEVEL_FINE:
- return android.Manifest.permission.ACCESS_FINE_LOCATION;
+ return ACCESS_FINE_LOCATION;
case RESOLUTION_LEVEL_COARSE:
- return android.Manifest.permission.ACCESS_COARSE_LOCATION;
+ return ACCESS_COARSE_LOCATION;
default:
return null;
}
}
private int getAllowedResolutionLevel(int pid, int uid) {
- if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
- pid, uid) == PERMISSION_GRANTED) {
+ if (mContext.checkPermission(ACCESS_FINE_LOCATION, pid, uid) == PERMISSION_GRANTED) {
return RESOLUTION_LEVEL_FINE;
- } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
- pid, uid) == PERMISSION_GRANTED) {
+ } else if (mContext.checkPermission(ACCESS_COARSE_LOCATION, pid, uid)
+ == PERMISSION_GRANTED) {
return RESOLUTION_LEVEL_COARSE;
} else {
return RESOLUTION_LEVEL_NONE;
@@ -1420,59 +1426,28 @@
return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
}
- private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
- if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
- throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
- }
+ private boolean checkCallingOrSelfLocationPermission() {
+ return mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) == PERMISSION_GRANTED
+ || mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
+ == PERMISSION_GRANTED;
}
- @GuardedBy("mLock")
- private int getMinimumResolutionLevelForProviderUseLocked(String provider) {
- if (GPS_PROVIDER.equals(provider) || PASSIVE_PROVIDER.equals(provider)) {
- // gps and passive providers require FINE permission
- return RESOLUTION_LEVEL_FINE;
- } else if (NETWORK_PROVIDER.equals(provider) || FUSED_PROVIDER.equals(provider)) {
- // network and fused providers are ok with COARSE or FINE
- return RESOLUTION_LEVEL_COARSE;
- } else {
- for (LocationProviderManager lp : mProviderManagers) {
- if (!lp.getName().equals(provider)) {
- continue;
- }
-
- ProviderProperties properties = lp.getProperties();
- if (properties != null) {
- if (properties.mRequiresSatellite) {
- // provider requiring satellites require FINE permission
- return RESOLUTION_LEVEL_FINE;
- } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
- // provider requiring network and or cell require COARSE or FINE
- return RESOLUTION_LEVEL_COARSE;
- }
- }
- }
+ private void enforceCallingOrSelfLocationPermission() {
+ if (checkCallingOrSelfLocationPermission()) {
+ return;
}
- return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
+ throw new SecurityException("uid " + Binder.getCallingUid() + " does not have "
+ + ACCESS_COARSE_LOCATION + " or " + ACCESS_FINE_LOCATION + ".");
}
- @GuardedBy("mLock")
- private void checkResolutionLevelIsSufficientForProviderUseLocked(int allowedResolutionLevel,
- String providerName) {
- int requiredResolutionLevel = getMinimumResolutionLevelForProviderUseLocked(providerName);
- if (allowedResolutionLevel < requiredResolutionLevel) {
- switch (requiredResolutionLevel) {
- case RESOLUTION_LEVEL_FINE:
- throw new SecurityException("\"" + providerName + "\" location provider " +
- "requires ACCESS_FINE_LOCATION permission.");
- case RESOLUTION_LEVEL_COARSE:
- throw new SecurityException("\"" + providerName + "\" location provider " +
- "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
- default:
- throw new SecurityException("Insufficient permission for \"" + providerName +
- "\" location provider.");
- }
+ private void enforceCallingOrSelfPackageName(String packageName) {
+ int uid = Binder.getCallingUid();
+ if (ArrayUtils.contains(mPackageManager.getPackagesForUid(uid), packageName)) {
+ return;
}
+
+ throw new SecurityException("invalid package \"" + packageName + "\" for uid " + uid);
}
public static int resolutionLevelToOp(int allowedResolutionLevel) {
@@ -1548,7 +1523,10 @@
*/
@Override
public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
- int allowedResolutionLevel = getCallerAllowedResolutionLevel();
+ if (!checkCallingOrSelfLocationPermission()) {
+ return Collections.emptyList();
+ }
+
synchronized (mLock) {
ArrayList<String> providers = new ArrayList<>(mProviderManagers.size());
for (LocationProviderManager manager : mProviderManagers) {
@@ -1556,9 +1534,6 @@
if (FUSED_PROVIDER.equals(name)) {
continue;
}
- if (allowedResolutionLevel < getMinimumResolutionLevelForProviderUseLocked(name)) {
- continue;
- }
if (enabledOnly && !manager.isUseable()) {
continue;
}
@@ -2002,33 +1977,18 @@
return sanitizedRequest;
}
- private void checkPackageName(String packageName) {
- if (packageName == null) {
- throw new SecurityException("invalid package name: " + null);
- }
- int uid = Binder.getCallingUid();
- String[] packages = mPackageManager.getPackagesForUid(uid);
- if (packages == null) {
- throw new SecurityException("invalid UID " + uid);
- }
- for (String pkg : packages) {
- if (packageName.equals(pkg)) return;
- }
- throw new SecurityException("invalid package name: " + packageName);
- }
-
@Override
public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
PendingIntent intent, String packageName, String featureId,
String listenerIdentifier) {
Objects.requireNonNull(listenerIdentifier);
+ enforceCallingOrSelfLocationPermission();
+ enforceCallingOrSelfPackageName(packageName);
+
synchronized (mLock) {
if (request == null) request = DEFAULT_LOCATION_REQUEST;
- checkPackageName(packageName);
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
- checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
- request.getProvider());
WorkSource workSource = request.getWorkSource();
if (workSource != null && !workSource.isEmpty()) {
mContext.enforceCallingOrSelfPermission(
@@ -2135,7 +2095,7 @@
@Override
public void removeUpdates(ILocationListener listener, PendingIntent intent,
String packageName) {
- checkPackageName(packageName);
+ enforceCallingOrSelfPackageName(packageName);
int pid = Binder.getCallingPid();
int uid = Binder.getCallingUid();
@@ -2197,12 +2157,12 @@
@Override
public Location getLastLocation(LocationRequest r, String packageName, String featureId) {
+ enforceCallingOrSelfLocationPermission();
+ enforceCallingOrSelfPackageName(packageName);
+
synchronized (mLock) {
LocationRequest request = r != null ? r : DEFAULT_LOCATION_REQUEST;
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
- checkPackageName(packageName);
- checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
- request.getProvider());
// no need to sanitize this request, as only the provider name is used
final int pid = Binder.getCallingPid();
@@ -2348,7 +2308,7 @@
public boolean injectLocation(Location location) {
mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
"Location Hardware permission not granted to inject location");
- mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
+ mContext.enforceCallingPermission(ACCESS_FINE_LOCATION,
"Access Fine Location permission not granted to inject Location");
synchronized (mLock) {
@@ -2374,17 +2334,14 @@
String packageName, String featureId, String listenerIdentifier) {
Objects.requireNonNull(listenerIdentifier);
+ mContext.enforceCallingOrSelfPermission(ACCESS_FINE_LOCATION, null);
+ enforceCallingOrSelfPackageName(packageName);
+
if (request == null) request = DEFAULT_LOCATION_REQUEST;
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
- checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
if (intent == null) {
throw new IllegalArgumentException("invalid pending intent: " + null);
}
- checkPackageName(packageName);
- synchronized (mLock) {
- checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
- request.getProvider());
- }
// Require that caller can manage given document
boolean callerHasLocationHardwarePermission =
mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
@@ -2430,7 +2387,7 @@
if (intent == null) {
throw new IllegalArgumentException("invalid pending intent: " + null);
}
- checkPackageName(packageName);
+ enforceCallingOrSelfPackageName(packageName);
if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
@@ -2517,36 +2474,30 @@
@Override
public boolean sendExtraCommand(String providerName, String command, Bundle extras) {
- if (providerName == null) {
- // throw NullPointerException to remain compatible with previous implementation
- throw new NullPointerException();
- }
+ Objects.requireNonNull(providerName);
+ Objects.requireNonNull(command);
mContext.enforceCallingOrSelfPermission(
Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, null);
+ enforceCallingOrSelfLocationPermission();
- synchronized (mLock) {
- checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
- providerName);
+ mLocationUsageLogger.logLocationApiUsage(
+ LocationStatsEnums.USAGE_STARTED,
+ LocationStatsEnums.API_SEND_EXTRA_COMMAND,
+ providerName);
- mLocationUsageLogger.logLocationApiUsage(
- LocationStatsEnums.USAGE_STARTED,
- LocationStatsEnums.API_SEND_EXTRA_COMMAND,
- providerName);
-
- LocationProviderManager manager = getLocationProviderManager(providerName);
- if (manager != null) {
- manager.sendExtraCommand(Binder.getCallingUid(), Binder.getCallingPid(), command,
- extras);
- }
-
- mLocationUsageLogger.logLocationApiUsage(
- LocationStatsEnums.USAGE_ENDED,
- LocationStatsEnums.API_SEND_EXTRA_COMMAND,
- providerName);
-
- return true;
+ LocationProviderManager manager = getLocationProviderManager(providerName);
+ if (manager != null) {
+ manager.sendExtraCommand(Binder.getCallingUid(), Binder.getCallingPid(), command,
+ extras);
}
+
+ mLocationUsageLogger.logLocationApiUsage(
+ LocationStatsEnums.USAGE_ENDED,
+ LocationStatsEnums.API_SEND_EXTRA_COMMAND,
+ providerName);
+
+ return true;
}
@Override
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index 408c1c9..b186771 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -49,8 +49,7 @@
mCallback = callback;
}
- public abstract void requestCreateSession(String packageName, String routeId,
- String routeType, long requestId);
+ public abstract void requestCreateSession(String packageName, String routeId, long requestId);
public abstract void releaseSession(String sessionId);
public abstract void selectRoute(String sessionId, String routeId);
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
index 3840d02..4b992be 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
@@ -73,11 +73,9 @@
}
@Override
- public void requestCreateSession(String packageName, String routeId, String routeType,
- long requestId) {
+ public void requestCreateSession(String packageName, String routeId, long requestId) {
if (mConnectionReady) {
- mActiveConnection.requestCreateSession(packageName, routeId, routeType,
- requestId);
+ mActiveConnection.requestCreateSession(packageName, routeId, requestId);
updateBinding();
}
}
@@ -429,11 +427,9 @@
mClient.dispose();
}
- public void requestCreateSession(String packageName, String routeId, String routeType,
- long requestId) {
+ public void requestCreateSession(String packageName, String routeId, long requestId) {
try {
- mProvider.requestCreateSession(packageName, routeId,
- routeType, requestId);
+ mProvider.requestCreateSession(packageName, routeId, requestId);
} catch (RemoteException ex) {
Slog.e(TAG, "Failed to deliver request to create a session.", ex);
}
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 161afb5..45d50b3 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -178,18 +178,14 @@
}
public void requestCreateSession(IMediaRouter2Client client, MediaRoute2Info route,
- String routeFeature, int requestId) {
+ int requestId) {
Objects.requireNonNull(client, "client must not be null");
Objects.requireNonNull(route, "route must not be null");
- if (TextUtils.isEmpty(routeFeature)) {
- throw new IllegalArgumentException("routeFeature must not be empty");
- }
final long token = Binder.clearCallingIdentity();
-
try {
synchronized (mLock) {
- requestCreateSessionLocked(client, route, routeFeature, requestId);
+ requestCreateSessionLocked(client, route, requestId);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -450,7 +446,7 @@
}
private void requestCreateSessionLocked(@NonNull IMediaRouter2Client client,
- @NonNull MediaRoute2Info route, @NonNull String routeFeature, long requestId) {
+ @NonNull MediaRoute2Info route, long requestId) {
final IBinder binder = client.asBinder();
final Client2Record clientRecord = mAllClientRecords.get(binder);
@@ -462,8 +458,7 @@
if (clientRecord != null) {
clientRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::requestCreateSessionOnHandler,
- clientRecord.mUserRecord.mHandler,
- clientRecord, route, routeFeature, requestId));
+ clientRecord.mUserRecord.mHandler, clientRecord, route, requestId));
}
}
@@ -624,7 +619,7 @@
if (clientRecord != null && managerRecord.mTrusted) {
//TODO: select route feature properly
requestCreateSessionLocked(clientRecord.mClient, route,
- route.getFeatures().get(0), uniqueRequestId);
+ uniqueRequestId);
}
}
}
@@ -985,7 +980,7 @@
}
private void requestCreateSessionOnHandler(Client2Record clientRecord,
- MediaRoute2Info route, String routeFeature, long requestId) {
+ MediaRoute2Info route, long requestId) {
final MediaRoute2Provider provider = findProvider(route.getProviderId());
if (provider == null) {
@@ -995,20 +990,13 @@
return;
}
- if (!route.getFeatures().contains(routeFeature)) {
- Slog.w(TAG, "Ignoring session creation request since the given route=" + route
- + " doesn't support the given feature=" + routeFeature);
- notifySessionCreationFailed(clientRecord, toClientRequestId(requestId));
- return;
- }
-
// TODO: Apply timeout for each request (How many seconds should we wait?)
- SessionCreationRequest request = new SessionCreationRequest(
- clientRecord, route, routeFeature, requestId);
+ SessionCreationRequest request =
+ new SessionCreationRequest(clientRecord, route, requestId);
mSessionCreationRequests.add(request);
provider.requestCreateSession(clientRecord.mPackageName, route.getOriginalId(),
- routeFeature, requestId);
+ requestId);
}
private void selectRouteOnHandler(@NonNull Client2Record clientRecord,
@@ -1173,15 +1161,11 @@
}
String originalRouteId = matchingRequest.mRoute.getId();
- String originalRouteFeature = matchingRequest.mRouteFeature;
Client2Record client2Record = matchingRequest.mClientRecord;
- if (!sessionInfo.getSelectedRoutes().contains(originalRouteId)
- || !TextUtils.equals(originalRouteFeature,
- sessionInfo.getRouteFeature())) {
+ if (!sessionInfo.getSelectedRoutes().contains(originalRouteId)) {
Slog.w(TAG, "Created session doesn't match the original request."
+ " originalRouteId=" + originalRouteId
- + ", originalRouteFeature=" + originalRouteFeature
+ ", requestId=" + requestId + ", sessionInfo=" + sessionInfo);
notifySessionCreationFailed(matchingRequest.mClientRecord,
toClientRequestId(requestId));
@@ -1470,15 +1454,12 @@
final class SessionCreationRequest {
public final Client2Record mClientRecord;
public final MediaRoute2Info mRoute;
- public final String mRouteFeature;
public final long mRequestId;
SessionCreationRequest(@NonNull Client2Record clientRecord,
- @NonNull MediaRoute2Info route,
- @NonNull String routeFeature, long requestId) {
+ @NonNull MediaRoute2Info route, long requestId) {
mClientRecord = clientRecord;
mRoute = route;
- mRouteFeature = routeFeature;
mRequestId = requestId;
}
}
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index c80a898..aad9636 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -460,8 +460,8 @@
// Binder call
@Override
public void requestCreateSession(IMediaRouter2Client client, MediaRoute2Info route,
- String routeType, int requestId) {
- mService2.requestCreateSession(client, route, routeType, requestId);
+ int requestId) {
+ mService2.requestCreateSession(client, route, requestId);
}
// Binder call
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index 6695227..3759ba9 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -96,8 +96,7 @@
}
@Override
- public void requestCreateSession(String packageName, String routeId, String routeType,
- long requestId) {
+ public void requestCreateSession(String packageName, String routeId, long requestId) {
// Do nothing
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 6331dd4..b1c38d1 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -400,10 +400,10 @@
} finally {
IoUtils.closeQuietly(fis);
}
- // After all of the sessions were loaded, they are ready to be sealed and validated
+ // Re-sealing the sealed sessions.
for (int i = 0; i < mSessions.size(); ++i) {
PackageInstallerSession session = mSessions.valueAt(i);
- session.sealAndValidateIfNecessary();
+ session.sealIfNecessary();
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 165bdeb..71555c9 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1374,15 +1374,13 @@
}
/**
- * If session should be sealed, then it's sealed to prevent further modification
- * and then it's validated.
- *
- * If the session was sealed but something went wrong then it's destroyed.
+ * If session should be sealed, then it's sealed to prevent further modification.
+ * If the session can't be sealed then it's destroyed.
*
* <p> This is meant to be called after all of the sessions are loaded and added to
* PackageInstallerService
*/
- void sealAndValidateIfNecessary() {
+ void sealIfNecessary() {
synchronized (mLock) {
if (!mShouldBeSealed || isStagedAndInTerminalState()) {
return;
@@ -1391,9 +1389,7 @@
List<PackageInstallerSession> childSessions = getChildSessions();
synchronized (mLock) {
try {
- sealAndValidateLocked(childSessions);
- } catch (StreamingException e) {
- Slog.e(TAG, "Streaming failed", e);
+ sealLocked(childSessions);
} catch (PackageManagerException e) {
Slog.e(TAG, "Package not valid", e);
}
diff --git a/services/core/java/com/android/server/stats/IonMemoryUtil.java b/services/core/java/com/android/server/stats/pull/IonMemoryUtil.java
similarity index 93%
rename from services/core/java/com/android/server/stats/IonMemoryUtil.java
rename to services/core/java/com/android/server/stats/pull/IonMemoryUtil.java
index c9be96f..fde0a59 100644
--- a/services/core/java/com/android/server/stats/IonMemoryUtil.java
+++ b/services/core/java/com/android/server/stats/pull/IonMemoryUtil.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.server.stats;
+package com.android.server.stats.pull;
import android.os.FileUtils;
import android.util.Slog;
@@ -30,8 +30,11 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-/** Utility methods for reading ion memory stats. */
-final class IonMemoryUtil {
+/**
+ * Utility methods for reading ion memory stats.
+ * TODO: Consider making package private after puller migration
+ */
+public final class IonMemoryUtil {
private static final String TAG = "IonMemoryUtil";
/** Path to debugfs file for the system ion heap. */
@@ -50,7 +53,7 @@
* Returns value of the total size in bytes of the system ion heap from
* /sys/kernel/debug/ion/heaps/system.
*/
- static long readSystemIonHeapSizeFromDebugfs() {
+ public static long readSystemIonHeapSizeFromDebugfs() {
return parseIonHeapSizeFromDebugfs(readFile(DEBUG_SYSTEM_ION_HEAP_FILE));
}
@@ -78,7 +81,7 @@
* Returns values of allocation sizes in bytes on the system ion heap from
* /sys/kernel/debug/ion/heaps/system.
*/
- static List<IonAllocations> readProcessSystemIonHeapSizesFromDebugfs() {
+ public static List<IonAllocations> readProcessSystemIonHeapSizesFromDebugfs() {
return parseProcessIonHeapSizesFromDebugfs(readFile(DEBUG_SYSTEM_ION_HEAP_FILE));
}
@@ -130,7 +133,7 @@
}
/** Summary information about process ion allocations. */
- static final class IonAllocations {
+ public static final class IonAllocations {
/** PID these allocations belong to. */
public int pid;
/** Size of all individual allocations added together. */
diff --git a/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java b/services/core/java/com/android/server/stats/pull/ProcfsMemoryUtil.java
similarity index 89%
rename from services/core/java/com/android/server/stats/ProcfsMemoryUtil.java
rename to services/core/java/com/android/server/stats/pull/ProcfsMemoryUtil.java
index c1eacce..638dfd2 100644
--- a/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java
+++ b/services/core/java/com/android/server/stats/pull/ProcfsMemoryUtil.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.server.stats;
+package com.android.server.stats.pull;
import static android.os.Process.PROC_OUT_STRING;
@@ -22,7 +22,7 @@
import java.util.function.BiConsumer;
-final class ProcfsMemoryUtil {
+public final class ProcfsMemoryUtil {
private static final int[] CMDLINE_OUT = new int[] { PROC_OUT_STRING };
private static final String[] STATUS_KEYS = new String[] {
"Uid:",
@@ -39,7 +39,7 @@
* VmSwap fields in /proc/pid/status in kilobytes or null if not available.
*/
@Nullable
- static MemorySnapshot readMemorySnapshotFromProcfs(int pid) {
+ public static MemorySnapshot readMemorySnapshotFromProcfs(int pid) {
long[] output = new long[STATUS_KEYS.length];
output[0] = -1;
Process.readProcLines("/proc/" + pid + "/status", STATUS_KEYS, output);
@@ -63,7 +63,7 @@
* Returns content of /proc/pid/cmdline (e.g. /system/bin/statsd) or an empty string
* if the file is not available.
*/
- static String readCmdlineFromProcfs(int pid) {
+ public static String readCmdlineFromProcfs(int pid) {
String[] cmdline = new String[1];
if (!Process.readProcFile("/proc/" + pid + "/cmdline", CMDLINE_OUT, cmdline, null, null)) {
return "";
@@ -71,7 +71,7 @@
return cmdline[0];
}
- static void forEachPid(BiConsumer<Integer, String> func) {
+ public static void forEachPid(BiConsumer<Integer, String> func) {
int[] pids = new int[1024];
pids = Process.getPids("/proc", pids);
for (int pid : pids) {
@@ -86,7 +86,7 @@
}
}
- static final class MemorySnapshot {
+ public static final class MemorySnapshot {
public int uid;
public int rssHighWaterMarkInKilobytes;
public int rssInKilobytes;
diff --git a/services/core/java/com/android/server/stats/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
similarity index 74%
rename from services/core/java/com/android/server/stats/StatsPullAtomService.java
rename to services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index f78330e..3bc860a 100644
--- a/services/core/java/com/android/server/stats/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.stats;
+package com.android.server.stats.pull;
import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
@@ -26,11 +26,11 @@
import static android.os.storage.VolumeInfo.TYPE_PUBLIC;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
-import static com.android.server.stats.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
-import static com.android.server.stats.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
-import static com.android.server.stats.ProcfsMemoryUtil.forEachPid;
-import static com.android.server.stats.ProcfsMemoryUtil.readCmdlineFromProcfs;
-import static com.android.server.stats.ProcfsMemoryUtil.readMemorySnapshotFromProcfs;
+import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
+import static com.android.server.stats.pull.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
+import static com.android.server.stats.pull.ProcfsMemoryUtil.forEachPid;
+import static com.android.server.stats.pull.ProcfsMemoryUtil.readCmdlineFromProcfs;
+import static com.android.server.stats.pull.ProcfsMemoryUtil.readMemorySnapshotFromProcfs;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -142,8 +142,8 @@
import com.android.server.am.MemoryStatUtil.MemoryStat;
import com.android.server.notification.NotificationManagerService;
import com.android.server.role.RoleManagerInternal;
-import com.android.server.stats.IonMemoryUtil.IonAllocations;
-import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot;
+import com.android.server.stats.pull.IonMemoryUtil.IonAllocations;
+import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot;
import com.android.server.storage.DiskStatsFileLogger;
import com.android.server.storage.DiskStatsLoggingService;
@@ -270,8 +270,8 @@
registerProcessSystemIonHeapSize();
registerTemperature();
registerCoolingDevice();
- registerBinderCalls();
- registerBinderCallsExceptions();
+ registerBinderCallsStats();
+ registerBinderCallsStatsExceptions();
registerLooperStats();
registerDiskStats();
registerDirectoryUsage();
@@ -1004,35 +1004,227 @@
}
private void registerProcessMemoryState() {
- // No op.
+ int tagId = StatsLog.PROCESS_MEMORY_STATE;
+ PullAtomMetadata metadata = PullAtomMetadata.newBuilder()
+ .setAdditiveFields(new int[] {4, 5, 6, 7, 8})
+ .build();
+ mStatsManager.registerPullAtomCallback(
+ tagId,
+ metadata,
+ (atomTag, data) -> pullProcessMemoryState(atomTag, data),
+ BackgroundThread.getExecutor()
+ );
}
- private void pullProcessMemoryState() {
- // No op.
+ private int pullProcessMemoryState(int atomTag, List<StatsEvent> pulledData) {
+ List<ProcessMemoryState> processMemoryStates =
+ LocalServices.getService(ActivityManagerInternal.class)
+ .getMemoryStateForProcesses();
+ for (ProcessMemoryState processMemoryState : processMemoryStates) {
+ final MemoryStat memoryStat = readMemoryStatFromFilesystem(processMemoryState.uid,
+ processMemoryState.pid);
+ if (memoryStat == null) {
+ continue;
+ }
+ StatsEvent e = StatsEvent.newBuilder()
+ .setAtomId(atomTag)
+ .writeInt(processMemoryState.uid)
+ .writeString(processMemoryState.processName)
+ .writeInt(processMemoryState.oomScore)
+ .writeLong(memoryStat.pgfault)
+ .writeLong(memoryStat.pgmajfault)
+ .writeLong(memoryStat.rssInBytes)
+ .writeLong(memoryStat.cacheInBytes)
+ .writeLong(memoryStat.swapInBytes)
+ .writeLong(-1) // unused
+ .writeLong(-1) // unused
+ .writeInt(-1) // unused
+ .build();
+ pulledData.add(e);
+ }
+ return StatsManager.PULL_SUCCESS;
+ }
+
+ /**
+ * Which native processes to snapshot memory for.
+ *
+ * <p>Processes are matched by their cmdline in procfs. Example: cat /proc/pid/cmdline returns
+ * /system/bin/statsd for the stats daemon.
+ */
+ private static final Set<String> MEMORY_INTERESTING_NATIVE_PROCESSES = Sets.newHashSet(
+ "/system/bin/statsd", // Stats daemon.
+ "/system/bin/surfaceflinger",
+ "/system/bin/apexd", // APEX daemon.
+ "/system/bin/audioserver",
+ "/system/bin/cameraserver",
+ "/system/bin/drmserver",
+ "/system/bin/healthd",
+ "/system/bin/incidentd",
+ "/system/bin/installd",
+ "/system/bin/lmkd", // Low memory killer daemon.
+ "/system/bin/logd",
+ "media.codec",
+ "media.extractor",
+ "media.metrics",
+ "/system/bin/mediadrmserver",
+ "/system/bin/mediaserver",
+ "/system/bin/performanced",
+ "/system/bin/tombstoned",
+ "/system/bin/traced", // Perfetto.
+ "/system/bin/traced_probes", // Perfetto.
+ "webview_zygote",
+ "zygote",
+ "zygote64");
+
+ /**
+ * Lowest available uid for apps.
+ *
+ * <p>Used to quickly discard memory snapshots of the zygote forks from native process
+ * measurements.
+ */
+ private static final int MIN_APP_UID = 10_000;
+
+ private static boolean isAppUid(int uid) {
+ return uid >= MIN_APP_UID;
}
private void registerProcessMemoryHighWaterMark() {
- // No op.
+ int tagId = StatsLog.PROCESS_MEMORY_HIGH_WATER_MARK;
+ mStatsManager.registerPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ (atomTag, data) -> pullProcessMemoryHighWaterMark(atomTag, data),
+ BackgroundThread.getExecutor()
+ );
}
- private void pullProcessMemoryHighWaterMark() {
- // No op.
+ private int pullProcessMemoryHighWaterMark(int atomTag, List<StatsEvent> pulledData) {
+ List<ProcessMemoryState> managedProcessList =
+ LocalServices.getService(ActivityManagerInternal.class)
+ .getMemoryStateForProcesses();
+ for (ProcessMemoryState managedProcess : managedProcessList) {
+ final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(managedProcess.pid);
+ if (snapshot == null) {
+ continue;
+ }
+ StatsEvent e = StatsEvent.newBuilder()
+ .setAtomId(atomTag)
+ .writeInt(managedProcess.uid)
+ .writeString(managedProcess.processName)
+ // RSS high-water mark in bytes.
+ .writeLong(snapshot.rssHighWaterMarkInKilobytes * 1024L)
+ .writeInt(snapshot.rssHighWaterMarkInKilobytes)
+ .build();
+ pulledData.add(e);
+ }
+ forEachPid((pid, cmdLine) -> {
+ if (!MEMORY_INTERESTING_NATIVE_PROCESSES.contains(cmdLine)) {
+ return;
+ }
+ final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(pid);
+ if (snapshot == null) {
+ return;
+ }
+ // Sometimes we get here a process that is not included in the whitelist. It comes
+ // from forking the zygote for an app. We can ignore that sample because this process
+ // is collected by ProcessMemoryState.
+ if (isAppUid(snapshot.uid)) {
+ return;
+ }
+ StatsEvent e = StatsEvent.newBuilder()
+ .setAtomId(atomTag)
+ .writeInt(snapshot.uid)
+ .writeString(cmdLine)
+ // RSS high-water mark in bytes.
+ .writeLong(snapshot.rssHighWaterMarkInKilobytes * 1024L)
+ .writeInt(snapshot.rssHighWaterMarkInKilobytes)
+ .build();
+ pulledData.add(e);
+ });
+ // Invoke rss_hwm_reset binary to reset RSS HWM counters for all processes.
+ SystemProperties.set("sys.rss_hwm_reset.on", "1");
+ return StatsManager.PULL_SUCCESS;
}
private void registerProcessMemorySnapshot() {
- // No op.
+ int tagId = StatsLog.PROCESS_MEMORY_SNAPSHOT;
+ mStatsManager.registerPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ (atomTag, data) -> pullProcessMemorySnapshot(atomTag, data),
+ BackgroundThread.getExecutor()
+ );
}
- private void pullProcessMemorySnapshot() {
- // No op.
+ private int pullProcessMemorySnapshot(int atomTag, List<StatsEvent> pulledData) {
+ List<ProcessMemoryState> managedProcessList =
+ LocalServices.getService(ActivityManagerInternal.class)
+ .getMemoryStateForProcesses();
+ for (ProcessMemoryState managedProcess : managedProcessList) {
+ final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(managedProcess.pid);
+ if (snapshot == null) {
+ continue;
+ }
+ StatsEvent e = StatsEvent.newBuilder()
+ .writeInt(managedProcess.uid)
+ .writeString(managedProcess.processName)
+ .writeInt(managedProcess.pid)
+ .writeInt(managedProcess.oomScore)
+ .writeInt(snapshot.rssInKilobytes)
+ .writeInt(snapshot.anonRssInKilobytes)
+ .writeInt(snapshot.swapInKilobytes)
+ .writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes)
+ .build();
+ pulledData.add(e);
+ }
+ forEachPid((pid, cmdLine) -> {
+ if (!MEMORY_INTERESTING_NATIVE_PROCESSES.contains(cmdLine)) {
+ return;
+ }
+ final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(pid);
+ if (snapshot == null) {
+ return;
+ }
+ // Sometimes we get here a process that is not included in the whitelist. It comes
+ // from forking the zygote for an app. We can ignore that sample because this process
+ // is collected by ProcessMemoryState.
+ if (isAppUid(snapshot.uid)) {
+ return;
+ }
+ StatsEvent e = StatsEvent.newBuilder()
+ .setAtomId(atomTag)
+ .writeInt(snapshot.uid)
+ .writeString(cmdLine)
+ .writeInt(pid)
+ .writeInt(-1001) // Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1.
+ .writeInt(snapshot.rssInKilobytes)
+ .writeInt(snapshot.anonRssInKilobytes)
+ .writeInt(snapshot.swapInKilobytes)
+ .writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes)
+ .build();
+ pulledData.add(e);
+ });
+ return StatsManager.PULL_SUCCESS;
}
private void registerSystemIonHeapSize() {
- // No op.
+ int tagId = StatsLog.SYSTEM_ION_HEAP_SIZE;
+ mStatsManager.registerPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ (atomTag, data) -> pullSystemIonHeapSize(atomTag, data),
+ BackgroundThread.getExecutor()
+ );
}
- private void pullSystemIonHeapSize() {
- // No op.
+ private int pullSystemIonHeapSize(int atomTag, List<StatsEvent> pulledData) {
+ final long systemIonHeapSizeInBytes = readSystemIonHeapSizeFromDebugfs();
+ StatsEvent e = StatsEvent.newBuilder()
+ .setAtomId(atomTag)
+ .writeLong(systemIonHeapSizeInBytes)
+ .build();
+ pulledData.add(e);
+ return StatsManager.PULL_SUCCESS;
}
private void registerIonHeapSize() {
@@ -1056,43 +1248,182 @@
}
private void registerProcessSystemIonHeapSize() {
- // No op.
+ int tagId = StatsLog.PROCESS_SYSTEM_ION_HEAP_SIZE;
+ mStatsManager.registerPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ (atomTag, data) -> pullProcessSystemIonHeapSize(atomTag, data),
+ BackgroundThread.getExecutor()
+ );
}
- private void pullProcessSystemIonHeapSize() {
- // No op.
+ private int pullProcessSystemIonHeapSize(int atomTag, List<StatsEvent> pulledData) {
+ List<IonAllocations> result = readProcessSystemIonHeapSizesFromDebugfs();
+ for (IonAllocations allocations : result) {
+ StatsEvent e = StatsEvent.newBuilder()
+ .setAtomId(atomTag)
+ .writeInt(getUidForPid(allocations.pid))
+ .writeString(readCmdlineFromProcfs(allocations.pid))
+ .writeInt((int) (allocations.totalSizeInBytes / 1024))
+ .writeInt(allocations.count)
+ .writeInt((int) (allocations.maxSizeInBytes / 1024))
+ .build();
+ pulledData.add(e);
+ }
+ return StatsManager.PULL_SUCCESS;
}
private void registerTemperature() {
- // No op.
+ int tagId = StatsLog.TEMPERATURE;
+ mStatsManager.registerPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ (atomTag, data) -> pullTemperature(atomTag, data),
+ BackgroundThread.getExecutor()
+ );
}
- private void pullTemperature() {
- // No op.
+ private int pullTemperature(int atomTag, List<StatsEvent> pulledData) {
+ IThermalService thermalService = getIThermalService();
+ if (thermalService == null) {
+ return StatsManager.PULL_SKIP;
+ }
+ final long callingToken = Binder.clearCallingIdentity();
+ try {
+ List<Temperature> temperatures = thermalService.getCurrentTemperatures();
+ for (Temperature temp : temperatures) {
+ StatsEvent e = StatsEvent.newBuilder()
+ .setAtomId(atomTag)
+ .writeInt(temp.getType())
+ .writeString(temp.getName())
+ .writeInt((int) (temp.getValue() * 10))
+ .writeInt(temp.getStatus())
+ .build();
+ pulledData.add(e);
+ }
+ } catch (RemoteException e) {
+ // Should not happen.
+ Slog.e(TAG, "Disconnected from thermal service. Cannot pull temperatures.");
+ return StatsManager.PULL_SKIP;
+ } finally {
+ Binder.restoreCallingIdentity(callingToken);
+ }
+ return StatsManager.PULL_SUCCESS;
}
private void registerCoolingDevice() {
- // No op.
+ int tagId = StatsLog.COOLING_DEVICE;
+ mStatsManager.registerPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ (atomTag, data) -> pullCooldownDevice(atomTag, data),
+ BackgroundThread.getExecutor()
+ );
}
- private void pullCooldownDevice() {
- // No op.
+ private int pullCooldownDevice(int atomTag, List<StatsEvent> pulledData) {
+ IThermalService thermalService = getIThermalService();
+ if (thermalService == null) {
+ return StatsManager.PULL_SKIP;
+ }
+ final long callingToken = Binder.clearCallingIdentity();
+ try {
+ List<CoolingDevice> devices = thermalService.getCurrentCoolingDevices();
+ for (CoolingDevice device : devices) {
+ StatsEvent e = StatsEvent.newBuilder()
+ .setAtomId(atomTag)
+ .writeInt(device.getType())
+ .writeString(device.getName())
+ .writeInt((int) (device.getValue()))
+ .build();
+ pulledData.add(e);
+ }
+ } catch (RemoteException e) {
+ // Should not happen.
+ Slog.e(TAG, "Disconnected from thermal service. Cannot pull temperatures.");
+ return StatsManager.PULL_SKIP;
+ } finally {
+ Binder.restoreCallingIdentity(callingToken);
+ }
+ return StatsManager.PULL_SUCCESS;
}
- private void registerBinderCalls() {
- // No op.
+ private void registerBinderCallsStats() {
+ int tagId = StatsLog.BINDER_CALLS;
+ PullAtomMetadata metadata = PullAtomMetadata.newBuilder()
+ .setAdditiveFields(new int[] {4, 5, 6, 8, 12})
+ .build();
+ mStatsManager.registerPullAtomCallback(
+ tagId,
+ metadata,
+ (atomTag, data) -> pullBinderCallsStats(atomTag, data),
+ BackgroundThread.getExecutor()
+ );
}
- private void pullBinderCalls() {
- // No op.
+ private int pullBinderCallsStats(int atomTag, List<StatsEvent> pulledData) {
+ BinderCallsStatsService.Internal binderStats =
+ LocalServices.getService(BinderCallsStatsService.Internal.class);
+ if (binderStats == null) {
+ Slog.e(TAG, "failed to get binderStats");
+ return StatsManager.PULL_SKIP;
+ }
+
+ List<ExportedCallStat> callStats = binderStats.getExportedCallStats();
+ binderStats.reset();
+ for (ExportedCallStat callStat : callStats) {
+ StatsEvent e = StatsEvent.newBuilder()
+ .setAtomId(atomTag)
+ .writeInt(callStat.workSourceUid)
+ .writeString(callStat.className)
+ .writeString(callStat.methodName)
+ .writeLong(callStat.callCount)
+ .writeLong(callStat.exceptionCount)
+ .writeLong(callStat.latencyMicros)
+ .writeLong(callStat.maxLatencyMicros)
+ .writeLong(callStat.cpuTimeMicros)
+ .writeLong(callStat.maxCpuTimeMicros)
+ .writeLong(callStat.maxReplySizeBytes)
+ .writeLong(callStat.maxRequestSizeBytes)
+ .writeLong(callStat.recordedCallCount)
+ .writeInt(callStat.screenInteractive ? 1 : 0)
+ .writeInt(callStat.callingUid)
+ .build();
+ pulledData.add(e);
+ }
+ return StatsManager.PULL_SUCCESS;
}
- private void registerBinderCallsExceptions() {
- // No op.
+ private void registerBinderCallsStatsExceptions() {
+ int tagId = StatsLog.BINDER_CALLS_EXCEPTIONS;
+ mStatsManager.registerPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ (atomTag, data) -> pullBinderCallsStatsExceptions(atomTag, data),
+ BackgroundThread.getExecutor()
+ );
}
- private void pullBinderCallsExceptions() {
- // No op.
+ private int pullBinderCallsStatsExceptions(int atomTag, List<StatsEvent> pulledData) {
+ BinderCallsStatsService.Internal binderStats =
+ LocalServices.getService(BinderCallsStatsService.Internal.class);
+ if (binderStats == null) {
+ Slog.e(TAG, "failed to get binderStats");
+ return StatsManager.PULL_SKIP;
+ }
+
+ ArrayMap<String, Integer> exceptionStats = binderStats.getExportedExceptionStats();
+ // TODO: decouple binder calls exceptions with the rest of the binder calls data so that we
+ // can reset the exception stats.
+ for (Map.Entry<String, Integer> entry : exceptionStats.entrySet()) {
+ StatsEvent e = StatsEvent.newBuilder()
+ .setAtomId(atomTag)
+ .writeString(entry.getKey())
+ .writeInt(entry.getValue())
+ .build();
+ pulledData.add(e);
+ }
+ return StatsManager.PULL_SUCCESS;
}
private void registerLooperStats() {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3dee913..109a6fd 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -218,7 +218,7 @@
private static final String STATS_COMPANION_LIFECYCLE_CLASS =
"com.android.server.stats.StatsCompanion$Lifecycle";
private static final String STATS_PULL_ATOM_SERVICE_CLASS =
- "com.android.server.stats.StatsPullAtomService";
+ "com.android.server.stats.pull.StatsPullAtomService";
private static final String USB_SERVICE_CLASS =
"com.android.server.usb.UsbService$Lifecycle";
private static final String MIDI_SERVICE_CLASS =
diff --git a/services/tests/servicestests/src/com/android/server/stats/IonMemoryUtilTest.java b/services/tests/servicestests/src/com/android/server/stats/pull/IonMemoryUtilTest.java
similarity index 96%
rename from services/tests/servicestests/src/com/android/server/stats/IonMemoryUtilTest.java
rename to services/tests/servicestests/src/com/android/server/stats/pull/IonMemoryUtilTest.java
index 8cbf8e5..d4d4b4d 100644
--- a/services/tests/servicestests/src/com/android/server/stats/IonMemoryUtilTest.java
+++ b/services/tests/servicestests/src/com/android/server/stats/pull/IonMemoryUtilTest.java
@@ -13,16 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.server.stats;
+package com.android.server.stats.pull;
-import static com.android.server.stats.IonMemoryUtil.parseIonHeapSizeFromDebugfs;
-import static com.android.server.stats.IonMemoryUtil.parseProcessIonHeapSizesFromDebugfs;
+import static com.android.server.stats.pull.IonMemoryUtil.parseIonHeapSizeFromDebugfs;
+import static com.android.server.stats.pull.IonMemoryUtil.parseProcessIonHeapSizesFromDebugfs;
import static com.google.common.truth.Truth.assertThat;
import androidx.test.filters.SmallTest;
-import com.android.server.stats.IonMemoryUtil.IonAllocations;
+import com.android.server.stats.pull.IonMemoryUtil.IonAllocations;
import org.junit.Test;
diff --git a/services/usage/java/com/android/server/usage/StorageStatsManagerInternal.java b/services/usage/java/com/android/server/usage/StorageStatsManagerInternal.java
new file mode 100644
index 0000000..a532548
--- /dev/null
+++ b/services/usage/java/com/android/server/usage/StorageStatsManagerInternal.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usage;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.content.pm.PackageStats;
+
+/**
+ * StorageStatsManager local system service interface.
+ *
+ * Only for use within the system server.
+ */
+public abstract class StorageStatsManagerInternal {
+ /**
+ * Class used to augment {@link PackageStats} with the data stored by the system on
+ * behalf of apps in system specific directories
+ * ({@link android.os.Environment#getDataSystemDirectory},
+ * {@link android.os.Environment#getDataSystemCeDirectory}, etc).
+ */
+ public interface StorageStatsAugmenter {
+ void augmentStatsForPackage(@NonNull PackageStats stats,
+ @NonNull String packageName, @UserIdInt int userId,
+ @NonNull String callingPackage);
+ void augmentStatsForUid(@NonNull PackageStats stats, int uid,
+ @NonNull String callingPackage);
+ void augmentStatsForUser(@NonNull PackageStats stats, @UserIdInt int userId,
+ @NonNull String callingPackage);
+ }
+
+ /**
+ * Register a {@link StorageStatsAugmenter}.
+ *
+ * @param augmenter the {@link StorageStatsAugmenter} object to be registered.
+ * @param tag the identifier to be used for debugging in logs/trace.
+ */
+ public abstract void registerStorageStatsAugmenter(@NonNull StorageStatsAugmenter augmenter,
+ @NonNull String tag);
+}
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 531a931..18b640f 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -18,6 +18,7 @@
import static com.android.internal.util.ArrayUtils.defeatNullable;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+import static com.android.server.usage.StorageStatsManagerInternal.StorageStatsAugmenter;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -46,6 +47,7 @@
import android.os.ParcelableException;
import android.os.StatFs;
import android.os.SystemProperties;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.CrateInfo;
@@ -58,6 +60,7 @@
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.DataUnit;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseLongArray;
@@ -77,6 +80,8 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Consumer;
public class StorageStatsService extends IStorageStatsManager.Stub {
private static final String TAG = "StorageStatsService";
@@ -111,6 +116,9 @@
private final Installer mInstaller;
private final H mHandler;
+ private final CopyOnWriteArrayList<Pair<String, StorageStatsAugmenter>>
+ mStorageStatsAugmenters = new CopyOnWriteArrayList<>();
+
public StorageStatsService(Context context) {
mContext = Preconditions.checkNotNull(context);
mAppOps = Preconditions.checkNotNull(context.getSystemService(AppOpsManager.class));
@@ -139,6 +147,8 @@
}
}
});
+
+ LocalServices.addService(StorageStatsManagerInternal.class, new LocalService());
}
private void invalidateMounts() {
@@ -300,6 +310,12 @@
} catch (InstallerException e) {
throw new ParcelableException(new IOException(e.getMessage()));
}
+ if (volumeUuid == StorageManager.UUID_PRIVATE_INTERNAL) {
+ forEachStorageStatsAugmenter((storageStatsAugmenter) -> {
+ storageStatsAugmenter.augmentStatsForPackage(stats,
+ packageName, userId, callingPackage);
+ }, "queryStatsForPackage");
+ }
return translate(stats);
}
}
@@ -353,6 +369,12 @@
} catch (InstallerException e) {
throw new ParcelableException(new IOException(e.getMessage()));
}
+
+ if (volumeUuid == StorageManager.UUID_PRIVATE_INTERNAL) {
+ forEachStorageStatsAugmenter((storageStatsAugmenter) -> {
+ storageStatsAugmenter.augmentStatsForUid(stats, uid, callingPackage);
+ }, "queryStatsForUid");
+ }
return translate(stats);
}
@@ -379,6 +401,12 @@
} catch (InstallerException e) {
throw new ParcelableException(new IOException(e.getMessage()));
}
+
+ if (volumeUuid == StorageManager.UUID_PRIVATE_INTERNAL) {
+ forEachStorageStatsAugmenter((storageStatsAugmenter) -> {
+ storageStatsAugmenter.augmentStatsForUser(stats, userId, callingPackage);
+ }, "queryStatsForUser");
+ }
return translate(stats);
}
@@ -705,4 +733,29 @@
throw new ParcelableException(new IOException(e.getMessage()));
}
}
+
+ void forEachStorageStatsAugmenter(@NonNull Consumer<StorageStatsAugmenter> consumer,
+ @NonNull String queryTag) {
+ for (int i = 0, count = mStorageStatsAugmenters.size(); i < count; ++i) {
+ final Pair<String, StorageStatsAugmenter> pair = mStorageStatsAugmenters.get(i);
+ final String augmenterTag = pair.first;
+ final StorageStatsAugmenter storageStatsAugmenter = pair.second;
+
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, queryTag + ":" + augmenterTag);
+ try {
+ consumer.accept(storageStatsAugmenter);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
+ }
+ }
+
+ private class LocalService extends StorageStatsManagerInternal {
+ @Override
+ public void registerStorageStatsAugmenter(
+ @NonNull StorageStatsAugmenter storageStatsAugmenter,
+ @NonNull String tag) {
+ mStorageStatsAugmenters.add(Pair.create(tag, storageStatsAugmenter));
+ }
+ }
}
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index f6ce0dc..b8b203d 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -592,7 +592,7 @@
private static boolean checkCarrierPrivilegeForAnySubId(Context context, int uid) {
SubscriptionManager sm = (SubscriptionManager) context.getSystemService(
Context.TELEPHONY_SUBSCRIPTION_SERVICE);
- int[] activeSubIds = sm.getActiveSubscriptionIdList(/* visibleOnly */ false);
+ int[] activeSubIds = sm.getActiveAndHiddenSubscriptionIdList();
for (int activeSubId : activeSubIds) {
if (getCarrierPrivilegeStatus(context, activeSubId, uid)
== TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
diff --git a/telephony/framework-telephony-jarjar-rules.txt b/telephony/framework-telephony-jarjar-rules.txt
new file mode 100644
index 0000000..7cab806
--- /dev/null
+++ b/telephony/framework-telephony-jarjar-rules.txt
@@ -0,0 +1,4 @@
+rule android.telephony.Annotation* android.telephony.framework.Annotation@1
+rule com.android.i18n.phonenumbers.** com.android.telephony.framework.phonenumbers.@1
+#TODO: add jarjar rules for statically linked util classes
+
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index 58e232c..cbce8a5 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -59,10 +59,22 @@
dst[i] = 0;
}
+static bool cmp_style_ids(ResourceId a, ResourceId b) {
+ // If one of a and b is from the framework package (package ID 0x01), and the
+ // other is a dynamic ID (package ID 0x00), then put the dynamic ID after the
+ // framework ID. This ensures that when AssetManager resolves the dynamic IDs,
+ // they will be in sorted order as expected by AssetManager.
+ if ((a.package_id() == kFrameworkPackageId && b.package_id() == 0x00) ||
+ (a.package_id() == 0x00 && b.package_id() == kFrameworkPackageId)) {
+ return b < a;
+ }
+ return a < b;
+}
+
static bool cmp_style_entries(const Style::Entry& a, const Style::Entry& b) {
if (a.key.id) {
if (b.key.id) {
- return a.key.id.value() < b.key.id.value();
+ return cmp_style_ids(a.key.id.value(), b.key.id.value());
}
return true;
} else if (!b.key.id) {
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index 8fbdd7f..af2293f 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -431,6 +431,47 @@
EXPECT_EQ("lib", iter->second);
}
+TEST_F(TableFlattenerTest, FlattenSharedLibraryWithStyle) {
+ std::unique_ptr<IAaptContext> context =
+ test::ContextBuilder().SetCompilationPackage("lib").SetPackageId(0x00).Build();
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .SetPackageId("lib", 0x00)
+ .AddValue("lib:style/Theme",
+ ResourceId(0x00030001),
+ test::StyleBuilder()
+ .AddItem("lib:attr/bar", ResourceId(0x00010002),
+ ResourceUtils::TryParseInt("2"))
+ .AddItem("lib:attr/foo", ResourceId(0x00010001),
+ ResourceUtils::TryParseInt("1"))
+ .AddItem("android:attr/bar", ResourceId(0x01010002),
+ ResourceUtils::TryParseInt("4"))
+ .AddItem("android:attr/foo", ResourceId(0x01010001),
+ ResourceUtils::TryParseInt("3"))
+ .Build())
+ .Build();
+ ResourceTable result;
+ ASSERT_TRUE(Flatten(context.get(), {}, table.get(), &result));
+
+ Maybe<ResourceTable::SearchResult> search_result =
+ result.FindResource(test::ParseNameOrDie("lib:style/Theme"));
+ ASSERT_TRUE(search_result);
+ EXPECT_EQ(0x00u, search_result.value().package->id.value());
+ EXPECT_EQ(0x03u, search_result.value().type->id.value());
+ EXPECT_EQ(0x01u, search_result.value().entry->id.value());
+ ASSERT_EQ(1u, search_result.value().entry->values.size());
+ Value* value = search_result.value().entry->values[0]->value.get();
+ Style* style = ValueCast<Style>(value);
+ ASSERT_TRUE(style);
+ ASSERT_EQ(4u, style->entries.size());
+ // Ensure the attributes from the shared library come after the items from
+ // android.
+ EXPECT_EQ(0x01010001, style->entries[0].key.id.value());
+ EXPECT_EQ(0x01010002, style->entries[1].key.id.value());
+ EXPECT_EQ(0x00010001, style->entries[2].key.id.value());
+ EXPECT_EQ(0x00010002, style->entries[3].key.id.value());
+}
+
TEST_F(TableFlattenerTest, FlattenTableReferencingSharedLibraries) {
std::unique_ptr<IAaptContext> context =
test::ContextBuilder().SetCompilationPackage("app").SetPackageId(0x7f).Build();
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 70c9bef..4c9ee85 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -70,6 +70,7 @@
"framework-annotations-lib",
"unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage
"unsupportedappusage-annotation", // for dalvik.annotation.compat.UnsupportedAppUsage
+ "framework-telephony-stubs",
],
srcs: [
":framework-wifi-updatable-sources",
diff --git a/wifi/jarjar-rules.txt b/wifi/jarjar-rules.txt
index 8f72040..d377ee6 100644
--- a/wifi/jarjar-rules.txt
+++ b/wifi/jarjar-rules.txt
@@ -1,5 +1,7 @@
rule android.net.InterfaceConfigurationParcel* @0
rule android.net.InterfaceConfiguration* com.android.server.x.wifi.net.InterfaceConfiguration@1
+rule android.net.NetworkFactory* com.android.server.x.wifi.net.NetworkFactory@1
+rule android.net.util.NetUtils* com.android.server.x.wifi.net.util.NetUtils@1
# We don't jar-jar the entire package because, we still use some classes (like
# AsyncChannel in com.android.internal.util) from these packages which are not
@@ -32,6 +34,7 @@
rule android.content.pm.BaseParceledListSlice* android.x.net.wifi.util.BaseParceledListSlice@1
rule android.content.pm.ParceledListSlice* android.x.net.wifi.util.ParceledListSlice@1
rule android.net.shared.Inet4AddressUtils* android.x.net.wifi.util.Inet4AddressUtils@1
+rule android.net.util.MacAddressUtils* android.x.net.wifi.util.MacAddressUtils@1
rule android.os.HandlerExecutor* android.x.net.wifi.util.HandlerExecutor@1
rule android.telephony.Annotation* android.x.net.wifi.util.TelephonyAnnotation@1
rule com.android.internal.util.AsyncChannel* android.x.net.wifi.util.AsyncChannel@1
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index f490766..67f1663 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -92,6 +92,8 @@
void allowAutojoinPasspoint(String fqdn, boolean enableAutoJoin);
+ void setMacRandomizationSettingPasspointEnabled(String fqdn, boolean enable);
+
boolean startScan(String packageName, String featureId);
List<ScanResult> getScanResults(String callingPackage, String callingFeatureId);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 9540103..ec3de43 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -4243,6 +4243,24 @@
}
/**
+ * Configure MAC randomization setting for a Passpoint profile.
+ * MAC randomization is enabled by default.
+ *
+ * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
+ * @param enable true to enable MAC randomization, false to disable MAC randomization.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void setMacRandomizationSettingPasspointEnabled(@NonNull String fqdn, boolean enable) {
+ try {
+ mService.setMacRandomizationSettingPasspointEnabled(fqdn, enable);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Disable an ephemeral network.
*
* @param ssid in the format of WifiConfiguration's SSID.
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index c0e0890..2fba5a3 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -122,6 +122,12 @@
* Whether the setCredentialSharedWithUser have been called.
*/
private boolean mIsSharedWithUserSet;
+
+ /**
+ * Whether this network is initialized with auto-join enabled (the default) or not.
+ */
+ private boolean mIsInitialAutoJoinEnabled;
+
/**
* Pre-shared key for use with WAPI-PSK networks.
*/
@@ -148,6 +154,7 @@
mIsMetered = false;
mIsSharedWithUser = true;
mIsSharedWithUserSet = false;
+ mIsInitialAutoJoinEnabled = true;
mPriority = UNASSIGNED_PRIORITY;
mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
mWapiPskPassphrase = null;
@@ -440,6 +447,27 @@
return this;
}
+ /**
+ * Specifies whether the suggestion is created with auto-join enabled or disabled. The
+ * user may modify the auto-join configuration of a suggestion directly once the device
+ * associates to the network.
+ * <p>
+ * If auto-join is initialized as disabled the user may still be able to manually connect
+ * to the network. Therefore, disabling auto-join only makes sense if
+ * {@link #setCredentialSharedWithUser(boolean)} is set to true (the default) which
+ * itself implies a secure (non-open) network.
+ * <p>
+ * If not set, defaults to true (i.e. auto-join is initialized as enabled).
+ *
+ * @param enabled true for initializing with auto-join enabled (the default), false to
+ * initializing with auto-join disabled.
+ * @return Instance of (@link {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setIsInitialAutoJoinEnabled(boolean enabled) {
+ mIsInitialAutoJoinEnabled = enabled;
+ return this;
+ }
+
private void setSecurityParamsInWifiConfiguration(
@NonNull WifiConfiguration configuration) {
if (!TextUtils.isEmpty(mWpa2PskPassphrase)) { // WPA-PSK network.
@@ -587,7 +615,6 @@
+ "suggestion with Passpoint configuration");
}
wifiConfiguration = buildWifiConfigurationForPasspoint();
-
} else {
if (mSsid == null) {
throw new IllegalStateException("setSsid should be invoked for suggestion");
@@ -608,6 +635,12 @@
}
mIsSharedWithUser = false;
}
+
+ if (!mIsSharedWithUser && !mIsInitialAutoJoinEnabled) {
+ throw new IllegalStateException("Should have not a network with both "
+ + "setIsUserAllowedToManuallyConnect and "
+ + "setIsAutoJoinEnabled set to false");
+ }
}
return new WifiNetworkSuggestion(
@@ -615,7 +648,8 @@
mPasspointConfiguration,
mIsAppInteractionRequired,
mIsUserInteractionRequired,
- mIsSharedWithUser);
+ mIsSharedWithUser,
+ mIsInitialAutoJoinEnabled);
}
}
@@ -642,6 +676,7 @@
* @hide
*/
public final boolean isUserInteractionRequired;
+
/**
* Whether app share credential with the user, allow user use provided credential to
* connect network manually.
@@ -649,6 +684,12 @@
*/
public final boolean isUserAllowedToManuallyConnect;
+ /**
+ * Whether the suggestion will be initialized as auto-joined or not.
+ * @hide
+ */
+ public final boolean isInitialAutoJoinEnabled;
+
/** @hide */
public WifiNetworkSuggestion() {
this.wifiConfiguration = null;
@@ -656,6 +697,7 @@
this.isAppInteractionRequired = false;
this.isUserInteractionRequired = false;
this.isUserAllowedToManuallyConnect = true;
+ this.isInitialAutoJoinEnabled = true;
}
/** @hide */
@@ -663,7 +705,8 @@
@Nullable PasspointConfiguration passpointConfiguration,
boolean isAppInteractionRequired,
boolean isUserInteractionRequired,
- boolean isUserAllowedToManuallyConnect) {
+ boolean isUserAllowedToManuallyConnect,
+ boolean isInitialAutoJoinEnabled) {
checkNotNull(networkConfiguration);
this.wifiConfiguration = networkConfiguration;
this.passpointConfiguration = passpointConfiguration;
@@ -671,6 +714,7 @@
this.isAppInteractionRequired = isAppInteractionRequired;
this.isUserInteractionRequired = isUserInteractionRequired;
this.isUserAllowedToManuallyConnect = isUserAllowedToManuallyConnect;
+ this.isInitialAutoJoinEnabled = isInitialAutoJoinEnabled;
}
public static final @NonNull Creator<WifiNetworkSuggestion> CREATOR =
@@ -682,7 +726,8 @@
in.readParcelable(null), // PasspointConfiguration
in.readBoolean(), // isAppInteractionRequired
in.readBoolean(), // isUserInteractionRequired
- in.readBoolean() // isSharedCredentialWithUser
+ in.readBoolean(), // isSharedCredentialWithUser
+ in.readBoolean() // isAutoJoinEnabled
);
}
@@ -704,6 +749,7 @@
dest.writeBoolean(isAppInteractionRequired);
dest.writeBoolean(isUserInteractionRequired);
dest.writeBoolean(isUserAllowedToManuallyConnect);
+ dest.writeBoolean(isInitialAutoJoinEnabled);
}
@Override
@@ -744,6 +790,7 @@
.append(", isAppInteractionRequired=").append(isAppInteractionRequired)
.append(", isUserInteractionRequired=").append(isUserInteractionRequired)
.append(", isUserAllowedToManuallyConnect=").append(isUserAllowedToManuallyConnect)
+ .append(", isInitialAutoJoinEnabled=").append(isInitialAutoJoinEnabled)
.append(" ]");
return sb.toString();
}
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 1822e84..7c335fc 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -431,6 +431,13 @@
private boolean mIsAutoJoinEnabled = true;
/**
+ * The mac randomization setting specifies whether a randomized or device MAC address will
+ * be used to connect to the passpoint network. If true, a randomized MAC will be used.
+ * Otherwise, the device MAC address will be used.
+ */
+ private boolean mIsMacRandomizationEnabled = true;
+
+ /**
* Configures the auto-association status of this Passpoint configuration. A value of true
* indicates that the configuration will be considered for auto-connection, a value of false
* indicates that only manual connection will work - the framework will not auto-associate to
@@ -444,6 +451,18 @@
}
/**
+ * Configures the MAC randomization setting for this Passpoint configuration.
+ * If set to true, the framework will use a randomized MAC address to connect to this Passpoint
+ * network. Otherwise, the framework will use the device MAC address.
+ *
+ * @param enabled true to use randomized MAC address, false to use device MAC address.
+ * @hide
+ */
+ public void setMacRandomizationEnabled(boolean enabled) {
+ mIsMacRandomizationEnabled = enabled;
+ }
+
+ /**
* Indicates whether the Passpoint configuration may be auto-connected to by the framework. A
* value of true indicates that auto-connection can happen, a value of false indicates that it
* cannot. However, even when auto-connection is not possible manual connection by the user is
@@ -459,6 +478,19 @@
}
/**
+ * Indicates whether a randomized MAC address or device MAC address will be used for
+ * connections to this Passpoint network. If true, a randomized MAC address will be used.
+ * Otherwise, the device MAC address will be used.
+ *
+ * @return true for MAC randomization enabled. False for disabled.
+ * @hide
+ */
+ @SystemApi
+ public boolean isMacRandomizationEnabled() {
+ return mIsMacRandomizationEnabled;
+ }
+
+ /**
* Constructor for creating PasspointConfiguration with default values.
*/
public PasspointConfiguration() {}
@@ -501,6 +533,7 @@
mAaaServerTrustedNames = source.mAaaServerTrustedNames;
mCarrierId = source.mCarrierId;
mIsAutoJoinEnabled = source.mIsAutoJoinEnabled;
+ mIsMacRandomizationEnabled = source.mIsMacRandomizationEnabled;
}
@Override
@@ -531,6 +564,7 @@
dest.writeBundle(bundle);
dest.writeInt(mCarrierId);
dest.writeBoolean(mIsAutoJoinEnabled);
+ dest.writeBoolean(mIsMacRandomizationEnabled);
}
@Override
@@ -562,6 +596,7 @@
&& mUsageLimitTimeLimitInMinutes == that.mUsageLimitTimeLimitInMinutes
&& mCarrierId == that.mCarrierId
&& mIsAutoJoinEnabled == that.mIsAutoJoinEnabled
+ && mIsMacRandomizationEnabled == that.mIsMacRandomizationEnabled
&& (mServiceFriendlyNames == null ? that.mServiceFriendlyNames == null
: mServiceFriendlyNames.equals(that.mServiceFriendlyNames));
}
@@ -572,7 +607,7 @@
mUpdateIdentifier, mCredentialPriority, mSubscriptionCreationTimeInMillis,
mSubscriptionExpirationTimeInMillis, mUsageLimitUsageTimePeriodInMinutes,
mUsageLimitStartTimeInMillis, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes,
- mServiceFriendlyNames, mCarrierId, mIsAutoJoinEnabled);
+ mServiceFriendlyNames, mCarrierId, mIsAutoJoinEnabled, mIsMacRandomizationEnabled);
}
@Override
@@ -627,6 +662,7 @@
}
builder.append("CarrierId:" + mCarrierId);
builder.append("IsAutoJoinEnabled:" + mIsAutoJoinEnabled);
+ builder.append("mIsMacRandomizationEnabled:" + mIsMacRandomizationEnabled);
return builder.toString();
}
@@ -733,6 +769,7 @@
config.setServiceFriendlyNames(friendlyNamesMap);
config.mCarrierId = in.readInt();
config.mIsAutoJoinEnabled = in.readBoolean();
+ config.mIsMacRandomizationEnabled = in.readBoolean();
return config;
}
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index 3c13562d..1cf3825 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -187,6 +187,11 @@
}
@Override
+ public void setMacRandomizationSettingPasspointEnabled(String fqdn, boolean enable) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public boolean startScan(String packageName, String featureId) {
throw new UnsupportedOperationException();
}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 5bdc344..983ac82 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -1706,6 +1706,17 @@
verify(mWifiService).allowAutojoinPasspoint(fqdn, true);
}
+ /**
+ * Test behavior of
+ * {@link WifiManager#setMacRandomizationSettingPasspointEnabled(String, boolean)}
+ */
+ @Test
+ public void testSetMacRandomizationSettingPasspointEnabled() throws Exception {
+ final String fqdn = "FullyQualifiedDomainName";
+ mWifiManager.setMacRandomizationSettingPasspointEnabled(fqdn, true);
+ verify(mWifiService).setMacRandomizationSettingPasspointEnabled(fqdn, true);
+ }
+
/**
* Test behavior of {@link WifiManager#disconnect()}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index ac91544..cb1b774 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -32,8 +32,6 @@
*/
@SmallTest
public class WifiNetworkSuggestionTest {
- private static final int TEST_UID = 45677;
- private static final int TEST_UID_OTHER = 45673;
private static final String TEST_SSID = "\"Test123\"";
private static final String TEST_BSSID = "12:12:12:12:12:12";
private static final String TEST_SSID_1 = "\"Test1234\"";
@@ -61,7 +59,8 @@
assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
suggestion.wifiConfiguration.meteredOverride);
assertEquals(-1, suggestion.wifiConfiguration.priority);
- assertEquals(false, suggestion.isUserAllowedToManuallyConnect);
+ assertFalse(suggestion.isUserAllowedToManuallyConnect);
+ assertTrue(suggestion.isInitialAutoJoinEnabled);
}
/**
@@ -90,7 +89,8 @@
assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
suggestion.wifiConfiguration.meteredOverride);
assertEquals(0, suggestion.wifiConfiguration.priority);
- assertEquals(false, suggestion.isUserAllowedToManuallyConnect);
+ assertFalse(suggestion.isUserAllowedToManuallyConnect);
+ assertTrue(suggestion.isInitialAutoJoinEnabled);
}
/**
@@ -105,6 +105,7 @@
.setSsid(TEST_SSID)
.setWpa2Passphrase(TEST_PRESHARED_KEY)
.setIsUserInteractionRequired(true)
+ .setIsInitialAutoJoinEnabled(false)
.setIsMetered(true)
.build();
@@ -119,6 +120,7 @@
suggestion.wifiConfiguration.meteredOverride);
assertEquals(-1, suggestion.wifiConfiguration.priority);
assertTrue(suggestion.isUserAllowedToManuallyConnect);
+ assertFalse(suggestion.isInitialAutoJoinEnabled);
}
/**
@@ -140,6 +142,7 @@
assertNull(suggestion.wifiConfiguration.preSharedKey);
assertTrue(suggestion.wifiConfiguration.requirePMF);
assertFalse(suggestion.isUserAllowedToManuallyConnect);
+ assertTrue(suggestion.isInitialAutoJoinEnabled);
}
/**
@@ -152,6 +155,7 @@
.setSsid(TEST_SSID)
.setWpa3Passphrase(TEST_PRESHARED_KEY)
.setCredentialSharedWithUser(true)
+ .setIsInitialAutoJoinEnabled(false)
.build();
assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
@@ -161,6 +165,7 @@
suggestion.wifiConfiguration.preSharedKey);
assertTrue(suggestion.wifiConfiguration.requirePMF);
assertTrue(suggestion.isUserAllowedToManuallyConnect);
+ assertFalse(suggestion.isInitialAutoJoinEnabled);
}
@@ -191,6 +196,7 @@
// allowedSuiteBCiphers are set according to the loaded certificate and cannot be tested
// here.
assertTrue(suggestion.isUserAllowedToManuallyConnect);
+ assertTrue(suggestion.isInitialAutoJoinEnabled);
}
/**
@@ -526,7 +532,7 @@
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion(
- configuration, null, false, true, true);
+ configuration, null, false, true, true, false);
Parcel parcelW = Parcel.obtain();
suggestion.writeToParcel(parcelW, 0);
@@ -548,6 +554,8 @@
parcelSuggestion.isAppInteractionRequired);
assertEquals(suggestion.isUserInteractionRequired,
parcelSuggestion.isUserInteractionRequired);
+ assertEquals(suggestion.isInitialAutoJoinEnabled,
+ parcelSuggestion.isInitialAutoJoinEnabled);
}
/**
@@ -580,6 +588,8 @@
parcelSuggestion.isAppInteractionRequired);
assertEquals(suggestion.isUserInteractionRequired,
parcelSuggestion.isUserInteractionRequired);
+ assertEquals(suggestion.isInitialAutoJoinEnabled,
+ parcelSuggestion.isInitialAutoJoinEnabled);
}
/**
@@ -593,14 +603,14 @@
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, true, false, true);
+ new WifiNetworkSuggestion(configuration, null, true, false, true, true);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID;
configuration1.BSSID = TEST_BSSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, true, true);
+ new WifiNetworkSuggestion(configuration1, null, false, true, true, false);
assertEquals(suggestion, suggestion1);
assertEquals(suggestion.hashCode(), suggestion1.hashCode());
@@ -616,13 +626,13 @@
configuration.SSID = TEST_SSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, false, false, true);
+ new WifiNetworkSuggestion(configuration, null, false, false, true, false);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID_1;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, false, true);
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, false);
assertNotEquals(suggestion, suggestion1);
}
@@ -638,13 +648,13 @@
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, false, false, true);
+ new WifiNetworkSuggestion(configuration, null, false, false, true, true);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, false, true);
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
assertNotEquals(suggestion, suggestion1);
}
@@ -659,13 +669,13 @@
configuration.SSID = TEST_SSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, false, false, true);
+ new WifiNetworkSuggestion(configuration, null, false, false, true, true);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, false, true);
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, true);
assertNotEquals(suggestion, suggestion1);
}
@@ -714,9 +724,38 @@
*/
@Test(expected = IllegalStateException.class)
public void testSetIsUserAllowedToManuallyConnectToWithOpenNetwork() {
- WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ new WifiNetworkSuggestion.Builder()
.setSsid(TEST_SSID)
.setCredentialSharedWithUser(true)
.build();
}
+
+ /**
+ * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+ * when {@link WifiNetworkSuggestion.Builder#setIsInitialAutoJoinEnabled(boolean)} to
+ * false on a open network suggestion.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testSetIsAutoJoinDisabledWithOpenNetwork() {
+ new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setIsInitialAutoJoinEnabled(false)
+ .build();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+ * when set both {@link WifiNetworkSuggestion.Builder#setIsInitialAutoJoinEnabled(boolean)}
+ * and {@link WifiNetworkSuggestion.Builder#setCredentialSharedWithUser(boolean)} (boolean)}
+ * to false on a network suggestion.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testSetIsAutoJoinDisabledWithSecureNetworkNotSharedWithUser() {
+ new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setWpa2Passphrase(TEST_PRESHARED_KEY)
+ .setCredentialSharedWithUser(false)
+ .setIsInitialAutoJoinEnabled(false)
+ .build();
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index 94054fd..603e78b 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -172,6 +172,7 @@
assertFalse(config.validate());
assertFalse(config.validateForR2());
assertTrue(config.isAutoJoinEnabled());
+ assertTrue(config.isMacRandomizationEnabled());
}
/**