Merge "Stop loading animation for addtional cursor type."
diff --git a/Android.bp b/Android.bp
index ea14b9d..2a820cb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -212,6 +212,7 @@
name: "framework-non-updatable-sources",
srcs: [
// Java/AIDL sources under frameworks/base
+ ":framework-appsearch-sources",
":framework-blobstore-sources",
":framework-core-sources",
":framework-drm-sources",
@@ -870,11 +871,13 @@
srcs: [
"core/java/android/os/HidlSupport.java",
"core/java/android/annotation/IntDef.java",
+ "core/java/android/annotation/IntRange.java",
"core/java/android/annotation/NonNull.java",
"core/java/android/annotation/Nullable.java",
"core/java/android/annotation/SystemApi.java",
"core/java/android/annotation/TestApi.java",
"core/java/android/annotation/UnsupportedAppUsage.java",
+ "core/java/android/os/HidlMemory.java",
"core/java/android/os/HwBinder.java",
"core/java/android/os/HwBlob.java",
"core/java/android/os/HwParcel.java",
@@ -1405,8 +1408,10 @@
srcs: [
"core/java/android/os/HidlSupport.java",
"core/java/android/annotation/IntDef.java",
+ "core/java/android/annotation/IntRange.java",
"core/java/android/annotation/NonNull.java",
"core/java/android/annotation/SystemApi.java",
+ "core/java/android/os/HidlMemory.java",
"core/java/android/os/HwBinder.java",
"core/java/android/os/HwBlob.java",
"core/java/android/os/HwParcel.java",
diff --git a/apex/appsearch/framework/Android.bp b/apex/appsearch/framework/Android.bp
new file mode 100644
index 0000000..0a65f73
--- /dev/null
+++ b/apex/appsearch/framework/Android.bp
@@ -0,0 +1,39 @@
+// 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.
+
+filegroup {
+ name: "framework-appsearch-sources",
+ srcs: [
+ "java/**/*.java",
+ "java/**/*.aidl",
+ ],
+ path: "java",
+}
+
+java_library {
+ name: "framework-appsearch",
+ installable: false,
+ sdk_version: "core_platform",
+ srcs: [
+ ":framework-appsearch-sources",
+ ],
+ aidl: {
+ export_include_dirs: [
+ "java",
+ ],
+ },
+ libs: [
+ "framework-minus-apex",
+ ],
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
new file mode 100644
index 0000000..a8ee35c
--- /dev/null
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.appsearch;
+
+import android.annotation.SystemService;
+import android.content.Context;
+
+/**
+ * TODO(b/142567528): add comments when implement this class
+ * @hide
+ */
+@SystemService(Context.APP_SEARCH_SERVICE)
+public class AppSearchManager {
+ private final IAppSearchManager mService;
+ /**
+ * TODO(b/142567528): add comments when implement this class
+ * @hide
+ */
+ public AppSearchManager(IAppSearchManager service) {
+ mService = service;
+ }
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java
new file mode 100644
index 0000000..fcebe3d
--- /dev/null
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.appsearch;
+
+import android.app.SystemServiceRegistry;
+import android.content.Context;
+
+/**
+ * This is where the AppSearchManagerService wrapper is registered.
+ *
+ * TODO(b/142567528): add comments when implement this class
+ * @hide
+ */
+public class AppSearchManagerFrameworkInitializer {
+
+ /**
+ * TODO(b/142567528): add comments when implement this class
+ */
+ public static void initialize() {
+ SystemServiceRegistry.registerStaticService(
+ Context.APP_SEARCH_SERVICE, AppSearchManager.class,
+ (service) -> new AppSearchManager(IAppSearchManager.Stub.asInterface(service)));
+ }
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
new file mode 100644
index 0000000..f0f4f51
--- /dev/null
+++ b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.appsearch;
+/** {@hide} */
+interface IAppSearchManager {
+}
diff --git a/apex/appsearch/service/Android.bp b/apex/appsearch/service/Android.bp
new file mode 100644
index 0000000..2821fbe
--- /dev/null
+++ b/apex/appsearch/service/Android.bp
@@ -0,0 +1,24 @@
+// 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.
+java_library {
+ name: "appsearch-service",
+ installable: true,
+ srcs: [
+ "java/**/*.java",
+ ],
+ libs: [
+ "framework",
+ "services.core",
+ ],
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
new file mode 100644
index 0000000..4d44d9d
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.appsearch;
+
+import android.app.appsearch.IAppSearchManager;
+import android.content.Context;
+
+import com.android.server.SystemService;
+
+/**
+ * TODO(b/142567528): add comments when implement this class
+ */
+public class AppSearchManagerService extends SystemService {
+
+ public AppSearchManagerService(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.APP_SEARCH_SERVICE, new Stub());
+ }
+
+ private class Stub extends IAppSearchManager.Stub {
+ }
+}
diff --git a/api/current.txt b/api/current.txt
index a45583a..63046b8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9927,6 +9927,7 @@
field public static final String ALARM_SERVICE = "alarm";
field public static final String APPWIDGET_SERVICE = "appwidget";
field public static final String APP_OPS_SERVICE = "appops";
+ field public static final String APP_SEARCH_SERVICE = "app_search";
field public static final String AUDIO_SERVICE = "audio";
field public static final String BATTERY_SERVICE = "batterymanager";
field public static final int BIND_ABOVE_CLIENT = 8; // 0x8
@@ -30060,7 +30061,8 @@
method public void addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void addScanResultsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.ScanResultsListener);
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE}) public void addSuggestionConnectionStatusListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SuggestionConnectionStatusListener);
- method public static int calculateSignalLevel(int, int);
+ method @Deprecated public static int calculateSignalLevel(int, int);
+ method public int calculateSignalLevel(int);
method @Deprecated public void cancelWps(android.net.wifi.WifiManager.WpsCallback);
method public static int compareSignalLevel(int, int);
method public android.net.wifi.WifiManager.MulticastLock createMulticastLock(String);
@@ -30073,6 +30075,7 @@
method public android.net.wifi.WifiInfo getConnectionInfo();
method public android.net.DhcpInfo getDhcpInfo();
method public int getMaxNumberOfNetworkSuggestionsPerApp();
+ method public int getMaxSignalLevel();
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public java.util.List<android.net.wifi.WifiNetworkSuggestion> getNetworkSuggestions();
method @Deprecated @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", "android.permission.NETWORK_SETUP_WIZARD"}) public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
method public java.util.List<android.net.wifi.ScanResult> getScanResults();
@@ -45590,6 +45593,8 @@
field public static final int PHONE_TYPE_NONE = 0; // 0x0
field public static final int PHONE_TYPE_SIP = 3; // 0x3
field public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2; // 0x2
+ field public static final int SET_OPPORTUNISTIC_SUB_NO_OPPORTUNISTIC_SUB_AVAILABLE = 3; // 0x3
+ field public static final int SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION = 4; // 0x4
field public static final int SET_OPPORTUNISTIC_SUB_SUCCESS = 0; // 0x0
field public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1; // 0x1
field public static final int SIM_STATE_ABSENT = 1; // 0x1
@@ -45606,8 +45611,14 @@
field public static final int UNKNOWN_CARRIER_ID = -1; // 0xffffffff
field public static final int UNSUPPORTED_CARD_ID = -1; // 0xffffffff
field public static final int UPDATE_AVAILABLE_NETWORKS_ABORTED = 2; // 0x2
+ field public static final int UPDATE_AVAILABLE_NETWORKS_DISABLE_MODEM_FAIL = 5; // 0x5
+ field public static final int UPDATE_AVAILABLE_NETWORKS_ENABLE_MODEM_FAIL = 6; // 0x6
field public static final int UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS = 3; // 0x3
+ field public static final int UPDATE_AVAILABLE_NETWORKS_MULTIPLE_NETWORKS_NOT_SUPPORTED = 7; // 0x7
field public static final int UPDATE_AVAILABLE_NETWORKS_NO_CARRIER_PRIVILEGE = 4; // 0x4
+ field public static final int UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE = 8; // 0x8
+ field public static final int UPDATE_AVAILABLE_NETWORKS_REMOTE_SERVICE_EXCEPTION = 9; // 0x9
+ field public static final int UPDATE_AVAILABLE_NETWORKS_SERVICE_IS_DISABLED = 10; // 0xa
field public static final int UPDATE_AVAILABLE_NETWORKS_SUCCESS = 0; // 0x0
field public static final int UPDATE_AVAILABLE_NETWORKS_UNKNOWN_FAILURE = 1; // 0x1
field public static final int USSD_ERROR_SERVICE_UNAVAIL = -2; // 0xfffffffe
@@ -57044,7 +57055,7 @@
method public int describeContents();
method public int getLayoutId();
method public String getPackage();
- method public boolean onLoadClass(Class);
+ method @Deprecated public boolean onLoadClass(Class);
method public void reapply(android.content.Context, android.view.View);
method public void removeAllViews(int);
method public void setAccessibilityTraversalAfter(int, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index e40fd24..f3cdac3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5489,6 +5489,17 @@
method @NonNull public static java.io.File getVendorDirectory();
}
+ public class HidlMemory implements java.io.Closeable {
+ ctor public HidlMemory(@NonNull String, @IntRange(from=0) long, @Nullable android.os.NativeHandle);
+ method public void close() throws java.io.IOException;
+ method @NonNull public android.os.HidlMemory dup() throws java.io.IOException;
+ method protected void finalize();
+ method @Nullable public android.os.NativeHandle getHandle();
+ method @NonNull public String getName();
+ method public long getSize();
+ method @NonNull public android.os.NativeHandle releaseHandle();
+ }
+
public class HidlSupport {
method public static boolean deepEquals(Object, Object);
method public static int deepHashCode(Object);
@@ -5519,6 +5530,7 @@
method public final void copyToInt8Array(long, byte[], int);
method public final boolean getBool(long);
method public final double getDouble(long);
+ method public final long getFieldHandle(long);
method public final float getFloat(long);
method public final short getInt16(long);
method public final int getInt32(long);
@@ -5533,6 +5545,7 @@
method public final void putDoubleArray(long, double[]);
method public final void putFloat(long, float);
method public final void putFloatArray(long, float[]);
+ method public final void putHidlMemory(long, @NonNull android.os.HidlMemory);
method public final void putInt16(long, short);
method public final void putInt16Array(long, short[]);
method public final void putInt32(long, int);
@@ -5561,9 +5574,11 @@
method public final double readDouble();
method public final java.util.ArrayList<java.lang.Double> readDoubleVector();
method public final android.os.HwBlob readEmbeddedBuffer(long, long, long, boolean);
+ method @NonNull @Nullable public final android.os.HidlMemory readEmbeddedHidlMemory(long, long, long);
method @Nullable public final android.os.NativeHandle readEmbeddedNativeHandle(long, long);
method public final float readFloat();
method public final java.util.ArrayList<java.lang.Float> readFloatVector();
+ method @NonNull public final android.os.HidlMemory readHidlMemory();
method public final short readInt16();
method public final java.util.ArrayList<java.lang.Short> readInt16Vector();
method public final int readInt32();
@@ -5588,6 +5603,7 @@
method public final void writeDoubleVector(java.util.ArrayList<java.lang.Double>);
method public final void writeFloat(float);
method public final void writeFloatVector(java.util.ArrayList<java.lang.Float>);
+ method public final void writeHidlMemory(@NonNull android.os.HidlMemory);
method public final void writeInt16(short);
method public final void writeInt16Vector(java.util.ArrayList<java.lang.Short>);
method public final void writeInt32(int);
@@ -5899,7 +5915,15 @@
}
public class WorkSource implements android.os.Parcelable {
+ ctor public WorkSource(int);
+ ctor public WorkSource(int, @NonNull String);
method public android.os.WorkSource.WorkChain createWorkChain();
+ method @Nullable public String getPackageName(int);
+ method public int getUid(int);
+ method @Nullable public java.util.List<android.os.WorkSource.WorkChain> getWorkChains();
+ method public boolean isEmpty();
+ method public int size();
+ method @NonNull public android.os.WorkSource withoutNames();
}
public static final class WorkSource.WorkChain implements android.os.Parcelable {
@@ -8655,6 +8679,10 @@
method @Deprecated public static android.telephony.SubscriptionPlan.Builder createRecurringWeekly(java.time.ZonedDateTime);
}
+ public class TelephonyFrameworkInitializer {
+ method public static void registerServiceWrappers();
+ }
+
public final class TelephonyHistogram implements android.os.Parcelable {
ctor public TelephonyHistogram(int, int, int);
ctor public TelephonyHistogram(android.telephony.TelephonyHistogram);
diff --git a/api/test-current.txt b/api/test-current.txt
index 897e825..a8bd9be 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1808,6 +1808,17 @@
method public static boolean contains(java.io.File, java.io.File);
}
+ public class HidlMemory implements java.io.Closeable {
+ ctor public HidlMemory(@NonNull String, @IntRange(from=0) long, @Nullable android.os.NativeHandle);
+ method public void close() throws java.io.IOException;
+ method @NonNull public android.os.HidlMemory dup() throws java.io.IOException;
+ method protected void finalize();
+ method @Nullable public android.os.NativeHandle getHandle();
+ method @NonNull public String getName();
+ method public long getSize();
+ method @NonNull public android.os.NativeHandle releaseHandle();
+ }
+
public abstract class HwBinder implements android.os.IHwBinder {
ctor public HwBinder();
method public static final void configureRpcThreadpool(long, boolean);
@@ -1831,6 +1842,7 @@
method public final void copyToInt8Array(long, byte[], int);
method public final boolean getBool(long);
method public final double getDouble(long);
+ method public final long getFieldHandle(long);
method public final float getFloat(long);
method public final short getInt16(long);
method public final int getInt32(long);
@@ -1845,6 +1857,7 @@
method public final void putDoubleArray(long, double[]);
method public final void putFloat(long, float);
method public final void putFloatArray(long, float[]);
+ method public final void putHidlMemory(long, @NonNull android.os.HidlMemory);
method public final void putInt16(long, short);
method public final void putInt16Array(long, short[]);
method public final void putInt32(long, int);
@@ -1873,9 +1886,11 @@
method public final double readDouble();
method public final java.util.ArrayList<java.lang.Double> readDoubleVector();
method public final android.os.HwBlob readEmbeddedBuffer(long, long, long, boolean);
+ method @NonNull @Nullable public final android.os.HidlMemory readEmbeddedHidlMemory(long, long, long);
method @Nullable public final android.os.NativeHandle readEmbeddedNativeHandle(long, long);
method public final float readFloat();
method public final java.util.ArrayList<java.lang.Float> readFloatVector();
+ method @NonNull public final android.os.HidlMemory readHidlMemory();
method public final short readInt16();
method public final java.util.ArrayList<java.lang.Short> readInt16Vector();
method public final int readInt32();
@@ -1900,6 +1915,7 @@
method public final void writeDoubleVector(java.util.ArrayList<java.lang.Double>);
method public final void writeFloat(float);
method public final void writeFloatVector(java.util.ArrayList<java.lang.Float>);
+ method public final void writeHidlMemory(@NonNull android.os.HidlMemory);
method public final void writeInt16(short);
method public final void writeInt16Vector(java.util.ArrayList<java.lang.Short>);
method public final void writeInt32(int);
@@ -2185,10 +2201,12 @@
method public boolean add(int);
method public boolean add(int, String);
method @Deprecated public android.os.WorkSource addReturningNewbs(android.os.WorkSource);
- method public int get(int);
- method public String getName(int);
+ method @Nullable public String getPackageName(int);
+ method public int getUid(int);
+ method public boolean isEmpty();
method @Deprecated public android.os.WorkSource[] setReturningDiffs(android.os.WorkSource);
method public int size();
+ method @NonNull public android.os.WorkSource withoutNames();
}
}
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index ce27ce6..b5bad05 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -499,8 +499,9 @@
StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/true);
kAllPullAtomInfo[{.atomTag = atomTag}] = {.additiveFields = additiveFields,
.coolDownNs = coolDownNs,
+ .puller = new StatsCallbackPuller(atomTag, callback),
.pullTimeoutNs = timeoutNs,
- .puller = new StatsCallbackPuller(atomTag, callback)};
+ };
}
void StatsPullerManager::UnregisterPullerCallback(int32_t atomTag) {
diff --git a/config/preloaded-classes b/config/preloaded-classes
index ab98e5b..0394a7a 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -514,6 +514,7 @@
android.app.admin.SystemUpdateInfo
android.app.admin.SystemUpdatePolicy$1
android.app.admin.SystemUpdatePolicy
+android.app.appsearch.AppSearchManagerFrameworkInitializer
android.app.assist.AssistContent$1
android.app.assist.AssistContent
android.app.assist.AssistStructure$1
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index fce7449..3ac88eb 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -10410,6 +10410,16 @@
p.recycle();
return brv;
}
+
+ /**
+ * Override and return true, since {@link RemoteViews#onLoadClass(Class)} is not overridden.
+ *
+ * @see RemoteViews#shouldUseStaticFilter()
+ */
+ @Override
+ protected boolean shouldUseStaticFilter() {
+ return true;
+ }
}
/**
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index d0ba879..5effa1b 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -22,6 +22,7 @@
import android.app.ContextImpl.ServiceInitializationState;
import android.app.admin.DevicePolicyManager;
import android.app.admin.IDevicePolicyManager;
+import android.app.appsearch.AppSearchManagerFrameworkInitializer;
import android.app.blob.BlobStoreManagerFrameworkInitializer;
import android.app.contentsuggestions.ContentSuggestionsManager;
import android.app.contentsuggestions.IContentSuggestionsManager;
@@ -166,12 +167,8 @@
import android.service.persistentdata.PersistentDataBlockManager;
import android.service.vr.IVrManager;
import android.telecom.TelecomManager;
-import android.telephony.CarrierConfigManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
+import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.TelephonyRegistryManager;
-import android.telephony.euicc.EuiccCardManager;
-import android.telephony.euicc.EuiccManager;
import android.util.ArrayMap;
import android.util.Log;
import android.view.ContextThemeWrapper;
@@ -604,13 +601,6 @@
return new SystemUpdateManager(service);
}});
- registerService(Context.TELEPHONY_SERVICE, TelephonyManager.class,
- new CachedServiceFetcher<TelephonyManager>() {
- @Override
- public TelephonyManager createService(ContextImpl ctx) {
- return new TelephonyManager(ctx.getOuterContext());
- }});
-
registerService(Context.TELEPHONY_REGISTRY_SERVICE, TelephonyRegistryManager.class,
new CachedServiceFetcher<TelephonyRegistryManager>() {
@Override
@@ -618,20 +608,6 @@
return new TelephonyRegistryManager(ctx);
}});
- registerService(Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class,
- new CachedServiceFetcher<SubscriptionManager>() {
- @Override
- public SubscriptionManager createService(ContextImpl ctx) throws ServiceNotFoundException {
- return new SubscriptionManager(ctx.getOuterContext());
- }});
-
- registerService(Context.CARRIER_CONFIG_SERVICE, CarrierConfigManager.class,
- new CachedServiceFetcher<CarrierConfigManager>() {
- @Override
- public CarrierConfigManager createService(ContextImpl ctx) {
- return new CarrierConfigManager(ctx.getOuterContext());
- }});
-
registerService(Context.TELECOM_SERVICE, TelecomManager.class,
new CachedServiceFetcher<TelecomManager>() {
@Override
@@ -639,20 +615,6 @@
return new TelecomManager(ctx.getOuterContext());
}});
- registerService(Context.EUICC_SERVICE, EuiccManager.class,
- new CachedServiceFetcher<EuiccManager>() {
- @Override
- public EuiccManager createService(ContextImpl ctx) {
- return new EuiccManager(ctx.getOuterContext());
- }});
-
- registerService(Context.EUICC_CARD_SERVICE, EuiccCardManager.class,
- new CachedServiceFetcher<EuiccCardManager>() {
- @Override
- public EuiccCardManager createService(ContextImpl ctx) {
- return new EuiccCardManager(ctx.getOuterContext());
- }});
-
registerService(Context.UI_MODE_SERVICE, UiModeManager.class,
new CachedServiceFetcher<UiModeManager>() {
@Override
@@ -1301,6 +1263,8 @@
JobSchedulerFrameworkInitializer.registerServiceWrappers();
BlobStoreManagerFrameworkInitializer.initialize();
+ TelephonyFrameworkInitializer.registerServiceWrappers();
+ AppSearchManagerFrameworkInitializer.initialize();
} finally {
// If any of the above code throws, we're in a pretty bad shape and the process
// will likely crash, but we'll reset it just in case there's an exception handler...
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 7703e08..8507316 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4898,6 +4898,15 @@
public static final String BATTERY_STATS_SERVICE = "batterystats";
/**
+ * Use with {@link #getSystemService(String)} to retrieve an
+ * AppSearchManager for indexing and querying app data managed
+ * by the system.
+ *
+ * @see #getSystemService(String)
+ */
+ public static final String APP_SEARCH_SERVICE = "app_search";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/content/om/OverlayableInfo.java b/core/java/android/content/om/OverlayableInfo.java
new file mode 100644
index 0000000..5923907
--- /dev/null
+++ b/core/java/android/content/om/OverlayableInfo.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.om;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.util.DataClass;
+
+import java.util.Objects;
+
+/**
+ * Immutable info on an overlayable defined inside a target package.
+ *
+ * @hide
+ */
+@DataClass(genSetters = false, genEqualsHashCode = true, genHiddenConstructor = true)
+public final class OverlayableInfo {
+
+ /**
+ * The "name" attribute of the overlayable tag. Used to identify the set of resources overlaid.
+ */
+ @NonNull
+ public final String name;
+
+ /**
+ * The "actor" attribute of the overlayable tag. Used to signal which apps are allowed to
+ * modify overlay state for this overlayable.
+ */
+ @Nullable
+ public final String actor;
+
+ // CHECKSTYLE:OFF Generated code
+ //
+
+
+
+ // Code below generated by codegen v1.0.3.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/om/OverlayableInfo.java
+
+
+ /**
+ * Creates a new OverlayableInfo.
+ *
+ * @param name
+ * The "name" attribute of the overlayable tag. Used to identify the set of resources overlaid.
+ * @param actor
+ * The "actor" attribute of the overlayable tag. Used to signal which apps are allowed to
+ * modify overlay state for this overlayable.
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public OverlayableInfo(
+ @NonNull String name,
+ @Nullable String actor) {
+ this.name = name;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, name);
+ this.actor = actor;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public boolean equals(Object o) {
+ // You can override field equality logic by defining either of the methods like:
+ // boolean fieldNameEquals(OverlayableInfo other) { ... }
+ // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ @SuppressWarnings("unchecked")
+ OverlayableInfo that = (OverlayableInfo) o;
+ //noinspection PointlessBooleanExpression
+ return true
+ && Objects.equals(name, that.name)
+ && Objects.equals(actor, that.actor);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int hashCode() {
+ // You can override field hashCode logic by defining methods like:
+ // int fieldNameHashCode() { ... }
+
+ int _hash = 1;
+ _hash = 31 * _hash + Objects.hashCode(name);
+ _hash = 31 * _hash + Objects.hashCode(actor);
+ return _hash;
+ }
+
+ @DataClass.Generated(
+ time = 1570059850579L,
+ codegenVersion = "1.0.3",
+ sourceFile = "frameworks/base/core/java/android/content/om/OverlayableInfo.java",
+ inputSignatures = "public final @android.annotation.NonNull java.lang.String name\npublic final @android.annotation.Nullable java.lang.String actor\nclass OverlayableInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genSetters=false, genEqualsHashCode=true, genHiddenConstructor=true)")
+ @Deprecated
+ private void __metadata() {}
+
+}
diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java
index de1d514..ad37555 100644
--- a/core/java/android/content/res/ApkAssets.java
+++ b/core/java/android/content/res/ApkAssets.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
+import android.content.om.OverlayableInfo;
import android.content.res.loader.ResourcesProvider;
import android.text.TextUtils;
@@ -254,6 +255,17 @@
}
}
+ /** @hide */
+ @Nullable
+ public OverlayableInfo getOverlayableInfo(String overlayableName) throws IOException {
+ return nativeGetOverlayableInfo(mNativePtr, overlayableName);
+ }
+
+ /** @hide */
+ public boolean definesOverlayable() throws IOException {
+ return nativeDefinesOverlayable(mNativePtr);
+ }
+
/**
* Returns false if the underlying APK was changed since this ApkAssets was loaded.
*/
@@ -305,4 +317,7 @@
private static native long nativeGetStringBlock(long ptr);
private static native boolean nativeIsUpToDate(long ptr);
private static native long nativeOpenXml(long ptr, @NonNull String fileName) throws IOException;
+ private static native @Nullable OverlayableInfo nativeGetOverlayableInfo(long ptr,
+ String overlayableName) throws IOException;
+ private static native boolean nativeDefinesOverlayable(long ptr) throws IOException;
}
diff --git a/core/java/android/os/HidlMemory.java b/core/java/android/os/HidlMemory.java
new file mode 100644
index 0000000..aeb6589
--- /dev/null
+++ b/core/java/android/os/HidlMemory.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * An abstract representation of a memory block, as representing by the HIDL system.
+ *
+ * The block is defined by a {name, size, handle} tuple, where the name is used to determine how to
+ * interpret the handle. The underlying handle is assumed to be owned by this instance and will be
+ * closed as soon as {@link #close()} is called on this instance, or this instance has been
+ * finalized (the latter supports using it in a shared manner without having to worry about who owns
+ * this instance, the former is more efficient resource-wise and is recommended for most use-cases).
+ * Note, however, that ownership of the handle does not necessarily imply ownership of the
+ * underlying file descriptors - the underlying handle may or may not own them. If you want the
+ * underlying handle to outlive this instance, call {@link #releaseHandle()} to obtain the handle
+ * and detach the ownership relationship.
+ *
+ * @hide
+ */
+@SystemApi
+@TestApi
+public class HidlMemory implements Closeable {
+ private final @NonNull String mName;
+ private final long mSize;
+ private @Nullable NativeHandle mHandle;
+ private long mNativeContext; // For use of native code.
+
+ /**
+ * Constructor.
+ *
+ * @param name The name of the IMapper service used to resolve the handle (e.g. "ashmem").
+ * @param size The (non-negative) size in bytes of the memory block.
+ * @param handle The handle. May be null. This instance will own the handle and will close it
+ * as soon as {@link #close()} is called or the object is destroyed. This, this
+ * handle instance should generally not be shared with other clients.
+ */
+ public HidlMemory(@NonNull String name, @IntRange(from = 0) long size,
+ @Nullable NativeHandle handle) {
+ mName = name;
+ mSize = size;
+ mHandle = handle;
+ }
+
+ /**
+ * Create a copy of this instance, where the underlying handle (and its file descriptors) have
+ * been duplicated.
+ */
+ @NonNull
+ public HidlMemory dup() throws IOException {
+ return new HidlMemory(mName, mSize, mHandle != null ? mHandle.dup() : null);
+ }
+
+ /**
+ * Close the underlying native handle. No-op if handle is null or has been released using {@link
+ * #releaseHandle()}.
+ */
+ @Override
+ public void close() throws IOException {
+ if (mHandle != null) {
+ mHandle.close();
+ }
+ }
+
+ /**
+ * Disowns the underlying handle and returns it. This object becomes invalid.
+ *
+ * @return The underlying handle.
+ */
+ @NonNull
+ public NativeHandle releaseHandle() {
+ NativeHandle handle = mHandle;
+ mHandle = null;
+ return handle;
+ }
+
+ /**
+ * Gets the name, which represents how the handle is to be interpreted.
+ *
+ * @return The name.
+ */
+ @NonNull
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Gets the size of the block, in bytes.
+ *
+ * @return The size.
+ */
+ public long getSize() {
+ return mSize;
+ }
+
+ /**
+ * Gets a native handle. The actual interpretation depends on the name and is implementation
+ * defined.
+ *
+ * @return The native handle.
+ */
+ @Nullable
+ public NativeHandle getHandle() {
+ return mHandle;
+ }
+
+ @Override
+ protected void finalize() {
+ try {
+ close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ nativeFinalize();
+ }
+ }
+
+ private native void nativeFinalize();
+}
diff --git a/core/java/android/os/HidlMemoryUtil.java b/core/java/android/os/HidlMemoryUtil.java
new file mode 100644
index 0000000..b08822d
--- /dev/null
+++ b/core/java/android/os/HidlMemoryUtil.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.os;
+
+import static android.system.OsConstants.MAP_SHARED;
+import static android.system.OsConstants.PROT_READ;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.Log;
+
+import com.android.internal.util.Preconditions;
+
+import java.nio.ByteBuffer;
+import java.nio.DirectByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Provides utilities for dealing with HidlMemory.
+ *
+ * @hide
+ */
+public final class HidlMemoryUtil {
+ static private final String TAG = "HidlMemoryUtil";
+
+ private HidlMemoryUtil() {
+ }
+
+ /**
+ * Copies a byte-array into a new Ashmem region and return it as HidlMemory.
+ * The returned instance owns the underlying file descriptors, and the client should generally
+ * call close on it when no longer in use (or otherwise, when the object gets destroyed it will
+ * be closed).
+ *
+ * @param input The input byte array.
+ * @return A HidlMemory instance, containing a copy of the input.
+ */
+ public static @NonNull
+ HidlMemory byteArrayToHidlMemory(@NonNull byte[] input) {
+ return byteArrayToHidlMemory(input, null);
+ }
+
+ /**
+ * Copies a byte-array into a new Ashmem region and return it as HidlMemory.
+ * The returned instance owns the underlying file descriptors, and the client should generally
+ * call close on it when no longer in use (or otherwise, when the object gets destroyed it will
+ * be closed).
+ *
+ * @param input The input byte array.
+ * @param name An optional name for the ashmem region.
+ * @return A HidlMemory instance, containing a copy of the input.
+ */
+ public static @NonNull
+ HidlMemory byteArrayToHidlMemory(@NonNull byte[] input, @Nullable String name) {
+ Preconditions.checkNotNull(input);
+
+ if (input.length == 0) {
+ return new HidlMemory("ashmem", 0, null);
+ }
+
+ try {
+ SharedMemory shmem = SharedMemory.create(name != null ? name : "", input.length);
+ ByteBuffer buffer = shmem.mapReadWrite();
+ buffer.put(input);
+ shmem.unmap(buffer);
+ NativeHandle handle = new NativeHandle(shmem.getFileDescriptor(), true);
+ return new HidlMemory("ashmem", input.length, handle);
+ } catch (ErrnoException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Copies a byte list into a new Ashmem region and return it as HidlMemory.
+ * The returned instance owns the underlying file descriptors, and the client should generally
+ * call close on it when no longer in use (or otherwise, when the object gets destroyed it will
+ * be closed).
+ *
+ * @param input The input byte list.
+ * @return A HidlMemory instance, containing a copy of the input.
+ */
+ public static @NonNull
+ HidlMemory byteListToHidlMemory(@NonNull List<Byte> input) {
+ return byteListToHidlMemory(input, null);
+ }
+
+ /**
+ * Copies a byte list into a new Ashmem region and return it as HidlMemory.
+ * The returned instance owns the underlying file descriptors, and the client should generally
+ * call close on it when no longer in use (or otherwise, when the object gets destroyed it will
+ * be closed).
+ *
+ * @param input The input byte list.
+ * @param name An optional name for the ashmem region.
+ * @return A HidlMemory instance, containing a copy of the input.
+ */
+ public static @NonNull
+ HidlMemory byteListToHidlMemory(@NonNull List<Byte> input, @Nullable String name) {
+ Preconditions.checkNotNull(input);
+
+ if (input.isEmpty()) {
+ return new HidlMemory("ashmem", 0, null);
+ }
+
+ try {
+ SharedMemory shmem = SharedMemory.create(name != null ? name : "", input.size());
+ ByteBuffer buffer = shmem.mapReadWrite();
+ for (Byte b : input) {
+ buffer.put(b);
+ }
+ shmem.unmap(buffer);
+ NativeHandle handle = new NativeHandle(shmem.getFileDescriptor(), true);
+ return new HidlMemory("ashmem", input.size(), handle);
+ } catch (ErrnoException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Copies all data from a HidlMemory instance into a byte array.
+ *
+ * @param mem The HidlMemory instance. Must be of name "ashmem" and of size that doesn't exceed
+ * {@link Integer#MAX_VALUE}.
+ * @return A byte array, containing a copy of the input.
+ */
+ public static @NonNull
+ byte[] hidlMemoryToByteArray(@NonNull HidlMemory mem) {
+ Preconditions.checkNotNull(mem);
+ Preconditions.checkArgumentInRange(mem.getSize(), 0L, (long) Integer.MAX_VALUE,
+ "Memory size");
+ Preconditions.checkArgument(mem.getSize() == 0 || mem.getName().equals("ashmem"),
+ "Unsupported memory type: %s", mem.getName());
+
+ if (mem.getSize() == 0) {
+ return new byte[0];
+ }
+
+ ByteBuffer buffer = getBuffer(mem);
+ byte[] result = new byte[buffer.remaining()];
+ buffer.get(result);
+ return result;
+ }
+
+ /**
+ * Copies all data from a HidlMemory instance into a byte list.
+ *
+ * @param mem The HidlMemory instance. Must be of name "ashmem" and of size that doesn't exceed
+ * {@link Integer#MAX_VALUE}.
+ * @return A byte list, containing a copy of the input.
+ */
+ @SuppressLint("ConcreteCollection")
+ public static @NonNull
+ ArrayList<Byte> hidlMemoryToByteList(@NonNull HidlMemory mem) {
+ Preconditions.checkNotNull(mem);
+ Preconditions.checkArgumentInRange(mem.getSize(), 0L, (long) Integer.MAX_VALUE,
+ "Memory size");
+ Preconditions.checkArgument(mem.getSize() == 0 || mem.getName().equals("ashmem"),
+ "Unsupported memory type: %s", mem.getName());
+
+ if (mem.getSize() == 0) {
+ return new ArrayList<>();
+ }
+
+ ByteBuffer buffer = getBuffer(mem);
+
+ ArrayList<Byte> result = new ArrayList<>(buffer.remaining());
+ while (buffer.hasRemaining()) {
+ result.add(buffer.get());
+ }
+ return result;
+ }
+
+ private static ByteBuffer getBuffer(@NonNull HidlMemory mem) {
+ try {
+ final int size = (int) mem.getSize();
+
+ if (size == 0) {
+ return ByteBuffer.wrap(new byte[0]);
+ }
+
+ NativeHandle handle = mem.getHandle();
+
+ final long address = Os.mmap(0, size, PROT_READ, MAP_SHARED, handle.getFileDescriptor(),
+ 0);
+ return new DirectByteBuffer(size, address, handle.getFileDescriptor(), () -> {
+ try {
+ Os.munmap(address, size);
+ } catch (ErrnoException e) {
+ Log.wtf(TAG, e);
+ }
+ }, true);
+ } catch (ErrnoException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/core/java/android/os/HwBlob.java b/core/java/android/os/HwBlob.java
index 2c453bf..154227b2 100644
--- a/core/java/android/os/HwBlob.java
+++ b/core/java/android/os/HwBlob.java
@@ -92,6 +92,14 @@
* @throws IndexOutOfBoundsException when offset is out of this HwBlob
*/
public native final String getString(long offset);
+ /**
+ * For embedded fields that follow a two-step approach for reading, first obtain their field
+ * handle using this method, and pass that field handle to the respective
+ * HwParcel.readEmbedded*() method.
+ * @param offset The field offset.
+ * @return The field handle.
+ */
+ public native final long getFieldHandle(long offset);
/**
* Copy the blobs data starting from the given byte offset into the range, copying
@@ -312,6 +320,20 @@
public native final void putBlob(long offset, HwBlob blob);
/**
+ * Writes a HidlMemory instance (without duplicating the underlying file descriptors) at an
+ * offset.
+ *
+ * @param offset location to write value
+ * @param mem a {@link HidlMemory} instance to write
+ * @throws IndexOutOfBoundsException when [offset, offset + sizeof(jobject)] is out of range
+ */
+ public final void putHidlMemory(long offset, @NonNull HidlMemory mem) {
+ putNativeHandle(offset + 0 /* offset of 'handle' field. */, mem.getHandle());
+ putInt64(offset + 16 /* offset of 'size' field. */, mem.getSize());
+ putString(offset + 24 /* offset of 'name' field. */, mem.getName());
+ }
+
+ /**
* @return current handle of HwBlob for reference in a parcelled binder transaction
*/
public native final long handle();
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index 5e8929c..9786f16 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -324,6 +324,15 @@
public native final void writeStrongBinder(IHwBinder binder);
/**
+ * Write a HidlMemory object (without duplicating the underlying file descriptors) to the end
+ * of the parcel.
+ *
+ * @param memory value to write
+ */
+ @FastNative
+ public native final void writeHidlMemory(@NonNull HidlMemory memory);
+
+ /**
* Checks to make sure that the interface name matches the name written by the parcel
* sender by writeInterfaceToken
*
@@ -582,6 +591,38 @@
public native final IHwBinder readStrongBinder();
/**
+ * Reads a HidlMemory value (without duplicating the underlying file
+ * descriptors) from the parcel. These file descriptors will only
+ * be open for the duration that the binder window is open. If they
+ * are needed further, you must call {@link HidlMemory#dup()}, which makes you also
+ * responsible for calling {@link HidlMemory#close()}.
+ *
+ * @return HidlMemory object read from parcel.
+ * @throws IllegalArgumentException if the parcel has no more data or is otherwise corrupt.
+ */
+ @FastNative
+ @NonNull
+ public native final HidlMemory readHidlMemory();
+
+ /**
+ * Reads an embedded HidlMemory (without duplicating the underlying
+ * file descriptors) from the parcel. These file descriptors will only
+ * be open for the duration that the binder window is open. If they
+ * are needed further, you must call {@link HidlMemory#dup()}. You
+ * do not need to call close on the HidlMemory returned from this.
+ *
+ * @param fieldHandle handle of the field, obtained from the {@link HwBlob}.
+ * @param parentHandle parentHandle from which to read the embedded object
+ * @param offset offset into parent
+ * @return a {@link HidlMemory} instance parsed from the parcel
+ * @throws IllegalArgumentException if the parcel has no more data
+ */
+ @FastNative
+ @NonNull
+ public native final @Nullable
+ HidlMemory readEmbeddedHidlMemory(long fieldHandle, long parentHandle, long offset);
+
+ /**
* Read opaque segment of data as a blob.
* @return blob of size expectedSize
* @throws IllegalArgumentException if the parcel has no more data
diff --git a/core/java/android/os/StatsLogEventWrapper.java b/core/java/android/os/StatsLogEventWrapper.java
index 89c9bb2..320fc13 100644
--- a/core/java/android/os/StatsLogEventWrapper.java
+++ b/core/java/android/os/StatsLogEventWrapper.java
@@ -139,7 +139,7 @@
out.writeLong(mElapsedTimeNs);
out.writeLong(mWallClockTimeNs);
if (mWorkSource != null) {
- ArrayList<android.os.WorkSource.WorkChain> workChains = mWorkSource.getWorkChains();
+ List<WorkSource.WorkChain> workChains = mWorkSource.getWorkChains();
// number of chains
out.writeInt(workChains.size());
for (int i = 0; i < workChains.size(); i++) {
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index 825fc64..b5635a4 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -13,13 +13,15 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
/**
* Describes the source of some work that may be done by someone else.
- * Currently the public representation of what a work source is is not
+ * Currently the public representation of what a work source is not
* defined; this is an opaque container.
*/
public class WorkSource implements Parcelable {
@@ -48,7 +50,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
static WorkSource sNewbWork;
/**
- * For returning gone work form a modification operation.
+ * For returning gone work from a modification operation.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
static WorkSource sGoneWork;
@@ -91,9 +93,14 @@
}
}
- /** @hide */
- @UnsupportedAppUsage
+
+ /**
+ * Creates a work source with the given uid.
+ * @param uid the uid performing the work
+ * @hide
+ */
@TestApi
+ @SystemApi
public WorkSource(int uid) {
mNum = 1;
mUids = new int[] { uid, 0 };
@@ -101,14 +108,18 @@
mChains = null;
}
- /** @hide */
- public WorkSource(int uid, String name) {
- if (name == null) {
- throw new NullPointerException("Name can't be null");
- }
+ /**
+ * Creates a work source with the given uid and package name.
+ * @param uid the uid performing the work
+ * @param packageName the package performing the work
+ * @hide
+ */
+ @SystemApi
+ public WorkSource(int uid, @NonNull String packageName) {
+ Preconditions.checkNotNull(packageName, "packageName can't be null");
mNum = 1;
mUids = new int[] { uid, 0 };
- mNames = new String[] { name, null };
+ mNames = new String[] { packageName, null };
mChains = null;
}
@@ -138,17 +149,34 @@
Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED, 0) == 1;
}
- /** @hide */
- @UnsupportedAppUsage
+ /**
+ * Returns the size of this work source.
+ * @hide
+ */
@TestApi
+ @SystemApi
public int size() {
return mNum;
}
- /** @hide */
+ /**
+ * @deprecated use {{@link #getUid(int)}} instead.
+ * @hide
+ */
@UnsupportedAppUsage
- @TestApi
+ @Deprecated
public int get(int index) {
+ return getUid(index);
+ }
+
+ /**
+ * Get the uid at the given index.
+ * If {@code index} < 0 or {@code index} >= {@link #size() N}, then the behavior is undefined.
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ public int getUid(int index) {
return mUids[index];
}
@@ -167,10 +195,25 @@
return mNum > 0 ? mUids[0] : mChains.get(0).getAttributionUid();
}
- /** @hide */
+ /**
+ * @deprecated use {{@link #getPackageName(int)}} instead.
+ * @hide
+ */
@UnsupportedAppUsage
- @TestApi
+ @Deprecated
public String getName(int index) {
+ return getPackageName(index);
+ }
+
+ /**
+ * Get the package name at the given index.
+ * If {@code index} < 0 or {@code index} >= {@link #size() N}, then the behavior is undefined.
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ @Nullable
+ public String getPackageName(int index) {
return mNames != null ? mNames[index] : null;
}
@@ -179,9 +222,8 @@
* intact.
*
* <p>Useful when combining with another WorkSource that doesn't have names.
- * @hide
*/
- public void clearNames() {
+ private void clearNames() {
if (mNames != null) {
mNames = null;
// Clear out any duplicate uids now that we don't have names to disambiguate them.
@@ -407,6 +449,22 @@
}
/**
+ * Returns a copy of this work source without any package names.
+ * If any {@link WorkChain WorkChains} are present, they are left intact.
+ *
+ * @return a {@link WorkSource} without any package names.
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @NonNull
+ public WorkSource withoutNames() {
+ final WorkSource copy = new WorkSource(this);
+ copy.clearNames();
+ return copy;
+ }
+
+ /**
* Legacy API: DO NOT USE. Only in use from unit tests.
*
* @hide
@@ -524,6 +582,8 @@
*
* @hide for internal use only.
*/
+ @SystemApi
+ @TestApi
public boolean isEmpty() {
return mNum == 0 && (mChains == null || mChains.isEmpty());
}
@@ -532,7 +592,9 @@
* @return the list of {@code WorkChains} associated with this {@code WorkSource}.
* @hide
*/
- public ArrayList<WorkChain> getWorkChains() {
+ @SystemApi
+ @Nullable
+ public List<WorkChain> getWorkChains() {
return mChains;
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 3251127..6458737 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -199,6 +199,8 @@
private static native void nativeWriteTransactionToParcel(long nativeObject, Parcel out);
private static native void nativeSetShadowRadius(long transactionObj, long nativeObject,
float shadowRadius);
+ private static native void nativeSetGlobalShadowSettings(@Size(4) float[] ambientColor,
+ @Size(4) float[] spotColor, float lightPosY, float lightPosZ, float lightRadius);
private final CloseGuard mCloseGuard = CloseGuard.get();
private String mName;
@@ -1979,6 +1981,42 @@
return sc;
}
+ private static void validateColorArg(@Size(4) float[] color) {
+ final String msg = "Color must be specified as a float array with"
+ + " four values to represent r, g, b, a in range [0..1]";
+ if (color.length != 4) {
+ throw new IllegalArgumentException(msg);
+ }
+ for (float c:color) {
+ if ((c < 0.f) || (c > 1.f)) {
+ throw new IllegalArgumentException(msg);
+ }
+ }
+ }
+
+ /**
+ * Sets the global configuration for all the shadows drawn by SurfaceFlinger. Shadow follows
+ * material design guidelines.
+ *
+ * @param ambientColor Color applied to the ambient shadow. The alpha is premultiplied. A
+ * float array with four values to represent r, g, b, a in range [0..1]
+ * @param spotColor Color applied to the spot shadow. The alpha is premultiplied. The position
+ * of the spot shadow depends on the light position. A float array with
+ * four values to represent r, g, b, a in range [0..1]
+ * @param lightPosY Y axis position of the light used to cast the spot shadow in pixels.
+ * @param lightPosZ Z axis position of the light used to cast the spot shadow in pixels. The X
+ * axis position is set to the display width / 2.
+ * @param lightRadius Radius of the light casting the shadow in pixels.
+ *[
+ * @hide
+ */
+ public static void setGlobalShadowSettings(@Size(4) float[] ambientColor,
+ @Size(4) float[] spotColor, float lightPosY, float lightPosZ, float lightRadius) {
+ validateColorArg(ambientColor);
+ validateColorArg(spotColor);
+ nativeSetGlobalShadowSettings(ambientColor, spotColor, lightPosY, lightPosZ, lightRadius);
+ }
+
/**
* An atomic set of changes to a set of SurfaceControl.
*/
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 89b111d..afa661e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -4966,6 +4966,8 @@
protected static final int FINISH_HANDLED = 1;
protected static final int FINISH_NOT_HANDLED = 2;
+ private String mTracePrefix;
+
/**
* Creates an input stage.
* @param next The next stage to which events should be forwarded.
@@ -4983,7 +4985,14 @@
} else if (shouldDropInputEvent(q)) {
finish(q, false);
} else {
- apply(q, onProcess(q));
+ traceEvent(q, Trace.TRACE_TAG_VIEW);
+ final int result;
+ try {
+ result = onProcess(q);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ apply(q, result);
}
}
@@ -5093,6 +5102,17 @@
return false;
}
}
+
+ private void traceEvent(QueuedInputEvent q, long traceTag) {
+ if (!Trace.isTagEnabled(traceTag)) {
+ return;
+ }
+
+ if (mTracePrefix == null) {
+ mTracePrefix = getClass().getSimpleName();
+ }
+ Trace.traceBegin(traceTag, mTracePrefix + " seq#=" + q.mEvent.getSequenceNumber());
+ }
}
/**
@@ -7709,26 +7729,46 @@
private void deliverInputEvent(QueuedInputEvent q) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
q.mEvent.getSequenceNumber());
- if (mInputEventConsistencyVerifier != null) {
- mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
- }
- InputStage stage;
- if (q.shouldSendToSynthesizer()) {
- stage = mSyntheticInputStage;
- } else {
- stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent src=0x"
+ + Integer.toHexString(q.mEvent.getSource()) + " eventTimeNano="
+ + q.mEvent.getEventTimeNano() + " seq#=" + q.mEvent.getSequenceNumber());
}
+ try {
+ if (mInputEventConsistencyVerifier != null) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "verifyEventConsistency");
+ try {
+ mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ }
- if (q.mEvent instanceof KeyEvent) {
- mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
- }
+ InputStage stage;
+ if (q.shouldSendToSynthesizer()) {
+ stage = mSyntheticInputStage;
+ } else {
+ stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
+ }
- if (stage != null) {
- handleWindowFocusChanged();
- stage.deliver(q);
- } else {
- finishInputEvent(q);
+ if (q.mEvent instanceof KeyEvent) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "preDispatchToUnhandledKeyManager");
+ try {
+ mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ }
+
+ if (stage != null) {
+ handleWindowFocusChanged();
+ stage.deliver(q);
+ } else {
+ finishInputEvent(q);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 86cec5e..c571737 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -202,6 +202,14 @@
public static final int FLAG_USE_LIGHT_BACKGROUND_LAYOUT = 4;
/**
+ * Used to restrict the views which can be inflated
+ *
+ * @see android.view.LayoutInflater.Filter#onLoadClass(java.lang.Class)
+ */
+ private static final LayoutInflater.Filter INFLATER_FILTER =
+ (clazz) -> clazz.isAnnotationPresent(RemoteViews.RemoteView.class);
+
+ /**
* Application that hosts the remote views.
*
* @hide
@@ -3413,13 +3421,24 @@
// Clone inflater so we load resources from correct context and
// we don't add a filter to the static version returned by getSystemService.
inflater = inflater.cloneInContext(inflationContext);
- inflater.setFilter(this);
+ inflater.setFilter(shouldUseStaticFilter() ? INFLATER_FILTER : this);
View v = inflater.inflate(rv.getLayoutId(), parent, false);
v.setTagInternal(R.id.widget_frame, rv.getLayoutId());
return v;
}
/**
+ * A static filter is much lighter than RemoteViews itself. It's optimized here only for
+ * RemoteVies class. Subclasses should always override this and return true if not overriding
+ * {@link this#onLoadClass(Class)}.
+ *
+ * @hide
+ */
+ protected boolean shouldUseStaticFilter() {
+ return this.getClass().equals(RemoteViews.class);
+ }
+
+ /**
* Implement this interface to receive a callback when
* {@link #applyAsync} or {@link #reapplyAsync} is finished.
* @hide
@@ -3686,11 +3705,15 @@
return (mActions == null) ? 0 : mActions.size();
}
- /* (non-Javadoc)
+ /**
* Used to restrict the views which can be inflated
*
* @see android.view.LayoutInflater.Filter#onLoadClass(java.lang.Class)
+ * @deprecated Used by system to enforce safe inflation of {@link RemoteViews}. Apps should not
+ * override this method. Changing of this method will NOT affect the process where RemoteViews
+ * is rendered.
*/
+ @Deprecated
public boolean onLoadClass(Class clazz) {
return clazz.isAnnotationPresent(RemoteView.class);
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index f5bfe5c..75a5804 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -4086,7 +4086,7 @@
if (workSource != null) {
for (int i = 0; i < workSource.size(); ++i) {
- uid = mapUid(workSource.get(i));
+ uid = mapUid(workSource.getUid(i));
if (mActiveEvents.updateState(historyItem, name, uid, 0)) {
addHistoryEventLocked(elapsedRealtime, uptime, historyItem, name, uid);
}
@@ -4114,8 +4114,8 @@
String tag) {
if (workSource != null) {
for (int i = 0; i < workSource.size(); ++i) {
- uid = workSource.get(i);
- final String workSourceName = workSource.getName(i);
+ uid = workSource.getUid(i);
+ final String workSourceName = workSource.getPackageName(i);
if (isOnBattery()) {
BatteryStatsImpl.Uid.Pkg pkg = getPackageStatsLocked(uid,
@@ -4124,7 +4124,7 @@
}
}
- ArrayList<WorkChain> workChains = workSource.getWorkChains();
+ List<WorkChain> workChains = workSource.getWorkChains();
if (workChains != null) {
for (int i = 0; i < workChains.size(); ++i) {
final WorkChain wc = workChains.get(i);
@@ -4350,7 +4350,7 @@
final long uptime = mClocks.uptimeMillis();
final int N = ws.size();
for (int i=0; i<N; i++) {
- noteStartWakeLocked(ws.get(i), pid, null, name, historyName, type,
+ noteStartWakeLocked(ws.getUid(i), pid, null, name, historyName, type,
unimportantForLogging, elapsedRealtime, uptime);
}
@@ -4379,7 +4379,7 @@
// First the starts :
final int NN = newWs.size();
for (int i=0; i<NN; i++) {
- noteStartWakeLocked(newWs.get(i), newPid, null, newName, newHistoryName, newType,
+ noteStartWakeLocked(newWs.getUid(i), newPid, null, newName, newHistoryName, newType,
newUnimportantForLogging, elapsedRealtime, uptime);
}
if (wcs != null) {
@@ -4397,7 +4397,7 @@
// Then the stops :
final int NO = ws.size();
for (int i=0; i<NO; i++) {
- noteStopWakeLocked(ws.get(i), pid, null, name, historyName, type, elapsedRealtime,
+ noteStopWakeLocked(ws.getUid(i), pid, null, name, historyName, type, elapsedRealtime,
uptime);
}
if (wcs != null) {
@@ -4418,7 +4418,7 @@
final long uptime = mClocks.uptimeMillis();
final int N = ws.size();
for (int i=0; i<N; i++) {
- noteStopWakeLocked(ws.get(i), pid, null, name, historyName, type, elapsedRealtime,
+ noteStopWakeLocked(ws.getUid(i), pid, null, name, historyName, type, elapsedRealtime,
uptime);
}
@@ -4441,11 +4441,11 @@
WorkSource workSource) {
final int N = workSource.size();
for (int i = 0; i < N; ++i) {
- final int uid = mapUid(workSource.get(i));
+ final int uid = mapUid(workSource.getUid(i));
noteLongPartialWakeLockStartInternal(name, historyName, uid);
}
- final ArrayList<WorkChain> workChains = workSource.getWorkChains();
+ final List<WorkChain> workChains = workSource.getWorkChains();
if (workChains != null) {
for (int i = 0; i < workChains.size(); ++i) {
final WorkChain workChain = workChains.get(i);
@@ -4478,11 +4478,11 @@
WorkSource workSource) {
final int N = workSource.size();
for (int i = 0; i < N; ++i) {
- final int uid = mapUid(workSource.get(i));
+ final int uid = mapUid(workSource.getUid(i));
noteLongPartialWakeLockFinishInternal(name, historyName, uid);
}
- final ArrayList<WorkChain> workChains = workSource.getWorkChains();
+ final List<WorkChain> workChains = workSource.getWorkChains();
if (workChains != null) {
for (int i = 0; i < workChains.size(); ++i) {
final WorkChain workChain = workChains.get(i);
@@ -4615,11 +4615,11 @@
public void noteGpsChangedLocked(WorkSource oldWs, WorkSource newWs) {
for (int i = 0; i < newWs.size(); ++i) {
- noteStartGpsLocked(newWs.get(i), null);
+ noteStartGpsLocked(newWs.getUid(i), null);
}
for (int i = 0; i < oldWs.size(); ++i) {
- noteStopGpsLocked((oldWs.get(i)), null);
+ noteStopGpsLocked((oldWs.getUid(i)), null);
}
List<WorkChain>[] wcs = WorkSource.diffChains(oldWs, newWs);
@@ -5564,7 +5564,7 @@
public void noteBluetoothScanStartedFromSourceLocked(WorkSource ws, boolean isUnoptimized) {
final int N = ws.size();
for (int i = 0; i < N; i++) {
- noteBluetoothScanStartedLocked(null, ws.get(i), isUnoptimized);
+ noteBluetoothScanStartedLocked(null, ws.getUid(i), isUnoptimized);
}
final List<WorkChain> workChains = ws.getWorkChains();
@@ -5602,7 +5602,7 @@
public void noteBluetoothScanStoppedFromSourceLocked(WorkSource ws, boolean isUnoptimized) {
final int N = ws.size();
for (int i = 0; i < N; i++) {
- noteBluetoothScanStoppedLocked(null, ws.get(i), isUnoptimized);
+ noteBluetoothScanStoppedLocked(null, ws.getUid(i), isUnoptimized);
}
final List<WorkChain> workChains = ws.getWorkChains();
@@ -5633,7 +5633,7 @@
public void noteBluetoothScanResultsFromSourceLocked(WorkSource ws, int numNewResults) {
final int N = ws.size();
for (int i = 0; i < N; i++) {
- int uid = mapUid(ws.get(i));
+ int uid = mapUid(ws.getUid(i));
getUidStatsLocked(uid).noteBluetoothScanResultsLocked(numNewResults);
}
@@ -5692,7 +5692,7 @@
mGlobalWifiRunningTimer.startRunningLocked(elapsedRealtime);
int N = ws.size();
for (int i=0; i<N; i++) {
- int uid = mapUid(ws.get(i));
+ int uid = mapUid(ws.getUid(i));
getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime);
}
@@ -5715,7 +5715,7 @@
final long elapsedRealtime = mClocks.elapsedRealtime();
int N = oldWs.size();
for (int i=0; i<N; i++) {
- int uid = mapUid(oldWs.get(i));
+ int uid = mapUid(oldWs.getUid(i));
getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime);
}
@@ -5729,7 +5729,7 @@
N = newWs.size();
for (int i=0; i<N; i++) {
- int uid = mapUid(newWs.get(i));
+ int uid = mapUid(newWs.getUid(i));
getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime);
}
@@ -5757,7 +5757,7 @@
mGlobalWifiRunningTimer.stopRunningLocked(elapsedRealtime);
int N = ws.size();
for (int i=0; i<N; i++) {
- int uid = mapUid(ws.get(i));
+ int uid = mapUid(ws.getUid(i));
getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime);
}
@@ -5963,7 +5963,7 @@
public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws) {
int N = ws.size();
for (int i=0; i<N; i++) {
- final int uid = mapUid(ws.get(i));
+ final int uid = mapUid(ws.getUid(i));
noteFullWifiLockAcquiredLocked(uid);
}
@@ -5980,7 +5980,7 @@
public void noteFullWifiLockReleasedFromSourceLocked(WorkSource ws) {
int N = ws.size();
for (int i=0; i<N; i++) {
- final int uid = mapUid(ws.get(i));
+ final int uid = mapUid(ws.getUid(i));
noteFullWifiLockReleasedLocked(uid);
}
@@ -5997,7 +5997,7 @@
public void noteWifiScanStartedFromSourceLocked(WorkSource ws) {
int N = ws.size();
for (int i=0; i<N; i++) {
- final int uid = mapUid(ws.get(i));
+ final int uid = mapUid(ws.getUid(i));
noteWifiScanStartedLocked(uid);
}
@@ -6014,7 +6014,7 @@
public void noteWifiScanStoppedFromSourceLocked(WorkSource ws) {
int N = ws.size();
for (int i=0; i<N; i++) {
- final int uid = mapUid(ws.get(i));
+ final int uid = mapUid(ws.getUid(i));
noteWifiScanStoppedLocked(uid);
}
@@ -6031,7 +6031,7 @@
public void noteWifiBatchedScanStartedFromSourceLocked(WorkSource ws, int csph) {
int N = ws.size();
for (int i=0; i<N; i++) {
- noteWifiBatchedScanStartedLocked(ws.get(i), csph);
+ noteWifiBatchedScanStartedLocked(ws.getUid(i), csph);
}
final List<WorkChain> workChains = ws.getWorkChains();
@@ -6045,7 +6045,7 @@
public void noteWifiBatchedScanStoppedFromSourceLocked(WorkSource ws) {
int N = ws.size();
for (int i=0; i<N; i++) {
- noteWifiBatchedScanStoppedLocked(ws.get(i));
+ noteWifiBatchedScanStoppedLocked(ws.getUid(i));
}
final List<WorkChain> workChains = ws.getWorkChains();
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index ed7f5de..49a73ee 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -18,6 +18,7 @@
import static com.android.internal.util.ArrayUtils.appendInt;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.pm.FeatureInfo;
@@ -221,6 +222,12 @@
private ArrayMap<String, Set<String>> mPackageToUserTypeWhitelist = new ArrayMap<>();
private ArrayMap<String, Set<String>> mPackageToUserTypeBlacklist = new ArrayMap<>();
+ /**
+ * Map of system pre-defined, uniquely named actors; keys are namespace,
+ * value maps actor name to package name.
+ */
+ private ArrayMap<String, ArrayMap<String, String>> mNamedActors = null;
+
public static SystemConfig getInstance() {
if (!isSystemProcess()) {
Slog.wtf(TAG, "SystemConfig is being accessed by a process other than "
@@ -398,12 +405,17 @@
return r;
}
+ @NonNull
+ public Map<String, ? extends Map<String, String>> getNamedActors() {
+ return mNamedActors != null ? mNamedActors : Collections.emptyMap();
+ }
+
/**
* Only use for testing. Do NOT use in production code.
* @param readPermissions false to create an empty SystemConfig; true to read the permissions.
*/
@VisibleForTesting
- protected SystemConfig(boolean readPermissions) {
+ public SystemConfig(boolean readPermissions) {
if (readPermissions) {
Slog.w(TAG, "Constructing a test SystemConfig");
readAllPermissions();
@@ -1028,6 +1040,44 @@
readInstallInUserType(parser,
mPackageToUserTypeWhitelist, mPackageToUserTypeBlacklist);
} break;
+ case "named-actor": {
+ String namespace = TextUtils.safeIntern(
+ parser.getAttributeValue(null, "namespace"));
+ String actorName = parser.getAttributeValue(null, "name");
+ String pkgName = TextUtils.safeIntern(
+ parser.getAttributeValue(null, "package"));
+ if (TextUtils.isEmpty(namespace)) {
+ Slog.wtf(TAG, "<" + name + "> without namespace in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else if (TextUtils.isEmpty(actorName)) {
+ Slog.wtf(TAG, "<" + name + "> without actor name in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else if (TextUtils.isEmpty(pkgName)) {
+ Slog.wtf(TAG, "<" + name + "> without package name in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else if ("android".equalsIgnoreCase(namespace)) {
+ throw new IllegalStateException("Defining " + actorName + " as "
+ + pkgName + " for the android namespace is not allowed");
+ } else {
+ if (mNamedActors == null) {
+ mNamedActors = new ArrayMap<>();
+ }
+
+ ArrayMap<String, String> nameToPkgMap = mNamedActors.get(namespace);
+ if (nameToPkgMap == null) {
+ nameToPkgMap = new ArrayMap<>();
+ mNamedActors.put(namespace, nameToPkgMap);
+ } else if (nameToPkgMap.containsKey(actorName)) {
+ String existing = nameToPkgMap.get(actorName);
+ throw new IllegalStateException("Duplicate actor definition for "
+ + namespace + "/" + actorName
+ + "; defined as both " + existing + " and " + pkgName);
+ }
+
+ nameToPkgMap.put(actorName, pkgName);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } break;
default: {
Slog.w(TAG, "Tag " + name + " is unknown in "
+ permFile + " at " + parser.getPositionDescription());
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index ea10949..51f8fcc 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -125,6 +125,7 @@
"android_text_Hyphenator.cpp",
"android_os_Debug.cpp",
"android_os_GraphicsEnvironment.cpp",
+ "android_os_HidlMemory.cpp",
"android_os_HidlSupport.cpp",
"android_os_HwBinder.cpp",
"android_os_HwBlob.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 32d62fe..378e125 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -147,6 +147,7 @@
extern int register_android_os_Trace(JNIEnv* env);
extern int register_android_os_FileObserver(JNIEnv *env);
extern int register_android_os_UEventObserver(JNIEnv* env);
+extern int register_android_os_HidlMemory(JNIEnv* env);
extern int register_android_os_MemoryFile(JNIEnv* env);
extern int register_android_os_SharedMemory(JNIEnv* env);
extern int register_android_net_LocalSocketImpl(JNIEnv* env);
@@ -1432,6 +1433,7 @@
REG_JNI(register_android_os_SystemProperties),
REG_JNI(register_android_os_Binder),
REG_JNI(register_android_os_Parcel),
+ REG_JNI(register_android_os_HidlMemory),
REG_JNI(register_android_os_HidlSupport),
REG_JNI(register_android_os_HwBinder),
REG_JNI(register_android_os_HwBlob),
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
index 6370253..f3a626e 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -194,6 +194,59 @@
return reinterpret_cast<jlong>(xml_tree.release());
}
+static jobject NativeGetOverlayableInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr,
+ jstring overlayable_name) {
+ const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
+
+ const auto& packages = apk_assets->GetLoadedArsc()->GetPackages();
+ if (packages.empty()) {
+ jniThrowException(env, "java/io/IOException", "Error reading overlayable from APK");
+ return 0;
+ }
+
+ // TODO(b/119899133): Convert this to a search for the info rather than assuming it's at index 0
+ const auto& overlayable_map = packages[0]->GetOverlayableMap();
+ if (overlayable_map.empty()) {
+ return nullptr;
+ }
+
+ auto overlayable_name_native = std::string(env->GetStringUTFChars(overlayable_name, NULL));
+ auto actor = overlayable_map.find(overlayable_name_native);
+ if (actor == overlayable_map.end()) {
+ return nullptr;
+ }
+
+ jstring actor_string = env->NewStringUTF(actor->first.c_str());
+ if (env->ExceptionCheck() || actor_string == nullptr) {
+ jniThrowException(env, "java/io/IOException", "Error reading overlayable from APK");
+ return 0;
+ }
+
+ jclass overlayable_class = env->FindClass("android/content/om/OverlayableInfo");
+ jmethodID overlayable_constructor = env->GetMethodID(overlayable_class, "<init>",
+ "(Ljava/lang/String;Ljava/lang/String;I)V");
+ return env->NewObject(
+ overlayable_class,
+ overlayable_constructor,
+ overlayable_name,
+ actor_string
+ );
+}
+
+static jboolean NativeDefinesOverlayable(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
+ const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
+
+ const auto& packages = apk_assets->GetLoadedArsc()->GetPackages();
+ if (packages.empty()) {
+ // Must throw to prevent bypass by returning false
+ jniThrowException(env, "java/io/IOException", "Error reading overlayable from APK");
+ return 0;
+ }
+
+ const auto& overlayable_infos = packages[0]->GetOverlayableMap();
+ return overlayable_infos.empty() ? JNI_FALSE : JNI_TRUE;
+}
+
// JNI registration.
static const JNINativeMethod gApkAssetsMethods[] = {
{"nativeLoad", "(Ljava/lang/String;ZZZZ)J", (void*)NativeLoad},
@@ -208,6 +261,9 @@
{"nativeGetStringBlock", "(J)J", (void*)NativeGetStringBlock},
{"nativeIsUpToDate", "(J)Z", (void*)NativeIsUpToDate},
{"nativeOpenXml", "(JLjava/lang/String;)J", (void*)NativeOpenXml},
+ {"nativeGetOverlayableInfo", "(JLjava/lang/String;)Landroid/content/om/OverlayableInfo;",
+ (void*)NativeGetOverlayableInfo},
+ {"nativeDefinesOverlayable", "(J)Z", (void*)NativeDefinesOverlayable},
};
int register_android_content_res_ApkAssets(JNIEnv* env) {
diff --git a/core/jni/android_os_HidlMemory.cpp b/core/jni/android_os_HidlMemory.cpp
new file mode 100644
index 0000000..69e4818
--- /dev/null
+++ b/core/jni/android_os_HidlMemory.cpp
@@ -0,0 +1,162 @@
+/*
+ * 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.
+ */
+
+#include "android_os_HidlMemory.h"
+#include "core_jni_helpers.h"
+#include "android_os_NativeHandle.h"
+
+#define PACKAGE_PATH "android/os"
+#define CLASS_NAME "HidlMemory"
+#define CLASS_PATH PACKAGE_PATH "/" CLASS_NAME
+
+namespace android {
+
+namespace {
+
+static struct {
+ jclass clazz;
+ jfieldID nativeContext; // long
+ jmethodID constructor; // HidlMemory(String, long, NativeHandle)
+ jmethodID getName; // String HidlMemory.getName()
+ jmethodID getSize; // int HidlMemory.getSize()
+ jmethodID getHandle; // NativeHandle HidlMemory.getHandle()
+} gFields;
+
+std::string stringFromJava(JNIEnv* env, jstring jstr) {
+ ScopedUtfChars s(env, jstr);
+ return s.c_str();
+}
+
+jstring stringToJava(JNIEnv* env, const std::string& cstr) {
+ return env->NewStringUTF(cstr.c_str());
+}
+
+static void nativeFinalize(JNIEnv* env, jobject jobj) {
+ jlong jNativeContext = env->GetLongField(jobj, gFields.nativeContext);
+ JHidlMemory* native = reinterpret_cast<JHidlMemory*>(jNativeContext);
+ delete native;
+}
+
+static JNINativeMethod gMethods[] = {
+ {"nativeFinalize", "()V", (void*) nativeFinalize},
+};
+
+} // namespace
+
+JHidlMemory::~JHidlMemory() {
+ if (mObj) {
+ // Must manually delete the underlying handle - hidl_memory doesn't own
+ // it.
+ native_handle_delete(const_cast<native_handle_t*>(mObj->handle()));
+ }
+}
+
+/* static */ const hardware::hidl_memory* JHidlMemory::fromJava(JNIEnv* env,
+ jobject jobj) {
+ // Try to get the result from cache.
+ env->MonitorEnter(jobj);
+ JHidlMemory* obj = getNativeContext(env, jobj);
+ if (!obj->mObj) {
+ // Create and cache.
+ obj->mObj = javaToNative(env, jobj);
+ }
+ env->MonitorExit(jobj);
+ return obj->mObj.get();
+}
+
+/* static */ jobject JHidlMemory::toJava(JNIEnv* env,
+ const hardware::hidl_memory& cobj) {
+ if (cobj.size() > std::numeric_limits<jlong>::max()) {
+ return nullptr;
+ }
+ jstring jname = stringToJava(env, cobj.name());
+ jlong jsize = static_cast<jlong>(cobj.size());
+ jobject jhandle =
+ JNativeHandle::MakeJavaNativeHandleObj(env, cobj.handle());
+
+ // We're sharing the handle of cobj, so the Java instance doesn't own it.
+ return env->NewObject(gFields.clazz,
+ gFields.constructor,
+ jname,
+ jsize,
+ jhandle,
+ false);
+}
+
+/* static */ std::unique_ptr<hardware::hidl_memory> JHidlMemory::javaToNative(
+ JNIEnv* env,
+ jobject jobj) {
+ jstring jname =
+ static_cast<jstring>(env->CallObjectMethod(jobj, gFields.getName));
+ jlong jsize = env->CallLongMethod(jobj, gFields.getSize);
+ jobject jhandle = env->CallObjectMethod(jobj, gFields.getHandle);
+
+ if (jsize > std::numeric_limits<size_t>::max()) {
+ return nullptr;
+ }
+
+ std::string cname = stringFromJava(env, jname);
+ size_t csize = jsize;
+ // We created the handle here, we're responsible to call
+ // native_handle_delete() on it. However, we don't assume ownership of the
+ // underlying fd, so we shouldn't call native_handle_close() on it.
+ native_handle_t* chandle = JNativeHandle::MakeCppNativeHandle(env, jhandle,
+ nullptr);
+ // hidl_memory doesn't take ownership of the handle here, so won't delete
+ // or close it.
+ return std::make_unique<hardware::hidl_memory>(cname, chandle, csize);
+}
+
+/* static */ JHidlMemory* JHidlMemory::getNativeContext(JNIEnv* env,
+ jobject jobj) {
+ env->MonitorEnter(jobj);
+ jlong jNativeContext = env->GetLongField(jobj, gFields.nativeContext);
+ JHidlMemory* native = reinterpret_cast<JHidlMemory*>(jNativeContext);
+ if (!native) {
+ native = new JHidlMemory();
+ env->SetLongField(jobj,
+ gFields.nativeContext,
+ reinterpret_cast<jlong>(native));
+ }
+ env->MonitorExit(jobj);
+ return native;
+}
+
+int register_android_os_HidlMemory(JNIEnv* env) {
+ jclass clazz = FindClassOrDie(env, CLASS_PATH);
+ gFields.clazz = MakeGlobalRefOrDie(env, clazz);
+
+ gFields.nativeContext = GetFieldIDOrDie(env, clazz, "mNativeContext", "J");
+
+ gFields.constructor = GetMethodIDOrDie(env,
+ clazz,
+ "<init>",
+ "(Ljava/lang/String;JL" PACKAGE_PATH "/NativeHandle;)V");
+ gFields.getName =
+ GetMethodIDOrDie(env, clazz, "getName", "()Ljava/lang/String;");
+ gFields.getSize = GetMethodIDOrDie(env, clazz, "getSize", "()J");
+ gFields.getHandle = GetMethodIDOrDie(env,
+ clazz,
+ "getHandle",
+ "()L" PACKAGE_PATH "/NativeHandle;");
+
+ RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods));
+
+ return 0;
+}
+
+} // namespace android
+
diff --git a/core/jni/android_os_HidlMemory.h b/core/jni/android_os_HidlMemory.h
new file mode 100644
index 0000000..993a132
--- /dev/null
+++ b/core/jni/android_os_HidlMemory.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_OS_HIDL_MEMORY_H
+#define ANDROID_OS_HIDL_MEMORY_H
+
+#include <jni.h>
+#include <hidl/HidlSupport.h>
+
+namespace android {
+
+// A utility class for handling the android.os.HidlMemory class from JNI code.
+class JHidlMemory final {
+ public:
+ // Convert an android.os.HidlMemory object to its C++ counterpart,
+ // hardware::hidl_memory.
+ // No duplication of file descriptors is performed.
+ // The returned reference is owned by the underlying Java object.
+ // Returns nullptr if conversion cannot be done.
+ static const hardware::hidl_memory* fromJava(JNIEnv* env,
+ jobject jobj);
+
+ // Convert a hardware::hidl_memory object to its Java counterpart,
+ // android.os.HidlMemory.
+ // No duplication of file descriptors is performed.
+ // Returns nullptr if conversion cannot be done.
+ static jobject toJava(JNIEnv* env,
+ const hardware::hidl_memory& cobj);
+
+ ~JHidlMemory();
+
+ private:
+ // We store an instance of type JHidlMemory attached to every Java object
+ // of type HidlMemory, for holding any native context we need. This instance
+ // will get deleted when finalize() is called on the Java object.
+ // This method either extracts the native object from the Java object, or
+ // attached a new one if it doesn't yet exist.
+ static JHidlMemory* getNativeContext(JNIEnv* env, jobject obj);
+
+ // Convert an android.os.HidlMemory object to its C++ counterpart,
+ // hardware::hidl_memory.
+ // No duplication of file descriptors is performed.
+ // IMPORTANT: caller is responsible to native_handle_delete() the handle of the
+ // returned object. This is due to an underlying limitation of the hidl_handle
+ // type, where ownership of the handle implies ownership of the fd and we don't
+ // want the latter.
+ // Returns nullptr if conversion cannot be done.
+ static std::unique_ptr<hardware::hidl_memory> javaToNative(JNIEnv* env,
+ jobject jobj);
+
+ std::unique_ptr<hardware::hidl_memory> mObj;
+};
+
+int register_android_os_HidlMemory(JNIEnv* env);
+
+} // namespace android
+
+#endif //ANDROID_OS_HIDL_MEMORY_H
diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp
index e5b72ca..0fb2911 100644
--- a/core/jni/android_os_HwBlob.cpp
+++ b/core/jni/android_os_HwBlob.cpp
@@ -340,6 +340,14 @@
return env->NewStringUTF(s->c_str());
}
+static jlong JHwBlob_native_getFieldHandle(JNIEnv* env,
+ jobject thiz,
+ jlong offset) {
+ sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
+
+ return reinterpret_cast<jlong>(blob->data()) + offset;
+}
+
#define DEFINE_BLOB_ARRAY_COPIER(Suffix,Type,NewType) \
static void JHwBlob_native_copyTo ## Suffix ## Array( \
JNIEnv *env, \
@@ -593,6 +601,7 @@
{ "getFloat", "(J)F", (void *)JHwBlob_native_getFloat },
{ "getDouble", "(J)D", (void *)JHwBlob_native_getDouble },
{ "getString", "(J)Ljava/lang/String;", (void *)JHwBlob_native_getString },
+ { "getFieldHandle", "(J)J", (void*) JHwBlob_native_getFieldHandle},
{ "copyToBoolArray", "(J[ZI)V", (void *)JHwBlob_native_copyToBoolArray },
{ "copyToInt8Array", "(J[BI)V", (void *)JHwBlob_native_copyToInt8Array },
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index f437a78..151dbfc 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -20,6 +20,7 @@
#include "android_os_HwParcel.h"
+#include "android_os_HidlMemory.h"
#include "android_os_HwBinder.h"
#include "android_os_HwBlob.h"
#include "android_os_NativeHandle.h"
@@ -27,6 +28,8 @@
#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
+#include <hidl/HidlBinderSupport.h>
+#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportSupport.h>
#include <hidl/Status.h>
#include <nativehelper/ScopedLocalRef.h>
@@ -650,6 +653,36 @@
signalExceptionForError(env, err);
}
+static void JHwParcel_native_writeHidlMemory(
+ JNIEnv *env, jobject thiz, jobject jmem) {
+
+ if (jmem == nullptr) {
+ jniThrowException(env, "java/lang/NullPointerException", nullptr);
+ return;
+ }
+
+ status_t err = OK;
+
+ // Convert the Java object to its C++ counterpart.
+ const hardware::hidl_memory* cmem = JHidlMemory::fromJava(env, jmem);
+ if (cmem == nullptr) {
+ err = BAD_VALUE;
+ }
+
+ if (err == OK) {
+ // Write it to the parcel.
+ hardware::Parcel* parcel =
+ JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+ size_t parentHandle;
+ err = parcel->writeBuffer(cmem, sizeof(*cmem), &parentHandle);
+ if (err == OK) {
+ err = hardware::writeEmbeddedToParcel(*cmem, parcel, parentHandle, 0);
+ }
+ }
+ signalExceptionForError(env, err);
+}
+
static jstring MakeStringObjFromHidlString(JNIEnv *env, const hidl_string &s) {
String16 utf16String(s.c_str(), s.size());
@@ -877,6 +910,74 @@
return objArray;
}
+static status_t readEmbeddedHidlMemory(JNIEnv* env,
+ hardware::Parcel* parcel,
+ const hardware::hidl_memory& mem,
+ size_t parentHandle,
+ size_t parentOffset,
+ jobject* result) {
+ status_t err = hardware::readEmbeddedFromParcel(mem,
+ *parcel,
+ parentHandle,
+ parentOffset);
+ if (err == OK) {
+ // Convert to Java.
+ *result = JHidlMemory::toJava(env, mem);
+ if (*result == nullptr) {
+ err = BAD_VALUE;
+ }
+ }
+ return err;
+}
+
+static jobject JHwParcel_native_readHidlMemory(
+ JNIEnv* env, jobject thiz) {
+ hardware::Parcel* parcel =
+ JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+ jobject result = nullptr;
+
+ const hardware::hidl_memory* mem;
+ size_t parentHandle;
+
+ status_t err = parcel->readBuffer(sizeof(*mem),
+ &parentHandle,
+ reinterpret_cast<const void**>(&mem));
+ if (err == OK) {
+ err = readEmbeddedHidlMemory(env,
+ parcel,
+ *mem,
+ parentHandle,
+ 0,
+ &result);
+ }
+
+ signalExceptionForError(env, err);
+ return result;
+}
+
+static jobject JHwParcel_native_readEmbeddedHidlMemory(
+ JNIEnv* env,
+ jobject thiz,
+ jlong fieldHandle,
+ jlong parentHandle,
+ jlong offset) {
+ hardware::Parcel* parcel =
+ JHwParcel::GetNativeContext(env, thiz)->getParcel();
+
+ jobject result = nullptr;
+ const hardware::hidl_memory* mem =
+ reinterpret_cast<const hardware::hidl_memory*>(fieldHandle);
+ status_t err = readEmbeddedHidlMemory(env,
+ parcel,
+ *mem,
+ parentHandle,
+ offset,
+ &result);
+ signalExceptionForError(env, err);
+ return result;
+}
+
static jobject JHwParcel_native_readStrongBinder(JNIEnv *env, jobject thiz) {
hardware::Parcel *parcel =
JHwParcel::GetNativeContext(env, thiz)->getParcel();
@@ -1075,6 +1176,14 @@
{ "release", "()V",
(void *)JHwParcel_native_release },
+ {"writeHidlMemory", "(L" PACKAGE_PATH "/HidlMemory;)V",
+ (void*) JHwParcel_native_writeHidlMemory},
+
+ {"readHidlMemory", "()L" PACKAGE_PATH "/HidlMemory;",
+ (void*) JHwParcel_native_readHidlMemory},
+
+ {"readEmbeddedHidlMemory", "(JJJ)L" PACKAGE_PATH "/HidlMemory;",
+ (void*) JHwParcel_native_readEmbeddedHidlMemory},
};
namespace android {
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index f8a2744..9f20388 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -491,6 +491,7 @@
float* floatColors = env->GetFloatArrayElements(fColor, 0);
half3 color(floatColors[0], floatColors[1], floatColors[2]);
transaction->setColor(ctrl, color);
+ env->ReleaseFloatArrayElements(fColor, floatColors, 0);
}
static void nativeSetMatrix(JNIEnv* env, jclass clazz, jlong transactionObj,
@@ -508,8 +509,12 @@
SurfaceControl* const surfaceControl = reinterpret_cast<SurfaceControl*>(nativeObject);
float* floatMatrix = env->GetFloatArrayElements(fMatrix, 0);
mat3 matrix(static_cast<float const*>(floatMatrix));
+ env->ReleaseFloatArrayElements(fMatrix, floatMatrix, 0);
+
float* floatTranslation = env->GetFloatArrayElements(fTranslation, 0);
vec3 translation(floatTranslation[0], floatTranslation[1], floatTranslation[2]);
+ env->ReleaseFloatArrayElements(fTranslation, floatTranslation, 0);
+
transaction->setColorTransform(surfaceControl, matrix, translation);
}
@@ -1262,6 +1267,22 @@
return reinterpret_cast<jlong>(surface.get());
}
+static void nativeSetGlobalShadowSettings(JNIEnv* env, jclass clazz, jfloatArray jAmbientColor,
+ jfloatArray jSpotColor, jfloat lightPosY, jfloat lightPosZ, jfloat lightRadius) {
+ sp<SurfaceComposerClient> client = SurfaceComposerClient::getDefault();
+
+ float* floatAmbientColor = env->GetFloatArrayElements(jAmbientColor, 0);
+ half4 ambientColor = half4(floatAmbientColor[0], floatAmbientColor[1], floatAmbientColor[2],
+ floatAmbientColor[3]);
+ env->ReleaseFloatArrayElements(jAmbientColor, floatAmbientColor, 0);
+
+ float* floatSpotColor = env->GetFloatArrayElements(jSpotColor, 0);
+ half4 spotColor = half4(floatSpotColor[0], floatSpotColor[1], floatSpotColor[2],
+ floatSpotColor[3]);
+ env->ReleaseFloatArrayElements(jSpotColor, floatSpotColor, 0);
+
+ client->setGlobalShadowSettings(ambientColor, spotColor, lightPosY, lightPosZ, lightRadius);
+}
// ----------------------------------------------------------------------------
static const JNINativeMethod sSurfaceControlMethods[] = {
@@ -1416,6 +1437,8 @@
(void*)nativeWriteTransactionToParcel },
{"nativeMirrorSurface", "(J)J",
(void*)nativeMirrorSurface },
+ {"nativeSetGlobalShadowSettings", "([F[FFFF)V",
+ (void*)nativeSetGlobalShadowSettings },
};
int register_android_view_SurfaceControl(JNIEnv* env)
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 62001aa..c63d2aa 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -5045,6 +5045,10 @@
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
+ <service android:name="com.android.server.usage.UsageStatsIdleService"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
<service android:name="com.android.server.net.watchlist.ReportWatchlistJobService"
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
diff --git a/core/tests/coretests/src/android/os/WorkSourceTest.java b/core/tests/coretests/src/android/os/WorkSourceTest.java
index e94d60c..4206fd2 100644
--- a/core/tests/coretests/src/android/os/WorkSourceTest.java
+++ b/core/tests/coretests/src/android/os/WorkSourceTest.java
@@ -228,13 +228,13 @@
WorkSource ws = new WorkSource();
ws.set(10);
assertEquals(1, ws.size());
- assertEquals(10, ws.get(0));
+ assertEquals(10, ws.getUid(0));
WorkSource ws2 = new WorkSource();
ws2.set(20, "foo");
assertEquals(1, ws2.size());
- assertEquals(20, ws2.get(0));
- assertEquals("foo", ws2.getName(0));
+ assertEquals(20, ws2.getUid(0));
+ assertEquals("foo", ws2.getPackageName(0));
}
public void testDiffChains_noChanges() {
@@ -410,8 +410,8 @@
assertTrue(ws2.remove(ws1));
assertEquals(0, ws1.size());
- assertEquals(50, ws1.get(0));
- assertEquals("foo", ws1.getName(0));
+ assertEquals(50, ws1.getUid(0));
+ assertEquals("foo", ws1.getPackageName(0));
}
public void testTransferWorkChains() {
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 6cbda07..b5d3a1f 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -273,6 +273,8 @@
ByteBucketArray<uint32_t> resource_ids_;
std::vector<DynamicPackageEntry> dynamic_package_map_;
std::vector<const std::pair<OverlayableInfo, std::unordered_set<uint32_t>>> overlayable_infos_;
+
+ // A map of overlayable name to actor
std::unordered_map<std::string, std::string> overlayable_map_;
};
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index a3a8777..d64e4ef 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -30,7 +30,9 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
/* IF YOU CHANGE ANY OF THE CONSTANTS IN THIS FILE, DO NOT FORGET
* TO UPDATE THE CORRESPONDING NATIVE GLUE AND AudioManager.java.
@@ -543,51 +545,75 @@
public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT;
- public static final int DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE |
- DEVICE_OUT_SPEAKER |
- DEVICE_OUT_WIRED_HEADSET |
- DEVICE_OUT_WIRED_HEADPHONE |
- DEVICE_OUT_BLUETOOTH_SCO |
- DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
- DEVICE_OUT_BLUETOOTH_SCO_CARKIT |
- DEVICE_OUT_BLUETOOTH_A2DP |
- DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
- DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER |
- DEVICE_OUT_HDMI |
- DEVICE_OUT_ANLG_DOCK_HEADSET |
- DEVICE_OUT_DGTL_DOCK_HEADSET |
- DEVICE_OUT_USB_ACCESSORY |
- DEVICE_OUT_USB_DEVICE |
- DEVICE_OUT_REMOTE_SUBMIX |
- DEVICE_OUT_TELEPHONY_TX |
- DEVICE_OUT_LINE |
- DEVICE_OUT_HDMI_ARC |
- DEVICE_OUT_SPDIF |
- DEVICE_OUT_FM |
- DEVICE_OUT_AUX_LINE |
- DEVICE_OUT_SPEAKER_SAFE |
- DEVICE_OUT_IP |
- DEVICE_OUT_BUS |
- DEVICE_OUT_PROXY |
- DEVICE_OUT_USB_HEADSET |
- DEVICE_OUT_HEARING_AID |
- DEVICE_OUT_DEFAULT);
- public static final int DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP |
- DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
- DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
- public static final int DEVICE_OUT_ALL_SCO = (DEVICE_OUT_BLUETOOTH_SCO |
- DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
- DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
+ // Deprecated in R because multiple device types are no longer accessed as a bit mask.
+ // Removing this will get lint warning about changing hidden apis.
@UnsupportedAppUsage
public static final int DEVICE_OUT_ALL_USB = (DEVICE_OUT_USB_ACCESSORY |
DEVICE_OUT_USB_DEVICE |
DEVICE_OUT_USB_HEADSET);
- public static final int DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO = (DEVICE_OUT_AUX_LINE |
- DEVICE_OUT_HDMI_ARC |
- DEVICE_OUT_SPDIF);
- public static final int DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER =
- (DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO |
- DEVICE_OUT_SPEAKER);
+
+ public static final Set<Integer> DEVICE_OUT_ALL_SET;
+ public static final Set<Integer> DEVICE_OUT_ALL_A2DP_SET;
+ public static final Set<Integer> DEVICE_OUT_ALL_SCO_SET;
+ public static final Set<Integer> DEVICE_OUT_ALL_USB_SET;
+ public static final Set<Integer> DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET;
+ public static final Set<Integer> DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET;
+ static {
+ DEVICE_OUT_ALL_SET = new HashSet<>();
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_EARPIECE);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_SPEAKER);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_WIRED_HEADSET);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_WIRED_HEADPHONE);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_SCO);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_SCO_HEADSET);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_A2DP);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_HDMI);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_ANLG_DOCK_HEADSET);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_DGTL_DOCK_HEADSET);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_USB_ACCESSORY);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_USB_DEVICE);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_REMOTE_SUBMIX);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_TELEPHONY_TX);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_LINE);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_HDMI_ARC);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_SPDIF);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_FM);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_AUX_LINE);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_SPEAKER_SAFE);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_IP);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BUS);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_PROXY);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_USB_HEADSET);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_HEARING_AID);
+ DEVICE_OUT_ALL_SET.add(DEVICE_OUT_DEFAULT);
+
+ DEVICE_OUT_ALL_A2DP_SET = new HashSet<>();
+ DEVICE_OUT_ALL_A2DP_SET.add(DEVICE_OUT_BLUETOOTH_A2DP);
+ DEVICE_OUT_ALL_A2DP_SET.add(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES);
+ DEVICE_OUT_ALL_A2DP_SET.add(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
+
+ DEVICE_OUT_ALL_SCO_SET = new HashSet<>();
+ DEVICE_OUT_ALL_SCO_SET.add(DEVICE_OUT_BLUETOOTH_SCO);
+ DEVICE_OUT_ALL_SCO_SET.add(DEVICE_OUT_BLUETOOTH_SCO_HEADSET);
+ DEVICE_OUT_ALL_SCO_SET.add(DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
+
+ DEVICE_OUT_ALL_USB_SET = new HashSet<>();
+ DEVICE_OUT_ALL_USB_SET.add(DEVICE_OUT_USB_ACCESSORY);
+ DEVICE_OUT_ALL_USB_SET.add(DEVICE_OUT_USB_DEVICE);
+ DEVICE_OUT_ALL_USB_SET.add(DEVICE_OUT_USB_HEADSET);
+
+ DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET = new HashSet<>();
+ DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET.add(DEVICE_OUT_AUX_LINE);
+ DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET.add(DEVICE_OUT_HDMI_ARC);
+ DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET.add(DEVICE_OUT_SPDIF);
+
+ DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET = new HashSet<>();
+ DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET.addAll(DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET);
+ DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET.add(DEVICE_OUT_SPEAKER);
+ }
// input devices
@UnsupportedAppUsage
@@ -635,37 +661,47 @@
@UnsupportedAppUsage
public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT;
- public static final int DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION |
- DEVICE_IN_AMBIENT |
- DEVICE_IN_BUILTIN_MIC |
- DEVICE_IN_BLUETOOTH_SCO_HEADSET |
- DEVICE_IN_WIRED_HEADSET |
- DEVICE_IN_HDMI |
- DEVICE_IN_TELEPHONY_RX |
- DEVICE_IN_BACK_MIC |
- DEVICE_IN_REMOTE_SUBMIX |
- DEVICE_IN_ANLG_DOCK_HEADSET |
- DEVICE_IN_DGTL_DOCK_HEADSET |
- DEVICE_IN_USB_ACCESSORY |
- DEVICE_IN_USB_DEVICE |
- DEVICE_IN_FM_TUNER |
- DEVICE_IN_TV_TUNER |
- DEVICE_IN_LINE |
- DEVICE_IN_SPDIF |
- DEVICE_IN_BLUETOOTH_A2DP |
- DEVICE_IN_LOOPBACK |
- DEVICE_IN_IP |
- DEVICE_IN_BUS |
- DEVICE_IN_PROXY |
- DEVICE_IN_USB_HEADSET |
- DEVICE_IN_BLUETOOTH_BLE |
- DEVICE_IN_HDMI_ARC |
- DEVICE_IN_ECHO_REFERENCE |
- DEVICE_IN_DEFAULT);
- public static final int DEVICE_IN_ALL_SCO = DEVICE_IN_BLUETOOTH_SCO_HEADSET;
- public static final int DEVICE_IN_ALL_USB = (DEVICE_IN_USB_ACCESSORY |
- DEVICE_IN_USB_DEVICE |
- DEVICE_IN_USB_HEADSET);
+ public static final Set<Integer> DEVICE_IN_ALL_SET;
+ public static final Set<Integer> DEVICE_IN_ALL_SCO_SET;
+ public static final Set<Integer> DEVICE_IN_ALL_USB_SET;
+ static {
+ DEVICE_IN_ALL_SET = new HashSet<>();
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_COMMUNICATION);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_AMBIENT);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_BUILTIN_MIC);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_BLUETOOTH_SCO_HEADSET);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_WIRED_HEADSET);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_HDMI);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_TELEPHONY_RX);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_BACK_MIC);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_REMOTE_SUBMIX);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_ANLG_DOCK_HEADSET);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_DGTL_DOCK_HEADSET);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_USB_ACCESSORY);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_USB_DEVICE);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_FM_TUNER);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_TV_TUNER);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_LINE);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_SPDIF);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_BLUETOOTH_A2DP);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_LOOPBACK);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_IP);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_BUS);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_PROXY);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_USB_HEADSET);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_BLUETOOTH_BLE);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_HDMI_ARC);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_ECHO_REFERENCE);
+ DEVICE_IN_ALL_SET.add(DEVICE_IN_DEFAULT);
+
+ DEVICE_IN_ALL_SCO_SET = new HashSet<>();
+ DEVICE_IN_ALL_SCO_SET.add(DEVICE_IN_BLUETOOTH_SCO_HEADSET);
+
+ DEVICE_IN_ALL_USB_SET = new HashSet<>();
+ DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_ACCESSORY);
+ DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_DEVICE);
+ DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_HEADSET);
+ }
// device states, must match AudioSystem::device_connection_state
@UnsupportedAppUsage
@@ -1229,6 +1265,40 @@
return getPlatformType(context) == PLATFORM_TELEVISION || forceSingleVolume;
}
+ /**
+ * Return a set of audio device types from a bit mask audio device type, which may
+ * represent multiple audio device types.
+ * FIXME: Remove this when getting ride of bit mask usage of audio device types.
+ */
+ public static Set<Integer> generateAudioDeviceTypesSet(int types) {
+ Set<Integer> deviceTypes = new HashSet<>();
+ Set<Integer> allDeviceTypes =
+ (types & DEVICE_BIT_IN) == 0 ? DEVICE_OUT_ALL_SET : DEVICE_IN_ALL_SET;
+ for (int deviceType : allDeviceTypes) {
+ if ((types & deviceType) == deviceType) {
+ deviceTypes.add(deviceType);
+ }
+ }
+ return deviceTypes;
+ }
+
+ /**
+ * Return the intersection of two audio device types collections.
+ */
+ public static Set<Integer> intersectionAudioDeviceTypes(
+ @NonNull Set<Integer> a, @NonNull Set<Integer> b) {
+ Set<Integer> intersection = new HashSet<>(a);
+ intersection.retainAll(b);
+ return intersection;
+ }
+
+ /**
+ * Return true if the audio device types collection only contains the given device type.
+ */
+ public static boolean isSingleAudioDeviceType(@NonNull Set<Integer> types, int type) {
+ return types.size() == 1 && types.contains(type);
+ }
+
public static final int DEFAULT_MUTE_STREAMS_AFFECTED =
(1 << STREAM_MUSIC) |
(1 << STREAM_RING) |
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index ced8615..81a7ee2 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -43,6 +43,7 @@
void setControlCategories(IMediaRouterClient client, in List<String> categories);
// Methods for media router 2
+ List<MediaRoute2Info> getSystemRoutes();
void registerClient2(IMediaRouter2Client client, String packageName);
void unregisterClient2(IMediaRouter2Client client);
void sendControlRequest(IMediaRouter2Client client, in MediaRoute2Info route, in Intent request);
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 74d26f0..94ac77a 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -131,6 +131,25 @@
mPackageName = mContext.getPackageName();
//TODO: read control categories from the manifest
mHandler = new Handler(Looper.getMainLooper());
+
+ List<MediaRoute2Info> currentSystemRoutes = null;
+ try {
+ currentSystemRoutes = mMediaRouterService.getSystemRoutes();
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Unable to get current currentSystemRoutes", ex);
+ }
+
+ if (currentSystemRoutes == null || currentSystemRoutes.isEmpty()) {
+ throw new RuntimeException("Null or empty currentSystemRoutes. Something is wrong.");
+ }
+
+ for (MediaRoute2Info route : currentSystemRoutes) {
+ mRoutes.put(route.getId(), route);
+ }
+ // The first route is the currently selected system route.
+ // For example, if there are two system routes (BT and device speaker),
+ // BT will be the first route in the list.
+ mSelectedRoute = currentSystemRoutes.get(0);
}
/**
@@ -409,6 +428,10 @@
}
void addRoutesOnHandler(List<MediaRoute2Info> routes) {
+ // TODO: When onRoutesAdded is first called,
+ // 1) clear mRoutes before adding the routes
+ // 2) Call onRouteSelected(system_route, reason_fallback) if previously selected route
+ // does not exist anymore. => We may need 'boolean MediaRoute2Info#isSystemRoute()'.
List<MediaRoute2Info> addedRoutes = new ArrayList<>();
for (MediaRoute2Info route : routes) {
mRoutes.put(route.getUniqueId(), route);
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java
new file mode 100644
index 0000000..2c60d6b
--- /dev/null
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 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.mediaroutertest;
+
+import static org.junit.Assert.assertNotNull;
+
+import android.content.Context;
+import android.media.MediaRoute2Info;
+import android.media.MediaRouter2;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class MediaRouter2Test {
+ Context mContext;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getTargetContext();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void testGetSelectedRoute_afterCreation() throws Exception {
+ MediaRouter2 router = MediaRouter2.getInstance(mContext);
+ MediaRoute2Info initiallySelectedRoute = router.getSelectedRoute();
+ assertNotNull(initiallySelectedRoute);
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index d619300..d577b5a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -748,7 +748,20 @@
|| (mConfig != null && mConfig.shared != config.shared)) {
return false;
}
- return security == getSecurity(config);
+
+ final int configSecurity = getSecurity(config);
+ final WifiManager wifiManager = getWifiManager();
+ switch (security) {
+ case SECURITY_PSK_SAE_TRANSITION:
+ return configSecurity == SECURITY_PSK
+ || (wifiManager.isWpa3SaeSupported() && configSecurity == SECURITY_SAE);
+ case SECURITY_OWE_TRANSITION:
+ return configSecurity == SECURITY_NONE
+ || (wifiManager.isEnhancedOpenSupported()
+ && configSecurity == SECURITY_OWE);
+ default:
+ return security == configSecurity;
+ }
}
public WifiConfiguration getConfig() {
@@ -1321,10 +1334,34 @@
mAccessPointListener = listener;
}
+ private static final String sPskSuffix = "," + String.valueOf(SECURITY_PSK);
+ private static final String sSaeSuffix = "," + String.valueOf(SECURITY_SAE);
+ private static final String sPskSaeSuffix = "," + String.valueOf(SECURITY_PSK_SAE_TRANSITION);
+ private static final String sOweSuffix = "," + String.valueOf(SECURITY_OWE);
+ private static final String sOpenSuffix = "," + String.valueOf(SECURITY_NONE);
+ private static final String sOweTransSuffix = "," + String.valueOf(SECURITY_OWE_TRANSITION);
+
private boolean isKeyEqual(String compareTo) {
if (mKey == null) {
return false;
}
+
+ if (compareTo.endsWith(sPskSuffix) || compareTo.endsWith(sSaeSuffix)) {
+ if (mKey.endsWith(sPskSaeSuffix)) {
+ // Special handling for PSK-SAE transition mode. If the AP has advertised both,
+ // we compare the key with both PSK and SAE for a match.
+ return TextUtils.equals(mKey.substring(0, mKey.lastIndexOf(',')),
+ compareTo.substring(0, compareTo.lastIndexOf(',')));
+ }
+ }
+ if (compareTo.endsWith(sOpenSuffix) || compareTo.endsWith(sOweSuffix)) {
+ if (mKey.endsWith(sOweTransSuffix)) {
+ // Special handling for OWE/Open networks. If AP advertises OWE in transition mode
+ // and we have an Open network saved, allow this connection to be established.
+ return TextUtils.equals(mKey.substring(0, mKey.lastIndexOf(',')),
+ compareTo.substring(0, compareTo.lastIndexOf(',')));
+ }
+ }
return mKey.equals(compareTo);
}
@@ -1661,6 +1698,8 @@
private static int getSecurity(ScanResult result) {
if (result.capabilities.contains("WEP")) {
return SECURITY_WEP;
+ } else if (result.capabilities.contains("PSK+SAE")) {
+ return SECURITY_PSK_SAE_TRANSITION;
} else if (result.capabilities.contains("SAE")) {
return SECURITY_SAE;
} else if (result.capabilities.contains("PSK")) {
@@ -1669,6 +1708,8 @@
return SECURITY_EAP_SUITE_B;
} else if (result.capabilities.contains("EAP")) {
return SECURITY_EAP;
+ } else if (result.capabilities.contains("OWE_TRANSITION")) {
+ return SECURITY_OWE_TRANSITION;
} else if (result.capabilities.contains("OWE")) {
return SECURITY_OWE;
}
@@ -1715,6 +1756,10 @@
return "SUITE_B";
} else if (security == SECURITY_OWE) {
return "OWE";
+ } else if (security == SECURITY_PSK_SAE_TRANSITION) {
+ return "PSK+SAE";
+ } else if (security == SECURITY_OWE_TRANSITION) {
+ return "OWE_TRANSITION";
}
return "NONE";
}
@@ -1892,16 +1937,4 @@
}
}
}
-
- /**
- * Lets the caller know if the network was cloned from another network
- *
- * @return true if the network is cloned
- */
- public boolean isCloned() {
- if (mConfig == null) {
- return false;
- }
- return mConfig.clonedNetworkConfigKey != null;
- }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 51e37d1..8591116 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -142,7 +142,7 @@
private void updateRssi(int newRssi) {
rssi = newRssi;
- level = WifiManager.calculateSignalLevel(rssi, WifiManager.RSSI_LEVELS);
+ level = mWifiManager.calculateSignalLevel(rssi);
}
private void maybeRequestNetworkScore() {
diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp
index 681b494..f40d3a1 100644
--- a/packages/SettingsProvider/Android.bp
+++ b/packages/SettingsProvider/Android.bp
@@ -29,6 +29,7 @@
"src/com/android/providers/settings/SettingsBackupAgent.java",
"src/com/android/providers/settings/SettingsState.java",
"src/com/android/providers/settings/SettingsHelper.java",
+ "src/com/android/providers/settings/WifiSoftApBandChangedNotifier.java",
],
static_libs: [
"androidx.test.rules",
diff --git a/packages/SettingsProvider/res/drawable/ic_wifi_settings.xml b/packages/SettingsProvider/res/drawable/ic_wifi_settings.xml
new file mode 100644
index 0000000..cb42656
--- /dev/null
+++ b/packages/SettingsProvider/res/drawable/ic_wifi_settings.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+ <path
+ android:fillColor="#000000"
+ android:pathData="M12.584,15.93c0.026-0.194,0.044-0.397,0.044-0.608c0-0.211-0.018-0.405-0.044-0.608l1.304-1.022
+c0.115-0.088,0.15-0.256,0.071-0.397l-1.234-2.133c-0.071-0.132-0.238-0.185-0.379-0.132l-1.533,0.617
+c-0.317-0.247-0.67-0.449-1.04-0.608L9.535,9.4c-0.018-0.132-0.141-0.247-0.3-0.247H6.768c-0.15,0-0.282,0.115-0.3,0.256
+L6.23,11.048c-0.379,0.159-0.723,0.361-1.04,0.608l-1.533-0.617c-0.141-0.053-0.3,0-0.379,0.132l-1.234,2.133
+c-0.079,0.132-0.044,0.3,0.07,0.397l1.304,1.022c-0.026,0.194-0.044,0.405-0.044,0.608s0.018,0.405,0.044,0.608l-1.304,1.022
+c-0.115,0.088-0.15,0.256-0.07,0.397l1.234,2.133c0.07,0.132,0.238,0.185,0.379,0.132l1.533-0.617
+c0.317,0.247,0.67,0.449,1.04,0.608l0.238,1.639c0.018,0.15,0.15,0.256,0.3,0.256h2.467c0.159,0,0.282-0.115,0.3-0.256
+l0.238-1.639c0.379-0.15,0.723-0.361,1.04-0.608l1.533,0.617c0.141,0.053,0.3,0,0.379-0.132l1.234-2.133
+c0.071-0.132,0.044-0.3-0.07-0.397L12.584,15.93z
+M8.002,17.481c-1.19,0-2.159-0.969-2.159-2.159s0.969-2.159,2.159-2.159
+s2.159,0.969,2.159,2.159C10.161,16.512,9.191,17.481,8.002,17.481z" />
+ <path
+ android:fillColor="#000000"
+ android:pathData="M16.003,12.026l5.995-7.474c-0.229-0.172-2.537-2.06-6-2.06s-5.771,1.889-6,2.06l5.995,7.469l0.005,0.01L16.003,12.026z" />
+</vector>
diff --git a/packages/SettingsProvider/res/values/strings.xml b/packages/SettingsProvider/res/values/strings.xml
index 9ca575e..3787727 100644
--- a/packages/SettingsProvider/res/values/strings.xml
+++ b/packages/SettingsProvider/res/values/strings.xml
@@ -19,4 +19,19 @@
<resources>
<!-- Name of the activity for Settings storage. -->
<string name="app_label">Settings Storage</string>
+
+ <!-- A notification is shown when the user's softap config has been changed due to underlying
+ hardware restrictions. This is the notifications's title.
+ [CHAR_LIMIT=NONE] -->
+ <string name="wifi_softap_config_change">Changes to your hotspot settings</string>
+
+ <!-- A notification is shown when the user's softap config has been changed due to underlying
+ hardware restrictions. This is the notification's summary message.
+ [CHAR_LIMIT=NONE] -->
+ <string name="wifi_softap_config_change_summary">Your hotspot band has changed.</string>
+
+ <!-- A notification is shown when the user's softap config has been changed due to underlying
+ hardware restrictions. This is the notification's full message.
+ [CHAR_LIMIT=NONE] -->
+ <string name="wifi_softap_config_change_detailed">This device doesn\u2019t support your preference for 5GHz only. Instead, this device will use the 5GHz band when available.</string>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 7e60452..443288c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -895,11 +895,9 @@
// the apBand preference
boolean dualMode = mWifiManager.isDualModeSupported();
int storedApBand = mWifiManager.getWifiApConfiguration().apBand;
- if (dualMode) {
- if (storedApBand != originalApBand) {
- Log.d(TAG, "restored ap configuration requires a conversion, notify the user");
- mWifiManager.notifyUserOfApBandConversion();
- }
+ if (dualMode && storedApBand != originalApBand) {
+ Log.d(TAG, "restored ap configuration requires a conversion, notify the user");
+ WifiSoftApBandChangedNotifier.notifyUserOfApBandConversion(this);
}
} catch (IOException | BackupUtils.BadVersionException e) {
Log.e(TAG, "Failed to unMarshal SoftAPConfiguration " + e.getMessage());
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApBandChangedNotifier.java b/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApBandChangedNotifier.java
new file mode 100644
index 0000000..d0d4956
--- /dev/null
+++ b/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApBandChangedNotifier.java
@@ -0,0 +1,88 @@
+/*
+ * 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.providers.settings;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+
+import com.android.internal.messages.nano.SystemMessageProto;
+import com.android.internal.notification.SystemNotificationChannels;
+
+/**
+ * Helper class for sending notifications when the user's Soft AP Band was changed upon restore.
+ */
+public class WifiSoftApBandChangedNotifier {
+ private WifiSoftApBandChangedNotifier() {}
+
+ /**
+ * Send a notification informing the user that their' Soft AP Band was changed upon restore.
+ * When the user taps on the notification, they are taken to the Wifi Tethering page in
+ * Settings.
+ */
+ public static void notifyUserOfApBandConversion(Context context) {
+ NotificationManager notificationManager =
+ context.getSystemService(NotificationManager.class);
+
+ // create channel, or update it if it already exists
+ NotificationChannel channel = new NotificationChannel(
+ SystemNotificationChannels.NETWORK_STATUS,
+ context.getString(android.R.string.notification_channel_network_status),
+ NotificationManager.IMPORTANCE_LOW);
+ notificationManager.createNotificationChannel(channel);
+
+ notificationManager.notify(
+ SystemMessageProto.SystemMessage.NOTE_SOFTAP_CONFIG_CHANGED,
+ createConversionNotification(context));
+ }
+
+ private static Notification createConversionNotification(Context context) {
+ Resources resources = context.getResources();
+ CharSequence title = resources.getText(R.string.wifi_softap_config_change);
+ CharSequence contentSummary = resources.getText(R.string.wifi_softap_config_change_summary);
+ CharSequence content = resources.getText(R.string.wifi_softap_config_change_detailed);
+ int color = resources.getColor(
+ android.R.color.system_notification_accent_color, context.getTheme());
+
+ return new Notification.Builder(context, SystemNotificationChannels.NETWORK_STATUS)
+ .setSmallIcon(R.drawable.ic_wifi_settings)
+ .setPriority(Notification.PRIORITY_HIGH)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setContentTitle(title)
+ .setContentText(contentSummary)
+ .setContentIntent(getPendingActivity(context))
+ .setTicker(title)
+ .setShowWhen(false)
+ .setLocalOnly(true)
+ .setColor(color)
+ .setStyle(new Notification.BigTextStyle()
+ .bigText(content)
+ .setBigContentTitle(title)
+ .setSummaryText(contentSummary))
+ .setAutoCancel(true)
+ .build();
+ }
+
+ private static PendingIntent getPendingActivity(Context context) {
+ Intent intent = new Intent("com.android.settings.WIFI_TETHER_SETTINGS")
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+}
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index c3f410e..86ef031 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -125,7 +125,7 @@
<!-- The tiles to display in QuickSettings in retail mode -->
<string name="quick_settings_tiles_retail_mode" translatable="false">
- cell,battery,dnd,flashlight,rotation,location
+ night,dark,dnd,flashlight,rotation,location
</string>
<!-- Whether or not the RSSI tile is capitalized or not. -->
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 4d86613..61a7cc7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -139,6 +139,14 @@
when(mMockCm.getDefaultNetworkCapabilitiesForUser(0)).thenReturn(
new NetworkCapabilities[] { mNetCapabilities });
when(mMockTm.createForSubscriptionId(anyInt())).thenReturn(mMockTm);
+ doAnswer(invocation -> {
+ int rssi = invocation.getArgument(0);
+ if (rssi < -88) return 0;
+ if (rssi < -77) return 1;
+ if (rssi < -66) return 2;
+ if (rssi < -55) return 3;
+ return 4;
+ }).when(mMockWm).calculateSignalLevel(anyInt());
mSignalStrength = mock(SignalStrength.class);
mServiceState = mock(ServiceState.class);
diff --git a/services/Android.bp b/services/Android.bp
index 6953e86..35dc44e 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -1,3 +1,38 @@
+filegroup {
+ name: "services-main-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//visibility:private"],
+}
+
+filegroup {
+ name: "services-sources",
+ srcs: [
+ ":services.core-sources",
+ ":services.accessibility-sources",
+ ":services.appprediction-sources",
+ ":services.appwidget-sources",
+ ":services.autofill-sources",
+ ":services.backup-sources",
+ ":services.companion-sources",
+ ":services.contentcapture-sources",
+ ":services.contentsuggestions-sources",
+ ":services.coverage-sources",
+ ":services.devicepolicy-sources",
+ ":services.midi-sources",
+ ":services.net-sources",
+ ":services.print-sources",
+ ":services.restrictions-sources",
+ ":services.startop.iorap-sources",
+ ":services.systemcaptions-sources",
+ ":services.usage-sources",
+ ":services.usb-sources",
+ ":services.voiceinteraction-sources",
+ ":services.wifi-sources",
+ ],
+ visibility: ["//visibility:private"],
+}
+
// merge all required services into one jar
// ============================================================
java_library {
@@ -9,9 +44,7 @@
profile: "art-profile",
},
- srcs: [
- "java/**/*.java",
- ],
+ srcs: [":services-main-sources"],
// The convention is to name each service module 'services.$(module_name)'
static_libs: [
diff --git a/services/accessibility/Android.bp b/services/accessibility/Android.bp
index f991d7b..284a2f2 100644
--- a/services/accessibility/Android.bp
+++ b/services/accessibility/Android.bp
@@ -1,5 +1,12 @@
+filegroup {
+ name: "services.accessibility-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
java_library_static {
name: "services.accessibility",
- srcs: ["java/**/*.java"],
+ srcs: [":services.accessibility-sources"],
libs: ["services.core"],
}
diff --git a/services/appprediction/Android.bp b/services/appprediction/Android.bp
index a7be587..e14e1df 100644
--- a/services/appprediction/Android.bp
+++ b/services/appprediction/Android.bp
@@ -1,5 +1,12 @@
+filegroup {
+ name: "services.appprediction-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
java_library_static {
name: "services.appprediction",
- srcs: ["java/**/*.java"],
+ srcs: [":services.appprediction-sources"],
libs: ["services.core"],
}
diff --git a/services/appwidget/Android.bp b/services/appwidget/Android.bp
index aad2ad19..54cf6ce 100644
--- a/services/appwidget/Android.bp
+++ b/services/appwidget/Android.bp
@@ -1,5 +1,12 @@
+filegroup {
+ name: "services.appwidget-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
java_library_static {
name: "services.appwidget",
- srcs: ["java/**/*.java"],
+ srcs: [":services.appwidget-sources"],
libs: ["services.core"],
}
diff --git a/services/autofill/Android.bp b/services/autofill/Android.bp
index 2768c18..539eb1a 100644
--- a/services/autofill/Android.bp
+++ b/services/autofill/Android.bp
@@ -1,5 +1,12 @@
+filegroup {
+ name: "services.autofill-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
java_library_static {
name: "services.autofill",
- srcs: ["java/**/*.java"],
+ srcs: [":services.autofill-sources"],
libs: ["services.core"],
}
diff --git a/services/backup/Android.bp b/services/backup/Android.bp
index a3b0c89..f02da20 100644
--- a/services/backup/Android.bp
+++ b/services/backup/Android.bp
@@ -1,6 +1,13 @@
+filegroup {
+ name: "services.backup-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
java_library_static {
name: "services.backup",
- srcs: ["java/**/*.java"],
+ srcs: [":services.backup-sources"],
libs: ["services.core"],
static_libs: ["backuplib"],
}
diff --git a/services/backup/backuplib/Android.bp b/services/backup/backuplib/Android.bp
index 7b194a092..00f51c9 100644
--- a/services/backup/backuplib/Android.bp
+++ b/services/backup/backuplib/Android.bp
@@ -1,5 +1,12 @@
+filegroup {
+ name: "backuplib-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
java_library {
name: "backuplib",
- srcs: ["java/**/*.java"],
+ srcs: [":backuplib-sources"],
libs: ["services.core"],
}
diff --git a/services/companion/Android.bp b/services/companion/Android.bp
index d2dac35..9677a7d 100644
--- a/services/companion/Android.bp
+++ b/services/companion/Android.bp
@@ -1,5 +1,12 @@
+filegroup {
+ name: "services.companion-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
java_library_static {
name: "services.companion",
- srcs: ["java/**/*.java"],
+ srcs: [":services.companion-sources"],
libs: ["services.core"],
}
diff --git a/services/contentcapture/Android.bp b/services/contentcapture/Android.bp
index 57e859e..96e2072 100644
--- a/services/contentcapture/Android.bp
+++ b/services/contentcapture/Android.bp
@@ -1,5 +1,12 @@
+filegroup {
+ name: "services.contentcapture-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
java_library_static {
name: "services.contentcapture",
- srcs: ["java/**/*.java"],
+ srcs: [":services.contentcapture-sources"],
libs: ["services.core"],
}
diff --git a/services/contentsuggestions/Android.bp b/services/contentsuggestions/Android.bp
index fc09d2e..d17f06f 100644
--- a/services/contentsuggestions/Android.bp
+++ b/services/contentsuggestions/Android.bp
@@ -1,5 +1,12 @@
+filegroup {
+ name: "services.contentsuggestions-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
java_library_static {
name: "services.contentsuggestions",
- srcs: ["java/**/*.java"],
+ srcs: [":services.contentsuggestions-sources"],
libs: ["services.core"],
-}
\ No newline at end of file
+}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index b8caefd..594ac10 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -1,3 +1,10 @@
+filegroup {
+ name: "services.core-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
java_library {
name: "protolog-common",
srcs: [
@@ -16,7 +23,10 @@
genrule {
name: "services.core.protologsrc",
- srcs: [":services.core.wm.protologgroups", "java/**/*.java"],
+ srcs: [
+ ":services.core.wm.protologgroups",
+ ":services.core-sources",
+ ],
tools: ["protologtool"],
cmd: "$(location protologtool) transform-protolog-calls " +
"--protolog-class com.android.server.protolog.common.ProtoLog " +
@@ -25,20 +35,23 @@
"--loggroups-class com.android.server.wm.ProtoLogGroup " +
"--loggroups-jar $(location :services.core.wm.protologgroups) " +
"--output-srcjar $(out) " +
- "$(locations java/**/*.java)",
+ "$(locations :services.core-sources)",
out: ["services.core.protolog.srcjar"],
}
genrule {
name: "generate-protolog.json",
- srcs: [":services.core.wm.protologgroups", "java/**/*.java"],
+ srcs: [
+ ":services.core.wm.protologgroups",
+ ":services.core-sources",
+ ],
tools: ["protologtool"],
cmd: "$(location protologtool) generate-viewer-config " +
"--protolog-class com.android.server.protolog.common.ProtoLog " +
"--loggroups-class com.android.server.wm.ProtoLogGroup " +
"--loggroups-jar $(location :services.core.wm.protologgroups) " +
"--viewer-conf $(out) " +
- "$(locations java/**/*.java)",
+ "$(locations :services.core-sources)",
out: ["services.core.protolog.json"],
}
@@ -60,25 +73,15 @@
java_library_static {
name: "services.core.unboosted",
-
- aidl: {
- include_dirs: [
- "frameworks/base/cmds/idmap2/idmap2d/aidl",
- "frameworks/native/aidl/binder",
- "frameworks/native/cmds/dumpstate/binder",
- "system/core/storaged/binder",
- "system/vold/binder",
- "system/gsid/aidl",
- ],
- },
srcs: [
":services.core.protologsrc",
":dumpstate_aidl",
+ ":framework_native_aidl",
+ ":gsiservice_aidl",
":idmap2_aidl",
":installd_aidl",
":storaged_aidl",
":vold_aidl",
- ":gsiservice_aidl",
":platform-compat-config",
":tethering-servicescore-srcs",
"java/com/android/server/EventLogTags.logtags",
diff --git a/services/core/java/android/app/usage/UsageStatsManagerInternal.java b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
index 6641b5b..2f8c506 100644
--- a/services/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -281,4 +281,13 @@
return mUsageRemaining;
}
}
+
+ /**
+ * Called by {@link com.android.server.usage.UsageStatsIdleService} when the device is idle to
+ * prune usage stats data for uninstalled packages.
+ *
+ * @param userId the user associated with the job
+ * @return {@code true} if the pruning was successful, {@code false} otherwise
+ */
+ public abstract boolean pruneUninstalledPackagesData(@UserIdInt int userId);
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index e1f6597..9ebe896 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -1947,11 +1947,11 @@
if (workSource.size() > 0) {
// If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
// by tags.
- return workSource.getName(0) != null;
+ return workSource.getPackageName(0) != null;
} else {
// For now, make sure callers have supplied an attribution tag for use with
// AppOpsManager. This might be relaxed in the future.
- final ArrayList<WorkChain> workChains = workSource.getWorkChains();
+ final List<WorkChain> workChains = workSource.getWorkChains();
return workChains != null && !workChains.isEmpty() &&
workChains.get(0).getAttributionTag() != null;
}
@@ -3309,18 +3309,24 @@
ipw.decreaseIndent();
}
- mSettingsStore.dump(fd, pw, args);
+ ipw.println("Location Settings:");
+ ipw.increaseIndent();
+ mSettingsStore.dump(fd, ipw, args);
+ ipw.decreaseIndent();
ipw.println("Location Providers:");
ipw.increaseIndent();
for (LocationProvider provider : mProviders) {
provider.dumpLocked(fd, ipw, args);
}
+ ipw.decreaseIndent();
}
if (mGnssManagerService != null) {
+ ipw.println("GNSS:");
+ ipw.increaseIndent();
+ mGnssManagerService.dump(fd, ipw, args);
ipw.decreaseIndent();
- mGnssManagerService.dump(fd, pw, args);
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3dc745b..88d0e4b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8649,7 +8649,7 @@
mBatteryStatsService.noteWakupAlarm(sourcePkg, sourceUid, workSource, tag);
if (workSource != null) {
- String workSourcePackage = workSource.getName(0);
+ String workSourcePackage = workSource.getPackageName(0);
int workSourceUid = workSource.getAttributionUid();
if (workSourcePackage == null) {
workSourcePackage = sourcePkg;
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 90973a8..a2b3574 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -44,6 +44,8 @@
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
/**
* Class to manage the inventory of all connected devices.
@@ -372,9 +374,14 @@
mDeviceBroker.postObserveDevicesForAllStreams();
}
- private static final int DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG =
- AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE
- | AudioSystem.DEVICE_OUT_LINE | AudioSystem.DEVICE_OUT_ALL_USB;
+ private static final Set<Integer> DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET;
+ static {
+ DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET = new HashSet<>();
+ DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADSET);
+ DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
+ DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_LINE);
+ DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET);
+ }
/*package*/ void onSetWiredDeviceConnectionState(
AudioDeviceInventory.WiredDeviceConnectionState wdcs) {
@@ -382,7 +389,7 @@
synchronized (mConnectedDevices) {
if ((wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED)
- && ((wdcs.mType & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0)) {
+ && DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(wdcs.mType)) {
mDeviceBroker.setBluetoothA2dpOnInt(true,
"onSetWiredDeviceConnectionState state DISCONNECTED");
}
@@ -393,7 +400,7 @@
return;
}
if (wdcs.mState != AudioService.CONNECTION_STATE_DISCONNECTED) {
- if ((wdcs.mType & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0) {
+ if (DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(wdcs.mType)) {
mDeviceBroker.setBluetoothA2dpOnInt(false,
"onSetWiredDeviceConnectionState state not DISCONNECTED");
}
@@ -764,13 +771,19 @@
// - none of these devices are connected anymore after one is disconnected AND
// - the device being disconnected is actually used for music.
// Access synchronized on mConnectedDevices
- private int mBecomingNoisyIntentDevices =
- AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE
- | AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI
- | AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET
- | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET
- | AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE
- | AudioSystem.DEVICE_OUT_HEARING_AID;
+ private static final Set<Integer> BECOMING_NOISY_INTENT_DEVICES_SET;
+ static {
+ BECOMING_NOISY_INTENT_DEVICES_SET = new HashSet<>();
+ BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADSET);
+ BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
+ BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_HDMI);
+ BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
+ BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET);
+ BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_LINE);
+ BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_HEARING_AID);
+ BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
+ BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET);
+ }
// must be called before removing the device from mConnectedDevices
// musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying
@@ -781,16 +794,16 @@
if (state != AudioService.CONNECTION_STATE_DISCONNECTED) {
return 0;
}
- if ((device & mBecomingNoisyIntentDevices) == 0) {
+ if (!BECOMING_NOISY_INTENT_DEVICES_SET.contains(device)) {
return 0;
}
int delay = 0;
- int devices = 0;
+ Set<Integer> devices = new HashSet<>();
for (int i = 0; i < mConnectedDevices.size(); i++) {
int dev = mConnectedDevices.valueAt(i).mDeviceType;
if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
- && ((dev & mBecomingNoisyIntentDevices) != 0)) {
- devices |= dev;
+ && BECOMING_NOISY_INTENT_DEVICES_SET.contains(dev)) {
+ devices.add(dev);
}
}
if (musicDevice == AudioSystem.DEVICE_NONE) {
@@ -801,8 +814,9 @@
// because music routing is altered in this case.
// also checks whether media routing if affected by a dynamic policy or mirroring
if (((device == musicDevice) || mDeviceBroker.isInCommunication())
- && (device == devices) && !mDeviceBroker.hasMediaDynamicPolicy()
- && ((musicDevice & AudioSystem.DEVICE_OUT_REMOTE_SUBMIX) == 0)) {
+ && AudioSystem.isSingleAudioDeviceType(devices, device)
+ && !mDeviceBroker.hasMediaDynamicPolicy()
+ && (musicDevice != AudioSystem.DEVICE_OUT_REMOTE_SUBMIX)) {
if (!AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0 /*not looking in past*/)
&& !mDeviceBroker.hasAudioFocusUsers()) {
// no media playback, not a "becoming noisy" situation, otherwise it could cause
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 9a92778..e426c6c 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -147,6 +147,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@@ -501,18 +502,20 @@
private volatile IRingtonePlayer mRingtonePlayer;
// Devices for which the volume is fixed (volume is either max or muted)
- int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
- AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
- AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
- AudioSystem.DEVICE_OUT_HDMI_ARC |
- AudioSystem.DEVICE_OUT_SPDIF |
- AudioSystem.DEVICE_OUT_AUX_LINE;
+ Set<Integer> mFixedVolumeDevices = new HashSet<>(Arrays.asList(
+ AudioSystem.DEVICE_OUT_HDMI,
+ AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET,
+ AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET,
+ AudioSystem.DEVICE_OUT_HDMI_ARC,
+ AudioSystem.DEVICE_OUT_SPDIF,
+ AudioSystem.DEVICE_OUT_AUX_LINE));
// Devices for which the volume is always max, no volume panel
- int mFullVolumeDevices = 0;
+ Set<Integer> mFullVolumeDevices = new HashSet<>();
// Devices for the which use the "absolute volume" concept (framework sends audio signal
// full scale, and volume control separately) and can be used for multiple use cases reflected
// by the audio mode (e.g. media playback in MODE_NORMAL, and phone calls in MODE_IN_CALL).
- int mAbsVolumeMultiModeCaseDevices = AudioSystem.DEVICE_OUT_HEARING_AID;
+ Set<Integer> mAbsVolumeMultiModeCaseDevices = new HashSet<>(
+ Arrays.asList(AudioSystem.DEVICE_OUT_HEARING_AID));
private final boolean mMonitorRotation;
@@ -866,13 +869,14 @@
}
mHdmiTvClient = mHdmiManager.getTvClient();
if (mHdmiTvClient != null) {
- mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
+ mFixedVolumeDevices.removeAll(
+ AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET);
}
mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
if (mHdmiPlaybackClient != null) {
// not a television: HDMI output will be always at max
- mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
- mFullVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
+ mFixedVolumeDevices.remove(AudioSystem.DEVICE_OUT_HDMI);
+ mFullVolumeDevices.add(AudioSystem.DEVICE_OUT_HDMI);
}
mHdmiAudioSystemClient = mHdmiManager.getAudioSystemClient();
}
@@ -1131,7 +1135,7 @@
@AudioService.ConnectionState int state, String caller) {
if (state == AudioService.CONNECTION_STATE_CONNECTED) {
// DEVICE_OUT_HDMI is now connected
- if ((AudioSystem.DEVICE_OUT_HDMI & mSafeMediaVolumeDevices) != 0) {
+ if (mSafeMediaVolumeDevices.contains(AudioSystem.DEVICE_OUT_HDMI)) {
sendMsg(mAudioHandler,
MSG_CHECK_MUSIC_ACTIVE,
SENDMSG_REPLACE,
@@ -1762,8 +1766,8 @@
// skip a2dp absolute volume control request when the device
// is not an a2dp device
- if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
- (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
+ if (!AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
+ && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
return;
}
@@ -1784,14 +1788,14 @@
flags &= ~AudioManager.FLAG_FIXED_VOLUME;
if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
- ((device & mFixedVolumeDevices) != 0)) {
+ mFixedVolumeDevices.contains(device)) {
flags |= AudioManager.FLAG_FIXED_VOLUME;
// Always toggle between max safe volume and 0 for fixed volume devices where safe
// volume is enforced, and max and 0 for the others.
// This is simulated by stepping by the full allowed volume range
if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
- (device & mSafeMediaVolumeDevices) != 0) {
+ mSafeMediaVolumeDevices.contains(device)) {
step = safeMediaVolumeIndex(device);
} else {
step = streamState.getMaxIndex();
@@ -1861,7 +1865,7 @@
!checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
mVolumeController.postDisplaySafeVolumeWarning(flags);
- } else if (((device & mFullVolumeDevices) == 0)
+ } else if (!mFullVolumeDevices.contains(device)
&& (streamState.adjustIndex(direction * step, device, caller)
|| streamState.mIsMuted)) {
// Post message to set system volume (it in turn will post a
@@ -1890,9 +1894,9 @@
int newIndex = mStreamStates[streamType].getIndex(device);
// Check if volume update should be send to AVRCP
- if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
- (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
- (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
+ if (streamTypeAlias == AudioSystem.STREAM_MUSIC
+ && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
+ && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
if (DEBUG_VOL) {
Log.d(TAG, "adjustSreamVolume: postSetAvrcpAbsoluteVolumeIndex index="
+ newIndex + "stream=" + streamType);
@@ -1901,7 +1905,7 @@
}
// Check if volume update should be send to Hearing Aid
- if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
+ if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
// only modify the hearing aid attenuation when the stream to modify matches
// the one expected by the hearing aid
if (streamType == getHearingAidStreamType()) {
@@ -1923,7 +1927,7 @@
if (mHdmiCecSink
&& streamTypeAlias == AudioSystem.STREAM_MUSIC
// vol change on a full volume device
- && ((device & mFullVolumeDevices) != 0)) {
+ && mFullVolumeDevices.contains(device)) {
int keyCode = KeyEvent.KEYCODE_UNKNOWN;
switch (direction) {
case AudioManager.ADJUST_RAISE:
@@ -2291,13 +2295,17 @@
int streamType = getHearingAidStreamType(newMode);
- final int device = AudioSystem.getDevicesForStream(streamType);
- if ((device & mAbsVolumeMultiModeCaseDevices) == 0) {
+ final Set<Integer> deviceTypes = AudioSystem.generateAudioDeviceTypesSet(
+ AudioSystem.getDevicesForStream(streamType));
+ final Set<Integer> absVolumeMultiModeCaseDevices = AudioSystem.intersectionAudioDeviceTypes(
+ mAbsVolumeMultiModeCaseDevices, deviceTypes);
+ if (absVolumeMultiModeCaseDevices.isEmpty()) {
return;
}
// handling of specific interfaces goes here:
- if ((device & mAbsVolumeMultiModeCaseDevices) == AudioSystem.DEVICE_OUT_HEARING_AID) {
+ if (AudioSystem.isSingleAudioDeviceType(
+ absVolumeMultiModeCaseDevices, AudioSystem.DEVICE_OUT_HEARING_AID)) {
final int index = getStreamVolume(streamType);
sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_MODE_CHANGE_HEARING_AID,
newMode, streamType, index));
@@ -2324,8 +2332,8 @@
// skip a2dp absolute volume control request when the device
// is not an a2dp device
- if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
- (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
+ if (!AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
+ && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
return;
}
// If we are being called by the system (e.g. hardware keys) check for current user
@@ -2357,7 +2365,7 @@
index = rescaleIndex(index * 10, streamType, streamTypeAlias);
if (streamTypeAlias == AudioSystem.STREAM_MUSIC
- && (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0
+ && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
&& (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
if (DEBUG_VOL) {
Log.d(TAG, "setStreamVolume postSetAvrcpAbsoluteVolumeIndex index=" + index
@@ -2366,7 +2374,7 @@
mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(index / 10);
}
- if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0
+ if (device == AudioSystem.DEVICE_OUT_HEARING_AID
&& streamType == getHearingAidStreamType()) {
Log.i(TAG, "setStreamVolume postSetHearingAidVolumeIndex index=" + index
+ " stream=" + streamType);
@@ -2379,13 +2387,13 @@
flags &= ~AudioManager.FLAG_FIXED_VOLUME;
if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
- ((device & mFixedVolumeDevices) != 0)) {
+ mFixedVolumeDevices.contains(device)) {
flags |= AudioManager.FLAG_FIXED_VOLUME;
// volume is either 0 or max allowed for fixed volume devices
if (index != 0) {
if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
- (device & mSafeMediaVolumeDevices) != 0) {
+ mSafeMediaVolumeDevices.contains(device)) {
index = safeMediaVolumeIndex(device);
} else {
index = streamState.getMaxIndex();
@@ -2568,7 +2576,7 @@
if (streamType == AudioSystem.STREAM_MUSIC) {
flags = updateFlagsForTvPlatform(flags);
- if ((device & mFullVolumeDevices) != 0) {
+ if (mFullVolumeDevices.contains(device)) {
flags &= ~AudioManager.FLAG_SHOW_UI;
}
}
@@ -2614,7 +2622,7 @@
int device,
boolean force,
String caller) {
- if ((device & mFullVolumeDevices) != 0) {
+ if (mFullVolumeDevices.contains(device)) {
return;
}
VolumeStreamState streamState = mStreamStates[streamType];
@@ -2731,8 +2739,8 @@
if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
if (mRmtSbmxFullVolRefCount == 0) {
- mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
- mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
+ mFullVolumeDevices.add(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX);
+ mFixedVolumeDevices.add(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX);
applyRequired = true;
}
mRmtSbmxFullVolRefCount++;
@@ -2741,8 +2749,8 @@
if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
mRmtSbmxFullVolRefCount--;
if (mRmtSbmxFullVolRefCount == 0) {
- mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
- mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
+ mFullVolumeDevices.remove(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX);
+ mFixedVolumeDevices.remove(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX);
applyRequired = true;
}
}
@@ -2824,7 +2832,7 @@
index = 0;
}
if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
- (device & mFixedVolumeDevices) != 0) {
+ mFixedVolumeDevices.contains(device)) {
index = mStreamStates[streamType].getMaxIndex();
}
return (index + 5) / 10;
@@ -3699,7 +3707,7 @@
if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
- if ((device & mSafeMediaVolumeDevices) != 0) {
+ if (mSafeMediaVolumeDevices.contains(device)) {
sendMsg(mAudioHandler,
MSG_CHECK_MUSIC_ACTIVE,
SENDMSG_REPLACE,
@@ -4251,6 +4259,8 @@
// retain the device on the A2DP output as the other must not correspond to an active
// selection if not the speaker.
// - HDMI-CEC system audio mode only output: give priority to available item in order.
+ // FIXME: Haven't applied audio device type refactor to this API
+ // as it is going to be deprecated.
if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
device = AudioSystem.DEVICE_OUT_SPEAKER;
} else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
@@ -4260,7 +4270,11 @@
} else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
device = AudioSystem.DEVICE_OUT_AUX_LINE;
} else {
- device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
+ for (int deviceType : AudioSystem.DEVICE_OUT_ALL_A2DP_SET) {
+ if ((deviceType & device) == deviceType) {
+ return deviceType;
+ }
+ }
}
}
return device;
@@ -4393,12 +4407,16 @@
mDeviceBroker.postBluetoothA2dpDeviceConfigChange(device);
}
- private static final int DEVICE_MEDIA_UNMUTED_ON_PLUG =
- AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
- AudioSystem.DEVICE_OUT_LINE |
- AudioSystem.DEVICE_OUT_ALL_A2DP |
- AudioSystem.DEVICE_OUT_ALL_USB |
- AudioSystem.DEVICE_OUT_HDMI;
+ private static final Set<Integer> DEVICE_MEDIA_UNMUTED_ON_PLUG_SET;
+ static {
+ DEVICE_MEDIA_UNMUTED_ON_PLUG_SET = new HashSet<>();
+ DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADSET);
+ DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
+ DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_LINE);
+ DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_A2DP_SET);
+ DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET);
+ DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_HDMI);
+ }
/** only public for mocking/spying, do not call outside of AudioService */
@VisibleForTesting
@@ -4414,7 +4432,7 @@
}
if (mNm.getZenMode() != Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
- && (newDevice & DEVICE_MEDIA_UNMUTED_ON_PLUG) != 0
+ && DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.contains(newDevice)
&& mStreamStates[AudioSystem.STREAM_MUSIC].mIsMuted
&& mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(newDevice) != 0
&& (newDevice & AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC)) != 0) {
@@ -4543,14 +4561,7 @@
}
}
synchronized (VolumeStreamState.class) {
- int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
-
- for (int i = 0; remainingDevices != 0; i++) {
- int device = (1 << i);
- if ((device & remainingDevices) == 0) {
- continue;
- }
- remainingDevices &= ~device;
+ for (int device : AudioSystem.DEVICE_OUT_ALL_SET) {
// retrieve current volume for device
// if no volume stored for current stream and device, use default volume if default
@@ -4610,11 +4621,12 @@
int index;
if (mIsMuted) {
index = 0;
- } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && isAvrcpAbsVolSupported) {
+ } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
+ && isAvrcpAbsVolSupported) {
index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
- } else if ((device & mFullVolumeDevices) != 0) {
+ } else if (mFullVolumeDevices.contains(device)) {
index = (mIndexMax + 5)/10;
- } else if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
+ } else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
index = (mIndexMax + 5)/10;
} else {
index = (getIndex(device) + 5)/10;
@@ -4632,12 +4644,12 @@
if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
if (mIsMuted) {
index = 0;
- } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
- isAvrcpAbsVolSupported) {
+ } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
+ && isAvrcpAbsVolSupported) {
index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
- } else if ((device & mFullVolumeDevices) != 0) {
+ } else if (mFullVolumeDevices.contains(device)) {
index = (mIndexMax + 5)/10;
- } else if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
+ } else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
index = (mIndexMax + 5)/10;
} else {
index = (mIndexMap.valueAt(i) + 5)/10;
@@ -4698,7 +4710,7 @@
&& device == AudioSystem.DEVICE_OUT_SPEAKER) {
for (int i = 0; i < mIndexMap.size(); i++) {
int otherDevice = mIndexMap.keyAt(i);
- if ((otherDevice & AudioSystem.DEVICE_OUT_ALL_SCO) != 0) {
+ if (AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(otherDevice)) {
mIndexMap.put(otherDevice, index);
}
}
@@ -4836,8 +4848,8 @@
for (int i = 0; i < mIndexMap.size(); i++) {
int device = mIndexMap.keyAt(i);
int index = mIndexMap.valueAt(i);
- if (((device & mFullVolumeDevices) != 0)
- || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
+ if (mFullVolumeDevices.contains(device)
+ || (mFixedVolumeDevices.contains(device) && index != 0)) {
mIndexMap.put(device, mIndexMax);
}
applyDeviceVolume_syncVSS(device, isAvrcpAbsVolSupported);
@@ -5008,7 +5020,7 @@
// that may have a different device selected
int streamDevice = getDeviceForStream(streamType);
if ((device != streamDevice) && isAvrcpAbsVolSupported
- && ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
+ && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)) {
mStreamStates[streamType].applyDeviceVolume_syncVSS(device,
isAvrcpAbsVolSupported);
}
@@ -5337,7 +5349,7 @@
}
/*package*/ void checkMusicActive(int deviceType, String caller) {
- if ((deviceType & mSafeMediaVolumeDevices) != 0) {
+ if (mSafeMediaVolumeDevices.contains(deviceType)) {
sendMsg(mAudioHandler,
MSG_CHECK_MUSIC_ACTIVE,
SENDMSG_REPLACE,
@@ -5783,9 +5795,9 @@
// the headset is compliant to EN 60950 with a max loudness of 100dB SPL.
private int mSafeUsbMediaVolumeIndex;
// mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
- /*package*/ final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET
- | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE
- | AudioSystem.DEVICE_OUT_USB_HEADSET;
+ /*package*/ final Set<Integer> mSafeMediaVolumeDevices = new HashSet<>(
+ Arrays.asList(AudioSystem.DEVICE_OUT_WIRED_HEADSET,
+ AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, AudioSystem.DEVICE_OUT_USB_HEADSET));
// mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
// When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
// automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
@@ -5795,7 +5807,7 @@
private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
private int safeMediaVolumeIndex(int device) {
- if ((device & mSafeMediaVolumeDevices) == 0) {
+ if (!mSafeMediaVolumeDevices.contains(device)) {
return MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC];
}
if (device == AudioSystem.DEVICE_OUT_USB_HEADSET) {
@@ -5830,14 +5842,9 @@
private void enforceSafeMediaVolume(String caller) {
VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
- int devices = mSafeMediaVolumeDevices;
- int i = 0;
+ Set<Integer> devices = mSafeMediaVolumeDevices;
- while (devices != 0) {
- int device = 1 << i++;
- if ((device & devices) == 0) {
- continue;
- }
+ for (int device : devices) {
int index = streamState.getIndex(device);
if (index > safeMediaVolumeIndex(device)) {
streamState.setIndex(safeMediaVolumeIndex(device), device, caller);
@@ -5849,16 +5856,15 @@
streamState,
0);
}
- devices &= ~device;
}
}
private boolean checkSafeMediaVolume(int streamType, int index, int device) {
synchronized (mSafeMediaVolumeStateLock) {
- if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
- (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
- ((device & mSafeMediaVolumeDevices) != 0) &&
- (index > safeMediaVolumeIndex(device))) {
+ if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)
+ && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC)
+ && (mSafeMediaVolumeDevices.contains(device))
+ && (index > safeMediaVolumeIndex(device))) {
return false;
}
return true;
@@ -5899,14 +5905,14 @@
if (DEBUG_VOL) {
Log.d(TAG, "CEC sink: setting HDMI as full vol device");
}
- mFullVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
+ mFullVolumeDevices.add(AudioSystem.DEVICE_OUT_HDMI);
} else {
if (DEBUG_VOL) {
Log.d(TAG, "TV, no CEC: setting HDMI as regular vol device");
}
// Android TV devices without CEC service apply software volume on
// HDMI output
- mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
+ mFullVolumeDevices.remove(AudioSystem.DEVICE_OUT_HDMI);
}
checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI,
@@ -6127,6 +6133,19 @@
pw.println();
}
+ private String dumpDeviceTypes(@NonNull Set<Integer> deviceTypes) {
+ Iterator<Integer> it = deviceTypes.iterator();
+ if (!it.hasNext()) {
+ return "";
+ }
+ final StringBuilder sb = new StringBuilder();
+ sb.append("0x" + Integer.toHexString(it.next()));
+ while (it.hasNext()) {
+ sb.append("," + "0x" + Integer.toHexString(it.next()));
+ }
+ return sb.toString();
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
@@ -6163,7 +6182,7 @@
pw.println(mDeviceBroker.isAvrcpAbsoluteVolumeSupported());
pw.print(" mIsSingleVolume="); pw.println(mIsSingleVolume);
pw.print(" mUseFixedVolume="); pw.println(mUseFixedVolume);
- pw.print(" mFixedVolumeDevices=0x"); pw.println(Integer.toHexString(mFixedVolumeDevices));
+ pw.print(" mFixedVolumeDevices="); pw.println(dumpDeviceTypes(mFixedVolumeDevices));
pw.print(" mHdmiCecSink="); pw.println(mHdmiCecSink);
pw.print(" mHdmiAudioSystemClient="); pw.println(mHdmiAudioSystemClient);
pw.print(" mHdmiPlaybackClient="); pw.println(mHdmiPlaybackClient);
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 637bcae..c84745e 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1169,14 +1169,15 @@
if (newWork != null) {
for (int i = 0; i < newWork.size(); i++) {
mAppOps.startOpNoThrow(AppOpsManager.OP_GPS,
- newWork.get(i), newWork.getName(i));
+ newWork.getUid(i), newWork.getPackageName(i));
}
}
// Update sources that are no longer tracked.
if (goneWork != null) {
for (int i = 0; i < goneWork.size(); i++) {
- mAppOps.finishOp(AppOpsManager.OP_GPS, goneWork.get(i), goneWork.getName(i));
+ mAppOps.finishOp(AppOpsManager.OP_GPS, goneWork.getUid(i),
+ goneWork.getPackageName(i));
}
}
}
diff --git a/services/core/java/com/android/server/location/LocationSettingsStore.java b/services/core/java/com/android/server/location/LocationSettingsStore.java
index a4b6d97..dc5628e 100644
--- a/services/core/java/com/android/server/location/LocationSettingsStore.java
+++ b/services/core/java/com/android/server/location/LocationSettingsStore.java
@@ -237,9 +237,6 @@
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
int userId = ActivityManager.getCurrentUser();
- ipw.println("--Location Settings--");
- ipw.increaseIndent();
-
ipw.print("Location Enabled: ");
ipw.println(isLocationEnabled(userId));
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 7820cd7..2cf920d 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -83,6 +83,24 @@
mContext = context;
}
+ @NonNull
+ public List<MediaRoute2Info> getSystemRoutes() {
+ final int uid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(uid);
+
+ Collection<MediaRoute2Info> systemRoutes;
+ synchronized (mLock) {
+ UserRecord userRecord = mUserRecords.get(userId);
+ if (userRecord == null) {
+ userRecord = new UserRecord(userId);
+ mUserRecords.put(userId, userRecord);
+ initializeUserLocked(userRecord);
+ }
+ systemRoutes = userRecord.mHandler.mSystemProvider.getProviderInfo().getRoutes();
+ }
+ return new ArrayList<>(systemRoutes);
+ }
+
public void registerClient(@NonNull IMediaRouter2Client client,
@NonNull String packageName) {
Objects.requireNonNull(client, "client must not be null");
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index ecc1aba..9336af4 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -443,6 +443,12 @@
// Binder call
@Override
+ public List<MediaRoute2Info> getSystemRoutes() {
+ return mService2.getSystemRoutes();
+ }
+
+ // Binder call
+ @Override
public void registerClient2(IMediaRouter2Client client, String packageName) {
final int uid = Binder.getCallingUid();
if (!validatePackageName(uid, packageName)) {
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index 620775e..4f64177 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -42,8 +42,8 @@
private static final String TAG = "MR2SystemProvider";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private static final String DEFAULT_ROUTE_ID = "DEFAULT_ROUTE";
- private static final String BLUETOOTH_ROUTE_ID = "BLUETOOTH_ROUTE";
+ static final String DEFAULT_ROUTE_ID = "DEFAULT_ROUTE";
+ static final String BLUETOOTH_ROUTE_ID = "BLUETOOTH_ROUTE";
// TODO: Move these to a proper place
public static final String CATEGORY_LIVE_AUDIO = "android.media.intent.category.LIVE_AUDIO";
@@ -191,12 +191,20 @@
publishRoutes();
}
+
+ /**
+ * The first route should be the currently selected system route.
+ * For example, if there are two system routes (BT and device speaker),
+ * BT will be the first route in the list.
+ *
+ * TODO: Support multiple BT devices
+ */
void publishRoutes() {
- MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder()
- .addRoute(mDefaultRoute);
+ MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder();
if (mBluetoothA2dpRoute != null) {
builder.addRoute(mBluetoothA2dpRoute);
}
+ builder.addRoute(mDefaultRoute);
setAndNotifyProviderInfo(builder.build());
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0ae4a8f..b60306b 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -360,9 +360,11 @@
private static final String EXTRA_KEY = "key";
/**
- * Apps targeting R+ that post custom toasts in the background will have those blocked. Apps can
+ * Apps that post custom toasts in the background will have those blocked. Apps can
* still post toasts created with {@link Toast#makeText(Context, CharSequence, int)} and its
* variants while in the background.
+ *
+ * TODO(b/144152069): Add @EnabledAfter(Q) to target R+ after assessing impact on dogfood
*/
@ChangeId
private static final long CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK = 128611929L;
diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
new file mode 100644
index 0000000..e055116
--- /dev/null
+++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.om;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.om.OverlayInfo;
+import android.content.om.OverlayableInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.net.Uri;
+import android.os.Process;
+import android.os.RemoteException;
+import android.text.TextUtils;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
+import com.android.server.SystemConfig;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Performs verification that a calling UID can act on a target package's overlayable.
+ *
+ * @hide
+ */
+public class OverlayActorEnforcer {
+
+ private final VerifyCallback mVerifyCallback;
+
+ public OverlayActorEnforcer(@NonNull VerifyCallback verifyCallback) {
+ mVerifyCallback = verifyCallback;
+ }
+
+ void enforceActor(@NonNull OverlayInfo overlayInfo, @NonNull String methodName,
+ int callingUid, int userId) throws SecurityException {
+ ActorState actorState = isAllowedActor(methodName, overlayInfo, callingUid, userId);
+ if (actorState == ActorState.ALLOWED) {
+ return;
+ }
+
+ String targetOverlayableName = overlayInfo.targetOverlayableName;
+ throw new SecurityException("UID" + callingUid + " is not allowed to call "
+ + methodName + " for "
+ + (TextUtils.isEmpty(targetOverlayableName) ? "" : (targetOverlayableName + " in "))
+ + overlayInfo.targetPackageName + " because " + actorState
+ );
+ }
+
+ /**
+ * An actor is valid if any of the following is true:
+ * - is {@link Process#ROOT_UID}, {@link Process#SYSTEM_UID}
+ * - is the target overlay package
+ * - has the CHANGE_OVERLAY_PACKAGES permission and an actor is not defined
+ * - is the same the as the package defined in {@link SystemConfig#getNamedActors()} for a given
+ * namespace and actor name
+ *
+ * @return true if the actor is allowed to act on the target overlayInfo
+ */
+ private ActorState isAllowedActor(String methodName, OverlayInfo overlayInfo,
+ int callingUid, int userId) {
+ switch (callingUid) {
+ case Process.ROOT_UID:
+ case Process.SYSTEM_UID:
+ return ActorState.ALLOWED;
+ }
+
+ String[] callingPackageNames = mVerifyCallback.getPackagesForUid(callingUid);
+ if (ArrayUtils.isEmpty(callingPackageNames)) {
+ return ActorState.NO_PACKAGES_FOR_UID;
+ }
+
+ // A target is always an allowed actor for itself
+ String targetPackageName = overlayInfo.targetPackageName;
+ if (ArrayUtils.contains(callingPackageNames, targetPackageName)) {
+ return ActorState.ALLOWED;
+ }
+
+ String targetOverlayableName = overlayInfo.targetOverlayableName;
+
+ if (TextUtils.isEmpty(targetOverlayableName)) {
+ try {
+ if (mVerifyCallback.doesTargetDefineOverlayable(targetPackageName, userId)) {
+ return ActorState.MISSING_TARGET_OVERLAYABLE_NAME;
+ } else {
+ // If there's no overlayable defined, fallback to the legacy permission check
+ try {
+ mVerifyCallback.enforcePermission(
+ android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName);
+
+ // If the previous method didn't throw, check passed
+ return ActorState.ALLOWED;
+ } catch (SecurityException e) {
+ return ActorState.MISSING_LEGACY_PERMISSION;
+ }
+ }
+ } catch (RemoteException | IOException e) {
+ return ActorState.ERROR_READING_OVERLAYABLE;
+ }
+ }
+
+ OverlayableInfo targetOverlayable;
+ try {
+ targetOverlayable = mVerifyCallback.getOverlayableForTarget(targetPackageName,
+ targetOverlayableName, userId);
+ } catch (IOException e) {
+ return ActorState.UNABLE_TO_GET_TARGET;
+ }
+
+ if (targetOverlayable == null) {
+ return ActorState.MISSING_OVERLAYABLE;
+ }
+
+ String actor = targetOverlayable.actor;
+ if (TextUtils.isEmpty(actor)) {
+ // If there's no actor defined, fallback to the legacy permission check
+ try {
+ mVerifyCallback.enforcePermission(
+ android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName);
+
+ // If the previous method didn't throw, check passed
+ return ActorState.ALLOWED;
+ } catch (SecurityException e) {
+ return ActorState.MISSING_LEGACY_PERMISSION;
+ }
+ }
+
+ Map<String, ? extends Map<String, String>> namedActors = mVerifyCallback.getNamedActors();
+ if (namedActors.isEmpty()) {
+ return ActorState.NO_NAMED_ACTORS;
+ }
+
+ Uri actorUri = Uri.parse(actor);
+
+ String actorScheme = actorUri.getScheme();
+ List<String> actorPathSegments = actorUri.getPathSegments();
+ if (!"overlay".equals(actorScheme) || CollectionUtils.size(actorPathSegments) != 1) {
+ return ActorState.INVALID_OVERLAYABLE_ACTOR_NAME;
+ }
+
+ String actorNamespace = actorUri.getAuthority();
+ Map<String, String> namespace = namedActors.get(actorNamespace);
+ if (namespace == null) {
+ return ActorState.MISSING_NAMESPACE;
+ }
+
+ String actorName = actorPathSegments.get(0);
+ String packageName = namespace.get(actorName);
+ if (TextUtils.isEmpty(packageName)) {
+ return ActorState.MISSING_ACTOR_NAME;
+ }
+
+ PackageInfo packageInfo = mVerifyCallback.getPackageInfo(packageName, userId);
+ if (packageInfo == null) {
+ return ActorState.MISSING_APP_INFO;
+ }
+
+ ApplicationInfo appInfo = packageInfo.applicationInfo;
+ if (appInfo == null) {
+ return ActorState.MISSING_APP_INFO;
+ }
+
+ // Currently only pre-installed apps can be actors
+ if (!appInfo.isSystemApp() && !appInfo.isUpdatedSystemApp()) {
+ return ActorState.ACTOR_NOT_PREINSTALLED;
+ }
+
+ if (ArrayUtils.contains(callingPackageNames, packageName)) {
+ return ActorState.ALLOWED;
+ }
+
+ return ActorState.INVALID_ACTOR;
+ }
+
+ /**
+ * For easier logging/debugging, a set of all possible failure/success states when running
+ * enforcement.
+ */
+ private enum ActorState {
+ ALLOWED,
+ INVALID_ACTOR,
+ MISSING_NAMESPACE,
+ MISSING_PACKAGE,
+ MISSING_APP_INFO,
+ ACTOR_NOT_PREINSTALLED,
+ NO_PACKAGES_FOR_UID,
+ MISSING_ACTOR_NAME,
+ ERROR_READING_OVERLAYABLE,
+ MISSING_TARGET_OVERLAYABLE_NAME,
+ MISSING_OVERLAYABLE,
+ INVALID_OVERLAYABLE_ACTOR_NAME,
+ NO_NAMED_ACTORS,
+ UNABLE_TO_GET_TARGET,
+ MISSING_LEGACY_PERMISSION
+ }
+
+ /**
+ * Delegate to the system for querying information about packages.
+ */
+ public interface VerifyCallback {
+
+ /**
+ * Read from the APK and AndroidManifest of a package to return the overlayable defined for
+ * a given name.
+ *
+ * @throws IOException if the target can't be read
+ */
+ @Nullable
+ OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
+ @Nullable String targetOverlayableName, int userId)
+ throws IOException;
+
+ /**
+ * @see android.content.pm.PackageManager#getPackagesForUid(int)
+ */
+ @Nullable
+ String[] getPackagesForUid(int uid);
+
+ /**
+ * @param userId user to filter package visibility by
+ * @see android.content.pm.PackageManager#getPackageInfo(String, int)
+ */
+ @Nullable
+ PackageInfo getPackageInfo(@NonNull String packageName, int userId);
+
+ /**
+ * @return map of system pre-defined, uniquely named actors; keys are namespace,
+ * value maps actor name to package name
+ */
+ @NonNull
+ Map<String, ? extends Map<String, String>> getNamedActors();
+
+ /**
+ * @return true if the target package has declared an overlayable
+ */
+ boolean doesTargetDefineOverlayable(String targetPackageName, int userId)
+ throws RemoteException, IOException;
+
+ /**
+ * @throws SecurityException containing message if the caller doesn't have the given
+ * permission
+ */
+ void enforcePermission(String permission, String message) throws SecurityException;
+ }
+}
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 5f3e503..63de61c 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -39,10 +39,12 @@
import android.content.IntentFilter;
import android.content.om.IOverlayManager;
import android.content.om.OverlayInfo;
+import android.content.om.OverlayableInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
+import android.content.res.ApkAssets;
import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
@@ -63,6 +65,7 @@
import com.android.server.FgThread;
import com.android.server.IoThread;
import com.android.server.LocalServices;
+import com.android.server.SystemConfig;
import com.android.server.SystemService;
import com.android.server.pm.UserManagerService;
@@ -229,6 +232,8 @@
private final OverlayManagerServiceImpl mImpl;
+ private final OverlayActorEnforcer mActorEnforcer;
+
private final AtomicBoolean mPersistSettingsScheduled = new AtomicBoolean(false);
public OverlayManagerService(@NonNull final Context context) {
@@ -237,12 +242,13 @@
traceBegin(TRACE_TAG_RRO, "OMS#OverlayManagerService");
mSettingsFile = new AtomicFile(
new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays");
- mPackageManager = new PackageManagerHelper();
+ mPackageManager = new PackageManagerHelper(context);
mUserManager = UserManagerService.getInstance();
IdmapManager im = new IdmapManager(mPackageManager);
mSettings = new OverlayManagerSettings();
mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
getDefaultOverlayPackages(), new OverlayChangeListener());
+ mActorEnforcer = new OverlayActorEnforcer(mPackageManager);
final IntentFilter packageFilter = new IntentFilter();
packageFilter.addAction(ACTION_PACKAGE_ADDED);
@@ -581,7 +587,7 @@
int userId) throws RemoteException {
try {
traceBegin(TRACE_TAG_RRO, "OMS#setEnabled " + packageName + " " + enable);
- enforceChangeOverlayPackagesPermission("setEnabled");
+ enforceActor(packageName, "setEnabled", userId);
userId = handleIncomingUser(userId, "setEnabled");
if (packageName == null) {
return false;
@@ -605,7 +611,7 @@
int userId) throws RemoteException {
try {
traceBegin(TRACE_TAG_RRO, "OMS#setEnabledExclusive " + packageName + " " + enable);
- enforceChangeOverlayPackagesPermission("setEnabledExclusive");
+ enforceActor(packageName, "setEnabledExclusive", userId);
userId = handleIncomingUser(userId, "setEnabledExclusive");
if (packageName == null || !enable) {
return false;
@@ -630,7 +636,7 @@
throws RemoteException {
try {
traceBegin(TRACE_TAG_RRO, "OMS#setEnabledExclusiveInCategory " + packageName);
- enforceChangeOverlayPackagesPermission("setEnabledExclusiveInCategory");
+ enforceActor(packageName, "setEnabledExclusiveInCategory", userId);
userId = handleIncomingUser(userId, "setEnabledExclusiveInCategory");
if (packageName == null) {
return false;
@@ -656,7 +662,7 @@
try {
traceBegin(TRACE_TAG_RRO, "OMS#setPriority " + packageName + " "
+ parentPackageName);
- enforceChangeOverlayPackagesPermission("setPriority");
+ enforceActor(packageName, "setPriority", userId);
userId = handleIncomingUser(userId, "setPriority");
if (packageName == null || parentPackageName == null) {
return false;
@@ -680,7 +686,7 @@
throws RemoteException {
try {
traceBegin(TRACE_TAG_RRO, "OMS#setHighestPriority " + packageName);
- enforceChangeOverlayPackagesPermission("setHighestPriority");
+ enforceActor(packageName, "setHighestPriority", userId);
userId = handleIncomingUser(userId, "setHighestPriority");
if (packageName == null) {
return false;
@@ -704,7 +710,7 @@
throws RemoteException {
try {
traceBegin(TRACE_TAG_RRO, "OMS#setLowestPriority " + packageName);
- enforceChangeOverlayPackagesPermission("setLowestPriority");
+ enforceActor(packageName, "setLowestPriority", userId);
userId = handleIncomingUser(userId, "setLowestPriority");
if (packageName == null) {
return false;
@@ -750,7 +756,7 @@
return;
}
- enforceChangeOverlayPackagesPermission("invalidateCachesForOverlay");
+ enforceActor(packageName, "invalidateCachesForOverlay", userId);
userId = handleIncomingUser(userId, "invalidateCachesForOverlay");
final long ident = Binder.clearCallingIdentity();
try {
@@ -861,18 +867,6 @@
}
/**
- * Enforce that the caller holds the CHANGE_OVERLAY_PACKAGES permission (or is
- * system or root).
- *
- * @param message used as message if SecurityException is thrown
- * @throws SecurityException if the permission check fails
- */
- private void enforceChangeOverlayPackagesPermission(@NonNull final String message) {
- getContext().enforceCallingOrSelfPermission(
- android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, message);
- }
-
- /**
* Enforce that the caller holds the DUMP permission (or is system or root).
*
* @param message used as message if SecurityException is thrown
@@ -881,6 +875,13 @@
private void enforceDumpPermission(@NonNull final String message) {
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, message);
}
+
+ private void enforceActor(String packageName, String methodName, int userId)
+ throws SecurityException {
+ OverlayInfo overlayInfo = mImpl.getOverlayInfo(packageName, userId);
+ int callingUid = Binder.getCallingUid();
+ mActorEnforcer.enforceActor(overlayInfo, methodName, callingUid, userId);
+ }
};
private final class OverlayChangeListener
@@ -1035,9 +1036,16 @@
}
}
- private static final class PackageManagerHelper implements
- OverlayManagerServiceImpl.PackageManagerHelper {
+ /**
+ * Delegate for {@link android.content.pm.PackageManager} and {@link PackageManagerInternal}
+ * functionality, separated for easy testing.
+ *
+ * @hide
+ */
+ public static final class PackageManagerHelper implements
+ OverlayManagerServiceImpl.PackageManagerHelper, OverlayActorEnforcer.VerifyCallback {
+ private final Context mContext;
private final IPackageManager mPackageManager;
private final PackageManagerInternal mPackageManagerInternal;
@@ -1048,11 +1056,14 @@
// behind until all pending intents have been processed.
private final SparseArray<HashMap<String, PackageInfo>> mCache = new SparseArray<>();
- PackageManagerHelper() {
+ PackageManagerHelper(Context context) {
+ mContext = context;
mPackageManager = getPackageManager();
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
}
+ // TODO(b/143096091): Remove PackageInfo cache so that PackageManager is always queried
+ // to enforce visibility/other permission checks
public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId,
final boolean useCache) {
if (useCache) {
@@ -1075,7 +1086,19 @@
@Override
public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId) {
- return getPackageInfo(packageName, userId, true);
+ // TODO(b/143096091): Remove clearing calling ID
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ return getPackageInfo(packageName, userId, true);
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ }
+
+ @NonNull
+ @Override
+ public Map<String, ? extends Map<String, String>> getNamedActors() {
+ return SystemConfig.getInstance().getNamedActors();
}
@Override
@@ -1097,6 +1120,70 @@
return mPackageManagerInternal.getOverlayPackages(userId);
}
+ @Nullable
+ @Override
+ public OverlayableInfo getOverlayableForTarget(@NonNull String packageName,
+ @Nullable String targetOverlayableName, int userId)
+ throws IOException {
+ // TODO(b/143096091): Remove clearing calling ID
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ PackageInfo packageInfo = getPackageInfo(packageName, userId);
+ if (packageInfo == null) {
+ throw new IOException("Unable to get target package");
+ }
+
+ String baseCodePath = packageInfo.applicationInfo.getBaseCodePath();
+
+ ApkAssets apkAssets = null;
+ try {
+ apkAssets = ApkAssets.loadFromPath(baseCodePath);
+ return apkAssets.getOverlayableInfo(targetOverlayableName);
+ } finally {
+ if (apkAssets != null) {
+ try {
+ apkAssets.close();
+ } catch (Throwable ignored) {
+ }
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ }
+
+ @Override
+ public boolean doesTargetDefineOverlayable(String targetPackageName, int userId)
+ throws RemoteException, IOException {
+ // TODO(b/143096091): Remove clearing calling ID
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ PackageInfo packageInfo = mPackageManager.getPackageInfo(targetPackageName, 0,
+ userId);
+ String baseCodePath = packageInfo.applicationInfo.getBaseCodePath();
+
+ ApkAssets apkAssets = null;
+ try {
+ apkAssets = ApkAssets.loadFromPath(baseCodePath);
+ return apkAssets.definesOverlayable();
+ } finally {
+ if (apkAssets != null) {
+ try {
+ apkAssets.close();
+ } catch (Throwable ignored) {
+ }
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ }
+
+ @Override
+ public void enforcePermission(String permission, String message) throws SecurityException {
+ mContext.enforceCallingOrSelfPermission(permission, message);
+ }
+
public PackageInfo getCachedPackageInfo(@NonNull final String packageName,
final int userId) {
final HashMap<String, PackageInfo> map = mCache.get(userId);
@@ -1128,6 +1215,22 @@
mCache.delete(userId);
}
+ @Nullable
+ @Override
+ public String[] getPackagesForUid(int uid) {
+ // TODO(b/143096091): Remove clearing calling ID
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ try {
+ return mPackageManager.getPackagesForUid(uid);
+ } catch (RemoteException ignored) {
+ return null;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ }
+
private static final String TAB1 = " ";
private static final String TAB2 = TAB1 + TAB1;
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index 62ea95b..f8c173f 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -32,6 +32,9 @@
per-file CrossProfileIntentResolver.java = omakoto@google.com, yamasani@google.com
per-file UserManagerService.java = omakoto@google.com, yamasani@google.com
per-file UserRestrictionsUtils.java = omakoto@google.com, rubinxu@google.com, sandness@google.com, yamasani@google.com
+per-file UserSystemPackageInstaller.java = bookatz@google.com, omakoto@google.com, yamasani@google.com
+per-file UserTypeDetails.java = bookatz@google.com, omakoto@google.com, yamasani@google.com
+per-file UserTypeFactory.java = bookatz@google.com, omakoto@google.com, yamasani@google.com
# security
per-file KeySetHandle.java = cbrubaker@google.com, nnk@google.com
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index fce7f04..9cfd095 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -107,6 +107,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
/**
@@ -1174,9 +1175,9 @@
opPackageName = workChain.getAttributionTag();
opUid = workChain.getAttributionUid();
} else {
- opPackageName = workSource.getName(0) != null
- ? workSource.getName(0) : wakeLock.mPackageName;
- opUid = workSource.get(0);
+ opPackageName = workSource.getPackageName(0) != null
+ ? workSource.getPackageName(0) : wakeLock.mPackageName;
+ opUid = workSource.getUid(0);
}
} else {
opPackageName = wakeLock.mPackageName;
@@ -2004,13 +2005,13 @@
private boolean wakeLockAffectsUser(WakeLock wakeLock, @UserIdInt int userId) {
if (wakeLock.mWorkSource != null) {
for (int k = 0; k < wakeLock.mWorkSource.size(); k++) {
- final int uid = wakeLock.mWorkSource.get(k);
+ final int uid = wakeLock.mWorkSource.getUid(k);
if (userId == UserHandle.getUserId(uid)) {
return true;
}
}
- final ArrayList<WorkChain> workChains = wakeLock.mWorkSource.getWorkChains();
+ final List<WorkChain> workChains = wakeLock.mWorkSource.getWorkChains();
if (workChains != null) {
for (int k = 0; k < workChains.size(); k++) {
final int uid = workChains.get(k).getAttributionUid();
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index d78aaa5..fe18fbf 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -27,6 +27,7 @@
import android.os.SystemProperties;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.SystemService;
import libcore.io.IoUtils;
@@ -35,6 +36,7 @@
import java.io.DataOutputStream;
import java.io.FileWriter;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
/**
* The recovery system service is responsible for coordinating recovery related
@@ -43,7 +45,7 @@
* triggers /system/bin/uncrypt via init to de-encrypt an OTA package on the
* /data partition so that it can be accessed under the recovery image.
*/
-public final class RecoverySystemService extends SystemService {
+public class RecoverySystemService extends IRecoverySystem.Stub {
private static final String TAG = "RecoverySystemService";
private static final boolean DEBUG = false;
@@ -51,191 +53,321 @@
private static final String UNCRYPT_SOCKET = "uncrypt";
// The init services that communicate with /system/bin/uncrypt.
- private static final String INIT_SERVICE_UNCRYPT = "init.svc.uncrypt";
- private static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb";
- private static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb";
-
- private static final int SOCKET_CONNECTION_MAX_RETRY = 30;
+ @VisibleForTesting
+ static final String INIT_SERVICE_UNCRYPT = "init.svc.uncrypt";
+ @VisibleForTesting
+ static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb";
+ @VisibleForTesting
+ static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb";
private static final Object sRequestLock = new Object();
- private Context mContext;
+ private static final int SOCKET_CONNECTION_MAX_RETRY = 30;
- public RecoverySystemService(Context context) {
- super(context);
- mContext = context;
+ private final Injector mInjector;
+ private final Context mContext;
+
+ static class Injector {
+ protected final Context mContext;
+
+ Injector(Context context) {
+ mContext = context;
+ }
+
+ public Context getContext() {
+ return mContext;
+ }
+
+ public PowerManager getPowerManager() {
+ return (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ }
+
+ public String systemPropertiesGet(String key) {
+ return SystemProperties.get(key);
+ }
+
+ public void systemPropertiesSet(String key, String value) {
+ SystemProperties.set(key, value);
+ }
+
+ public boolean uncryptPackageFileDelete() {
+ return RecoverySystem.UNCRYPT_PACKAGE_FILE.delete();
+ }
+
+ public String getUncryptPackageFileName() {
+ return RecoverySystem.UNCRYPT_PACKAGE_FILE.getName();
+ }
+
+ public FileWriter getUncryptPackageFileWriter() throws IOException {
+ return new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE);
+ }
+
+ public UncryptSocket connectService() {
+ UncryptSocket socket = new UncryptSocket();
+ if (!socket.connectService()) {
+ socket.close();
+ return null;
+ }
+ return socket;
+ }
+
+ public void threadSleep(long millis) throws InterruptedException {
+ Thread.sleep(millis);
+ }
}
- @Override
- public void onStart() {
- publishBinderService(Context.RECOVERY_SERVICE, new BinderService());
+ /**
+ * Handles the lifecycle events for the RecoverySystemService.
+ */
+ public static final class Lifecycle extends SystemService {
+ public Lifecycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ RecoverySystemService recoverySystemService = new RecoverySystemService(getContext());
+ publishBinderService(Context.RECOVERY_SERVICE, recoverySystemService);
+ }
}
- private final class BinderService extends IRecoverySystem.Stub {
- @Override // Binder call
- public boolean uncrypt(String filename, IRecoverySystemProgressListener listener) {
- if (DEBUG) Slog.d(TAG, "uncrypt: " + filename);
+ private RecoverySystemService(Context context) {
+ this(new Injector(context));
+ }
- synchronized (sRequestLock) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
+ @VisibleForTesting
+ RecoverySystemService(Injector injector) {
+ mInjector = injector;
+ mContext = injector.getContext();
+ }
- final boolean available = checkAndWaitForUncryptService();
- if (!available) {
- Slog.e(TAG, "uncrypt service is unavailable.");
- return false;
- }
+ @Override // Binder call
+ public boolean uncrypt(String filename, IRecoverySystemProgressListener listener) {
+ if (DEBUG) Slog.d(TAG, "uncrypt: " + filename);
- // Write the filename into UNCRYPT_PACKAGE_FILE to be read by
- // uncrypt.
- RecoverySystem.UNCRYPT_PACKAGE_FILE.delete();
+ synchronized (sRequestLock) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
- try (FileWriter uncryptFile = new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE)) {
- uncryptFile.write(filename + "\n");
- } catch (IOException e) {
- Slog.e(TAG, "IOException when writing \"" +
- RecoverySystem.UNCRYPT_PACKAGE_FILE + "\":", e);
- return false;
- }
+ if (!checkAndWaitForUncryptService()) {
+ Slog.e(TAG, "uncrypt service is unavailable.");
+ return false;
+ }
- // Trigger uncrypt via init.
- SystemProperties.set("ctl.start", "uncrypt");
+ // Write the filename into uncrypt package file to be read by
+ // uncrypt.
+ mInjector.uncryptPackageFileDelete();
- // Connect to the uncrypt service socket.
- LocalSocket socket = connectService();
- if (socket == null) {
- Slog.e(TAG, "Failed to connect to uncrypt socket");
- return false;
- }
+ try (FileWriter uncryptFile = mInjector.getUncryptPackageFileWriter()) {
+ uncryptFile.write(filename + "\n");
+ } catch (IOException e) {
+ Slog.e(TAG, "IOException when writing \""
+ + mInjector.getUncryptPackageFileName() + "\":", e);
+ return false;
+ }
- // Read the status from the socket.
- DataInputStream dis = null;
- DataOutputStream dos = null;
- try {
- dis = new DataInputStream(socket.getInputStream());
- dos = new DataOutputStream(socket.getOutputStream());
- int lastStatus = Integer.MIN_VALUE;
- while (true) {
- int status = dis.readInt();
- // Avoid flooding the log with the same message.
- if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
- continue;
- }
- lastStatus = status;
+ // Trigger uncrypt via init.
+ mInjector.systemPropertiesSet("ctl.start", "uncrypt");
- if (status >= 0 && status <= 100) {
- // Update status
- Slog.i(TAG, "uncrypt read status: " + status);
- if (listener != null) {
- try {
- listener.onProgress(status);
- } catch (RemoteException ignored) {
- Slog.w(TAG, "RemoteException when posting progress");
- }
- }
- if (status == 100) {
- Slog.i(TAG, "uncrypt successfully finished.");
- // Ack receipt of the final status code. uncrypt
- // waits for the ack so the socket won't be
- // destroyed before we receive the code.
- dos.writeInt(0);
- break;
- }
- } else {
- // Error in /system/bin/uncrypt.
- Slog.e(TAG, "uncrypt failed with status: " + status);
- // Ack receipt of the final status code. uncrypt waits
- // for the ack so the socket won't be destroyed before
- // we receive the code.
- dos.writeInt(0);
- return false;
- }
+ // Connect to the uncrypt service socket.
+ UncryptSocket socket = mInjector.connectService();
+ if (socket == null) {
+ Slog.e(TAG, "Failed to connect to uncrypt socket");
+ return false;
+ }
+
+ // Read the status from the socket.
+ try {
+ int lastStatus = Integer.MIN_VALUE;
+ while (true) {
+ int status = socket.getPercentageUncrypted();
+ // Avoid flooding the log with the same message.
+ if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
+ continue;
}
- } catch (IOException e) {
- Slog.e(TAG, "IOException when reading status: ", e);
- return false;
- } finally {
- IoUtils.closeQuietly(dis);
- IoUtils.closeQuietly(dos);
- IoUtils.closeQuietly(socket);
- }
+ lastStatus = status;
+ if (status >= 0 && status <= 100) {
+ // Update status
+ Slog.i(TAG, "uncrypt read status: " + status);
+ if (listener != null) {
+ try {
+ listener.onProgress(status);
+ } catch (RemoteException ignored) {
+ Slog.w(TAG, "RemoteException when posting progress");
+ }
+ }
+ if (status == 100) {
+ Slog.i(TAG, "uncrypt successfully finished.");
+ // Ack receipt of the final status code. uncrypt
+ // waits for the ack so the socket won't be
+ // destroyed before we receive the code.
+ socket.sendAck();
+ break;
+ }
+ } else {
+ // Error in /system/bin/uncrypt.
+ Slog.e(TAG, "uncrypt failed with status: " + status);
+ // Ack receipt of the final status code. uncrypt waits
+ // for the ack so the socket won't be destroyed before
+ // we receive the code.
+ socket.sendAck();
+ return false;
+ }
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "IOException when reading status: ", e);
+ return false;
+ } finally {
+ socket.close();
+ }
+
+ return true;
+ }
+ }
+
+ @Override // Binder call
+ public boolean clearBcb() {
+ if (DEBUG) Slog.d(TAG, "clearBcb");
+ synchronized (sRequestLock) {
+ return setupOrClearBcb(false, null);
+ }
+ }
+
+ @Override // Binder call
+ public boolean setupBcb(String command) {
+ if (DEBUG) Slog.d(TAG, "setupBcb: [" + command + "]");
+ synchronized (sRequestLock) {
+ return setupOrClearBcb(true, command);
+ }
+ }
+
+ @Override // Binder call
+ public void rebootRecoveryWithCommand(String command) {
+ if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");
+ synchronized (sRequestLock) {
+ if (!setupOrClearBcb(true, command)) {
+ return;
+ }
+
+ // Having set up the BCB, go ahead and reboot.
+ PowerManager pm = mInjector.getPowerManager();
+ pm.reboot(PowerManager.REBOOT_RECOVERY);
+ }
+ }
+
+ /**
+ * Check if any of the init services is still running. If so, we cannot
+ * start a new uncrypt/setup-bcb/clear-bcb service right away; otherwise
+ * it may break the socket communication since init creates / deletes
+ * the socket (/dev/socket/uncrypt) on service start / exit.
+ */
+ private boolean checkAndWaitForUncryptService() {
+ for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
+ final String uncryptService = mInjector.systemPropertiesGet(INIT_SERVICE_UNCRYPT);
+ final String setupBcbService = mInjector.systemPropertiesGet(INIT_SERVICE_SETUP_BCB);
+ final String clearBcbService = mInjector.systemPropertiesGet(INIT_SERVICE_CLEAR_BCB);
+ final boolean busy = "running".equals(uncryptService)
+ || "running".equals(setupBcbService) || "running".equals(clearBcbService);
+ if (DEBUG) {
+ Slog.i(TAG, "retry: " + retry + " busy: " + busy
+ + " uncrypt: [" + uncryptService + "]"
+ + " setupBcb: [" + setupBcbService + "]"
+ + " clearBcb: [" + clearBcbService + "]");
+ }
+
+ if (!busy) {
return true;
}
- }
- @Override // Binder call
- public boolean clearBcb() {
- if (DEBUG) Slog.d(TAG, "clearBcb");
- synchronized (sRequestLock) {
- return setupOrClearBcb(false, null);
+ try {
+ mInjector.threadSleep(1000);
+ } catch (InterruptedException e) {
+ Slog.w(TAG, "Interrupted:", e);
}
}
- @Override // Binder call
- public boolean setupBcb(String command) {
- if (DEBUG) Slog.d(TAG, "setupBcb: [" + command + "]");
- synchronized (sRequestLock) {
- return setupOrClearBcb(true, command);
- }
- }
+ return false;
+ }
- @Override // Binder call
- public void rebootRecoveryWithCommand(String command) {
- if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");
- synchronized (sRequestLock) {
- if (!setupOrClearBcb(true, command)) {
- return;
- }
+ private boolean setupOrClearBcb(boolean isSetup, String command) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
- // Having set up the BCB, go ahead and reboot.
- PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- pm.reboot(PowerManager.REBOOT_RECOVERY);
- }
- }
-
- /**
- * Check if any of the init services is still running. If so, we cannot
- * start a new uncrypt/setup-bcb/clear-bcb service right away; otherwise
- * it may break the socket communication since init creates / deletes
- * the socket (/dev/socket/uncrypt) on service start / exit.
- */
- private boolean checkAndWaitForUncryptService() {
- for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
- final String uncryptService = SystemProperties.get(INIT_SERVICE_UNCRYPT);
- final String setupBcbService = SystemProperties.get(INIT_SERVICE_SETUP_BCB);
- final String clearBcbService = SystemProperties.get(INIT_SERVICE_CLEAR_BCB);
- final boolean busy = "running".equals(uncryptService) ||
- "running".equals(setupBcbService) || "running".equals(clearBcbService);
- if (DEBUG) {
- Slog.i(TAG, "retry: " + retry + " busy: " + busy +
- " uncrypt: [" + uncryptService + "]" +
- " setupBcb: [" + setupBcbService + "]" +
- " clearBcb: [" + clearBcbService + "]");
- }
-
- if (!busy) {
- return true;
- }
-
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- Slog.w(TAG, "Interrupted:", e);
- }
- }
-
+ final boolean available = checkAndWaitForUncryptService();
+ if (!available) {
+ Slog.e(TAG, "uncrypt service is unavailable.");
return false;
}
- private LocalSocket connectService() {
- LocalSocket socket = new LocalSocket();
+ if (isSetup) {
+ mInjector.systemPropertiesSet("ctl.start", "setup-bcb");
+ } else {
+ mInjector.systemPropertiesSet("ctl.start", "clear-bcb");
+ }
+
+ // Connect to the uncrypt service socket.
+ UncryptSocket socket = mInjector.connectService();
+ if (socket == null) {
+ Slog.e(TAG, "Failed to connect to uncrypt socket");
+ return false;
+ }
+
+ try {
+ // Send the BCB commands if it's to setup BCB.
+ if (isSetup) {
+ socket.sendCommand(command);
+ }
+
+ // Read the status from the socket.
+ int status = socket.getPercentageUncrypted();
+
+ // Ack receipt of the status code. uncrypt waits for the ack so
+ // the socket won't be destroyed before we receive the code.
+ socket.sendAck();
+
+ if (status == 100) {
+ Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear")
+ + " bcb successfully finished.");
+ } else {
+ // Error in /system/bin/uncrypt.
+ Slog.e(TAG, "uncrypt failed with status: " + status);
+ return false;
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "IOException when communicating with uncrypt:", e);
+ return false;
+ } finally {
+ socket.close();
+ }
+
+ return true;
+ }
+
+ /**
+ * Provides a wrapper for the low-level details of framing packets sent to the uncrypt
+ * socket.
+ */
+ public static class UncryptSocket {
+ private LocalSocket mLocalSocket;
+ private DataInputStream mInputStream;
+ private DataOutputStream mOutputStream;
+
+ /**
+ * Attempt to connect to the uncrypt service. Connection will be retried for up to
+ * {@link #SOCKET_CONNECTION_MAX_RETRY} times. If the connection is unsuccessful, the
+ * socket will be closed. If the connection is successful, the connection must be closed
+ * by the caller.
+ *
+ * @return true if connection was successful, false if unsuccessful
+ */
+ public boolean connectService() {
+ mLocalSocket = new LocalSocket();
boolean done = false;
// The uncrypt socket will be created by init upon receiving the
// service request. It may not be ready by this point. So we will
// keep retrying until success or reaching timeout.
for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
try {
- socket.connect(new LocalSocketAddress(UNCRYPT_SOCKET,
+ mLocalSocket.connect(new LocalSocketAddress(UNCRYPT_SOCKET,
LocalSocketAddress.Namespace.RESERVED));
done = true;
break;
@@ -249,71 +381,69 @@
}
if (!done) {
Slog.e(TAG, "Timed out connecting to uncrypt socket");
- return null;
- }
- return socket;
- }
-
- private boolean setupOrClearBcb(boolean isSetup, String command) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
-
- final boolean available = checkAndWaitForUncryptService();
- if (!available) {
- Slog.e(TAG, "uncrypt service is unavailable.");
+ close();
return false;
}
- if (isSetup) {
- SystemProperties.set("ctl.start", "setup-bcb");
- } else {
- SystemProperties.set("ctl.start", "clear-bcb");
- }
-
- // Connect to the uncrypt service socket.
- LocalSocket socket = connectService();
- if (socket == null) {
- Slog.e(TAG, "Failed to connect to uncrypt socket");
- return false;
- }
-
- DataInputStream dis = null;
- DataOutputStream dos = null;
try {
- dis = new DataInputStream(socket.getInputStream());
- dos = new DataOutputStream(socket.getOutputStream());
-
- // Send the BCB commands if it's to setup BCB.
- if (isSetup) {
- byte[] cmdUtf8 = command.getBytes("UTF-8");
- dos.writeInt(cmdUtf8.length);
- dos.write(cmdUtf8, 0, cmdUtf8.length);
- }
-
- // Read the status from the socket.
- int status = dis.readInt();
-
- // Ack receipt of the status code. uncrypt waits for the ack so
- // the socket won't be destroyed before we receive the code.
- dos.writeInt(0);
-
- if (status == 100) {
- Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear") +
- " bcb successfully finished.");
- } else {
- // Error in /system/bin/uncrypt.
- Slog.e(TAG, "uncrypt failed with status: " + status);
- return false;
- }
+ mInputStream = new DataInputStream(mLocalSocket.getInputStream());
+ mOutputStream = new DataOutputStream(mLocalSocket.getOutputStream());
} catch (IOException e) {
- Slog.e(TAG, "IOException when communicating with uncrypt:", e);
+ close();
return false;
- } finally {
- IoUtils.closeQuietly(dis);
- IoUtils.closeQuietly(dos);
- IoUtils.closeQuietly(socket);
}
return true;
}
+
+ /**
+ * Sends a command to the uncrypt service.
+ *
+ * @param command command to send to the uncrypt service
+ * @throws IOException if the socket is closed or there was an error writing to the socket
+ */
+ public void sendCommand(String command) throws IOException {
+ if (mLocalSocket.isClosed()) {
+ throw new IOException("socket is closed");
+ }
+
+ byte[] cmdUtf8 = command.getBytes(StandardCharsets.UTF_8);
+ mOutputStream.writeInt(cmdUtf8.length);
+ mOutputStream.write(cmdUtf8, 0, cmdUtf8.length);
+ }
+
+ /**
+ * Reads the status from the uncrypt service which is usually represented as a percentage.
+ * @return an integer representing the percentage completed
+ * @throws IOException if the socket was closed or there was an error reading the socket
+ */
+ public int getPercentageUncrypted() throws IOException {
+ if (mLocalSocket.isClosed()) {
+ throw new IOException("socket is closed");
+ }
+
+ return mInputStream.readInt();
+ }
+
+ /**
+ * Sends a confirmation to the uncrypt service.
+ * @throws IOException if the socket was closed or there was an error writing to the socket
+ */
+ public void sendAck() throws IOException {
+ if (mLocalSocket.isClosed()) {
+ throw new IOException("socket is closed");
+ }
+
+ mOutputStream.writeInt(0);
+ }
+
+ /**
+ * Closes the socket and all underlying data streams.
+ */
+ public void close() {
+ IoUtils.closeQuietly(mInputStream);
+ IoUtils.closeQuietly(mOutputStream);
+ IoUtils.closeQuietly(mLocalSocket);
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 11f09d0..a0b878c 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -92,12 +92,13 @@
// Refer to WindowManagerService#applyImeVisibility(token, false).
// If IMMS's imeTarget is child of DisplayContent's imeTarget and child window
// is above the parent, we will consider it as the same target for now.
+ // Also, if imeTarget is closing, it would be considered as outdated target.
// TODO(b/139861270): Remove the child & sublayer check once IMMS is aware of
// actual IME target.
- return mImeTargetFromIme == mDisplayContent.mInputMethodTarget
- || (mDisplayContent.mInputMethodTarget.getParentWindow() == mImeTargetFromIme
- && mDisplayContent.mInputMethodTarget.mSubLayer
- > mImeTargetFromIme.mSubLayer);
+ final WindowState dcTarget = mDisplayContent.mInputMethodTarget;
+ return (!dcTarget.isClosing() && mImeTargetFromIme == dcTarget)
+ || (dcTarget.getParentWindow() == mImeTargetFromIme
+ && dcTarget.mSubLayer > mImeTargetFromIme.mSubLayer);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2d6d5f4..a42f2e1 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -143,6 +143,7 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.res.Configuration;
+import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.Insets;
@@ -1247,6 +1248,20 @@
LocalServices.addService(WindowManagerInternal.class, new LocalService());
mEmbeddedWindowController = new EmbeddedWindowController(mGlobalLock);
+ setGlobalShadowSettings();
+ }
+
+ private void setGlobalShadowSettings() {
+ final TypedArray a = mContext.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);
+ float lightY = a.getDimension(R.styleable.Lighting_lightY, 0);
+ float lightZ = a.getDimension(R.styleable.Lighting_lightZ, 0);
+ float lightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0);
+ float ambientShadowAlpha = a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0);
+ float spotShadowAlpha = a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0);
+ float[] ambientColor = {0.f, 0.f, 0.f, ambientShadowAlpha};
+ float[] spotColor = {0.f, 0.f, 0.f, spotShadowAlpha};
+ SurfaceControl.setGlobalShadowSettings(ambientColor, spotColor, lightY, lightZ,
+ lightRadius);
}
/**
diff --git a/services/coverage/Android.bp b/services/coverage/Android.bp
index 16c9c1b..e4f5464 100644
--- a/services/coverage/Android.bp
+++ b/services/coverage/Android.bp
@@ -1,5 +1,12 @@
+filegroup {
+ name: "services.coverage-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
java_library_static {
name: "services.coverage",
- srcs: ["java/**/*.java"],
+ srcs: [":services.coverage-sources"],
libs: ["jacocoagent"],
}
diff --git a/services/devicepolicy/Android.bp b/services/devicepolicy/Android.bp
index bffa44e..380ee94 100644
--- a/services/devicepolicy/Android.bp
+++ b/services/devicepolicy/Android.bp
@@ -1,6 +1,13 @@
+filegroup {
+ name: "services.devicepolicy-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
java_library_static {
name: "services.devicepolicy",
- srcs: ["java/**/*.java"],
+ srcs: [":services.devicepolicy-sources"],
libs: [
"services.core",
@@ -15,4 +22,4 @@
platform_compat_config {
name: "services-devicepolicy-platform-compat-config",
src: ":services.devicepolicy",
-}
\ No newline at end of file
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index f1ed1d9..39d840f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -281,7 +281,8 @@
"com.android.server.DeviceIdleController";
private static final String BLOB_STORE_MANAGER_SERVICE_CLASS =
"com.android.server.blob.BlobStoreManagerService";
-
+ private static final String APP_SEARCH_MANAGER_SERVICE_CLASS =
+ "com.android.server.appsearch.AppSearchManagerService";
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
private static final String UNCRYPT_PACKAGE_FILE = "/cache/recovery/uncrypt_file";
@@ -704,7 +705,7 @@
// Bring up recovery system in case a rescue party needs a reboot
t.traceBegin("StartRecoverySystemService");
- mSystemServiceManager.startService(RecoverySystemService.class);
+ mSystemServiceManager.startService(RecoverySystemService.Lifecycle.class);
t.traceEnd();
// Now that we have the bare essentials of the OS up and running, take
@@ -2023,6 +2024,10 @@
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY);
t.traceEnd();
+ t.traceBegin("AppSearchManagerService");
+ mSystemServiceManager.startService(APP_SEARCH_MANAGER_SERVICE_CLASS);
+ t.traceEnd();
+
// These are needed to propagate to the runnable below.
final NetworkManagementService networkManagementF = networkManagement;
final NetworkStatsService networkStatsF = networkStats;
diff --git a/services/midi/Android.bp b/services/midi/Android.bp
index 3745e89..20e0083 100644
--- a/services/midi/Android.bp
+++ b/services/midi/Android.bp
@@ -1,5 +1,12 @@
+filegroup {
+ name: "services.midi-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
java_library_static {
name: "services.midi",
- srcs: ["java/**/*.java"],
+ srcs: [":services.midi-sources"],
libs: ["services.core"],
}
diff --git a/services/net/Android.bp b/services/net/Android.bp
index c56ecd6..42c69e0 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -1,8 +1,15 @@
+filegroup {
+ name: "services.net-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
java_library_static {
name: "services.net",
srcs: [
":tethering-servicesnet-srcs",
- "java/**/*.java",
+ ":services.net-sources",
],
static_libs: [
"dnsresolver_aidl_interface-V2-java",
@@ -20,6 +27,8 @@
"java/android/net/shared/*.java",
"java/android/net/netlink/*.java",
],
+ path: "java",
+ visibility: ["//packages/modules/NetworkStack"],
}
filegroup {
@@ -35,4 +44,5 @@
"java/android/net/util/NetworkConstants.java",
"java/android/net/util/SharedLog.java"
],
+ visibility: ["//frameworks/base/packages/Tethering"],
}
diff --git a/services/print/Android.bp b/services/print/Android.bp
index 80a8c75..aad24d7 100644
--- a/services/print/Android.bp
+++ b/services/print/Android.bp
@@ -1,5 +1,12 @@
+filegroup {
+ name: "services.print-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
java_library_static {
name: "services.print",
- srcs: ["java/**/*.java"],
+ srcs: [":services.print-sources"],
libs: ["services.core"],
}
diff --git a/services/restrictions/Android.bp b/services/restrictions/Android.bp
index 979e891..805858f 100644
--- a/services/restrictions/Android.bp
+++ b/services/restrictions/Android.bp
@@ -1,5 +1,12 @@
+filegroup {
+ name: "services.restrictions-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
java_library_static {
name: "services.restrictions",
- srcs: ["java/**/*.java"],
+ srcs: [":services.restrictions-sources"],
libs: ["services.core"],
}
diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index 6a90d0b..2510b60 100644
--- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -713,7 +713,7 @@
// Verify has set work source and hasn't unset yet.
verify(mBackupManagerService)
.setWorkSource(
- argThat(workSource -> workSource.get(0) == PACKAGE_1.uid));
+ argThat(workSource -> workSource.getUid(0) == PACKAGE_1.uid));
verify(mBackupManagerService, never()).setWorkSource(null);
});
KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
diff --git a/services/systemcaptions/Android.bp b/services/systemcaptions/Android.bp
index 4e190b6..1ce3e66 100644
--- a/services/systemcaptions/Android.bp
+++ b/services/systemcaptions/Android.bp
@@ -1,5 +1,12 @@
+filegroup {
+ name: "services.systemcaptions-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
java_library_static {
name: "services.systemcaptions",
- srcs: ["java/**/*.java"],
+ srcs: [":services.systemcaptions-sources"],
libs: ["services.core"],
}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 30ccb71..52fb69e 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -8,6 +8,7 @@
// Include all test java files.
srcs: [
"src/**/*.java",
+ "src/**/*.kt",
"aidl/com/android/servicestests/aidl/INetworkStateObserver.aidl",
"aidl/com/android/servicestests/aidl/ICmdReceiverService.aidl",
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
new file mode 100644
index 0000000..233e16c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.om
+
+import android.content.om.OverlayInfo
+import android.content.om.OverlayableInfo
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageInfo
+import android.os.Process
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.ExpectedException
+
+class OverlayActorEnforcerTests {
+ companion object {
+ private const val NAMESPACE = "testnamespace"
+ private const val ACTOR_NAME = "testactor"
+ private const val ACTOR_PKG_NAME = "com.test.actor.one"
+ private const val OVERLAYABLE_NAME = "TestOverlayable"
+ private const val UID = 3536
+ private const val USER_ID = 55
+ }
+
+ @get:Rule
+ val expectedException = ExpectedException.none()!!
+
+ @Test
+ fun isRoot() {
+ verify(callingUid = Process.ROOT_UID)
+ }
+
+ @Test(expected = SecurityException::class)
+ fun isShell() {
+ verify(callingUid = Process.SHELL_UID)
+ }
+
+ @Test
+ fun isSystem() {
+ verify(callingUid = Process.SYSTEM_UID)
+ }
+
+ @Test(expected = SecurityException::class)
+ fun noOverlayable_noTarget() {
+ verify(targetOverlayableName = null)
+ }
+
+ @Test
+ fun noOverlayable_noTarget_withPermission() {
+ verify(targetOverlayableName = null, hasPermission = true)
+ }
+
+ @Test(expected = SecurityException::class)
+ fun noOverlayable_withTarget() {
+ verify(targetOverlayableName = OVERLAYABLE_NAME)
+ }
+
+ @Test(expected = SecurityException::class)
+ fun withOverlayable_noTarget() {
+ verify(
+ targetOverlayableName = null,
+ overlayableInfo = OverlayableInfo(OVERLAYABLE_NAME, null)
+ )
+ }
+
+ @Test(expected = SecurityException::class)
+ fun withOverlayable_noActor() {
+ verify(
+ overlayableInfo = OverlayableInfo(OVERLAYABLE_NAME, null)
+ )
+ }
+
+ @Test
+ fun withOverlayable_noActor_withPermission() {
+ verify(
+ hasPermission = true,
+ overlayableInfo = OverlayableInfo(OVERLAYABLE_NAME, null)
+ )
+ }
+
+ @Test(expected = SecurityException::class)
+ fun withOverlayable_withActor_notActor() {
+ verify(
+ isActor = false,
+ overlayableInfo = OverlayableInfo(OVERLAYABLE_NAME,
+ "overlay://$NAMESPACE/$ACTOR_NAME")
+ )
+ }
+
+ @Test(expected = SecurityException::class)
+ fun withOverlayable_withActor_isActor_notPreInstalled() {
+ verify(
+ isActor = true,
+ isPreInstalled = false,
+ overlayableInfo = OverlayableInfo(OVERLAYABLE_NAME,
+ "overlay://$NAMESPACE/$ACTOR_NAME")
+ )
+ }
+
+ @Test
+ fun withOverlayable_withActor_isActor_isPreInstalled() {
+ verify(
+ isActor = true,
+ isPreInstalled = true,
+ overlayableInfo = OverlayableInfo(OVERLAYABLE_NAME,
+ "overlay://$NAMESPACE/$ACTOR_NAME")
+ )
+ }
+
+ @Test(expected = SecurityException::class)
+ fun withOverlayable_invalidActor() {
+ verify(
+ isActor = true,
+ isPreInstalled = true,
+ overlayableInfo = OverlayableInfo(OVERLAYABLE_NAME, "notValidActor")
+ )
+ }
+
+ private fun verify(
+ isActor: Boolean = false,
+ isPreInstalled: Boolean = false,
+ hasPermission: Boolean = false,
+ overlayableInfo: OverlayableInfo? = null,
+ callingUid: Int = UID,
+ targetOverlayableName: String? = OVERLAYABLE_NAME
+ ) {
+ val callback = MockCallback(
+ isActor = isActor,
+ isPreInstalled = isPreInstalled,
+ hasPermission = hasPermission,
+ overlayableInfo = overlayableInfo
+ )
+
+ val overlayInfo = overlayInfo(targetOverlayableName)
+ OverlayActorEnforcer(callback)
+ .enforceActor(overlayInfo, "test", callingUid, USER_ID)
+ }
+
+ private fun overlayInfo(targetOverlayableName: String?) = OverlayInfo("com.test.overlay",
+ "com.test.target", targetOverlayableName, null, "/path", OverlayInfo.STATE_UNKNOWN, 0,
+ 0, false)
+
+ private class MockCallback(
+ private val isActor: Boolean = false,
+ private val isPreInstalled: Boolean = false,
+ private val hasPermission: Boolean = false,
+ private val overlayableInfo: OverlayableInfo? = null,
+ private vararg val packageNames: String = arrayOf("com.test.actor.one")
+ ) : OverlayActorEnforcer.VerifyCallback {
+
+ override fun getNamedActors() = if (isActor) {
+ mapOf(NAMESPACE to mapOf(ACTOR_NAME to ACTOR_PKG_NAME))
+ } else {
+ emptyMap()
+ }
+
+ override fun getOverlayableForTarget(
+ packageName: String,
+ targetOverlayableName: String?,
+ userId: Int
+ ) = overlayableInfo
+
+ override fun getPackagesForUid(uid: Int) = when (uid) {
+ UID -> packageNames
+ else -> null
+ }
+
+ override fun getPackageInfo(packageName: String, userId: Int) = PackageInfo().apply {
+ applicationInfo = ApplicationInfo().apply {
+ flags = if (isPreInstalled) ApplicationInfo.FLAG_SYSTEM else 0
+ }
+ }
+
+ override fun doesTargetDefineOverlayable(targetPackageName: String?, userId: Int): Boolean {
+ return overlayableInfo != null
+ }
+
+ override fun enforcePermission(permission: String?, message: String?) {
+ if (!hasPermission) {
+ throw SecurityException()
+ }
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
new file mode 100644
index 0000000..1f312bf
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.recoverysystem;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.IPowerManager;
+import android.os.IRecoverySystemProgressListener;
+import android.os.Looper;
+import android.os.PowerManager;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.FileWriter;
+
+/**
+ * atest FrameworksServicesTests:RecoverySystemServiceTest
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RecoverySystemServiceTest {
+ private RecoverySystemService mRecoverySystemService;
+ private RecoverySystemServiceTestable.FakeSystemProperties mSystemProperties;
+ private RecoverySystemService.UncryptSocket mUncryptSocket;
+ private Context mContext;
+ private IPowerManager mIPowerManager;
+ private FileWriter mUncryptUpdateFileWriter;
+
+ @Before
+ public void setup() {
+ mContext = mock(Context.class);
+ mSystemProperties = new RecoverySystemServiceTestable.FakeSystemProperties();
+ mUncryptSocket = mock(RecoverySystemService.UncryptSocket.class);
+ mUncryptUpdateFileWriter = mock(FileWriter.class);
+
+ Looper looper = InstrumentationRegistry.getContext().getMainLooper();
+ mIPowerManager = mock(IPowerManager.class);
+ PowerManager powerManager = new PowerManager(mock(Context.class), mIPowerManager,
+ new Handler(looper));
+
+ mRecoverySystemService = new RecoverySystemServiceTestable(mContext, mSystemProperties,
+ powerManager, mUncryptUpdateFileWriter, mUncryptSocket);
+ }
+
+ @Test
+ public void clearBcb_success() throws Exception {
+ doNothing().when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.RECOVERY), any());
+ when(mUncryptSocket.getPercentageUncrypted()).thenReturn(100);
+
+ assertThat(mRecoverySystemService.clearBcb(), is(true));
+
+ assertThat(mSystemProperties.getCtlStart(), is("clear-bcb"));
+ verify(mUncryptSocket).sendAck();
+ verify(mUncryptSocket).close();
+ }
+
+ @Test
+ public void clearBcb_uncrypt_failure() throws Exception {
+ doNothing().when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.RECOVERY), any());
+ when(mUncryptSocket.getPercentageUncrypted()).thenReturn(0);
+
+ assertThat(mRecoverySystemService.clearBcb(), is(false));
+
+ assertThat(mSystemProperties.getCtlStart(), is("clear-bcb"));
+ verify(mUncryptSocket).sendAck();
+ verify(mUncryptSocket).close();
+ }
+
+ @Test(expected = SecurityException.class)
+ public void clearBcb_noPerm() {
+ doThrow(SecurityException.class).when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.RECOVERY), any());
+ mRecoverySystemService.clearBcb();
+ }
+
+ @Test
+ public void setupBcb_success() throws Exception {
+ doNothing().when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.RECOVERY), any());
+ when(mUncryptSocket.getPercentageUncrypted()).thenReturn(100);
+
+ assertThat(mRecoverySystemService.setupBcb("foo"), is(true));
+
+ assertThat(mSystemProperties.getCtlStart(), is("setup-bcb"));
+ verify(mUncryptSocket).sendCommand("foo");
+ verify(mUncryptSocket).sendAck();
+ verify(mUncryptSocket).close();
+ }
+
+ @Test
+ public void setupBcb_uncrypt_failure() throws Exception {
+ doNothing().when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.RECOVERY), any());
+ when(mUncryptSocket.getPercentageUncrypted()).thenReturn(0);
+
+ assertThat(mRecoverySystemService.setupBcb("foo"), is(false));
+
+ assertThat(mSystemProperties.getCtlStart(), is("setup-bcb"));
+ verify(mUncryptSocket).sendCommand("foo");
+ verify(mUncryptSocket).sendAck();
+ verify(mUncryptSocket).close();
+ }
+
+ @Test(expected = SecurityException.class)
+ public void setupBcb_noPerm() {
+ doThrow(SecurityException.class).when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.RECOVERY), any());
+ mRecoverySystemService.setupBcb("foo");
+ }
+
+ @Test
+ public void rebootRecoveryWithCommand_success() throws Exception {
+ doNothing().when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.RECOVERY), any());
+ when(mUncryptSocket.getPercentageUncrypted()).thenReturn(100);
+
+ mRecoverySystemService.rebootRecoveryWithCommand("foo");
+
+ assertThat(mSystemProperties.getCtlStart(), is("setup-bcb"));
+ verify(mUncryptSocket).sendCommand("foo");
+ verify(mUncryptSocket).sendAck();
+ verify(mUncryptSocket).close();
+ verify(mIPowerManager).reboot(anyBoolean(), eq("recovery"), anyBoolean());
+ }
+
+ @Test
+ public void rebootRecoveryWithCommand_failure() throws Exception {
+ doNothing().when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.RECOVERY), any());
+ when(mUncryptSocket.getPercentageUncrypted()).thenReturn(0);
+
+ mRecoverySystemService.rebootRecoveryWithCommand("foo");
+
+ assertThat(mSystemProperties.getCtlStart(), is("setup-bcb"));
+ verify(mUncryptSocket).sendCommand("foo");
+ verify(mUncryptSocket).sendAck();
+ verify(mUncryptSocket).close();
+ verifyNoMoreInteractions(mIPowerManager);
+ }
+
+ @Test(expected = SecurityException.class)
+ public void rebootRecoveryWithCommand_noPerm() {
+ doThrow(SecurityException.class).when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.RECOVERY), any());
+ mRecoverySystemService.rebootRecoveryWithCommand("foo");
+ }
+
+ @Test
+ public void uncrypt_success() throws Exception {
+ doNothing().when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.RECOVERY), any());
+ when(mUncryptSocket.getPercentageUncrypted()).thenReturn(0, 5, 25, 50, 90, 99, 100);
+
+ IRecoverySystemProgressListener listener = mock(IRecoverySystemProgressListener.class);
+ assertThat(mRecoverySystemService.uncrypt("foo.zip", listener), is(true));
+
+ assertThat(mSystemProperties.getCtlStart(), is("uncrypt"));
+ verify(mUncryptSocket, times(7)).getPercentageUncrypted();
+ verify(mUncryptSocket).sendAck();
+ verify(mUncryptSocket).close();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
new file mode 100644
index 0000000..a986b71
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.recoverysystem;
+
+import android.content.Context;
+import android.os.PowerManager;
+
+import java.io.FileWriter;
+
+public class RecoverySystemServiceTestable extends RecoverySystemService {
+ private static class MockInjector extends RecoverySystemService.Injector {
+ private final FakeSystemProperties mSystemProperties;
+ private final PowerManager mPowerManager;
+ private final FileWriter mUncryptPackageFileWriter;
+ private final UncryptSocket mUncryptSocket;
+
+ MockInjector(Context context, FakeSystemProperties systemProperties,
+ PowerManager powerManager, FileWriter uncryptPackageFileWriter,
+ UncryptSocket uncryptSocket) {
+ super(context);
+ mSystemProperties = systemProperties;
+ mPowerManager = powerManager;
+ mUncryptPackageFileWriter = uncryptPackageFileWriter;
+ mUncryptSocket = uncryptSocket;
+ }
+
+ @Override
+ public PowerManager getPowerManager() {
+ return mPowerManager;
+ }
+
+ @Override
+ public String systemPropertiesGet(String key) {
+ return mSystemProperties.get(key);
+ }
+
+ @Override
+ public void systemPropertiesSet(String key, String value) {
+ mSystemProperties.set(key, value);
+ }
+
+ @Override
+ public boolean uncryptPackageFileDelete() {
+ return true;
+ }
+
+ @Override
+ public String getUncryptPackageFileName() {
+ return "mock-file.txt";
+ }
+
+ @Override
+ public FileWriter getUncryptPackageFileWriter() {
+ return mUncryptPackageFileWriter;
+ }
+
+ @Override
+ public UncryptSocket connectService() {
+ return mUncryptSocket;
+ }
+
+ @Override
+ public void threadSleep(long millis) {
+ }
+ }
+
+ RecoverySystemServiceTestable(Context context, FakeSystemProperties systemProperties,
+ PowerManager powerManager, FileWriter uncryptPackageFileWriter,
+ UncryptSocket uncryptSocket) {
+ super(new MockInjector(context, systemProperties, powerManager, uncryptPackageFileWriter,
+ uncryptSocket));
+ }
+
+ public static class FakeSystemProperties {
+ private String mCtlStart = null;
+
+ public String get(String key) {
+ if (RecoverySystemService.INIT_SERVICE_UNCRYPT.equals(key)
+ || RecoverySystemService.INIT_SERVICE_SETUP_BCB.equals(key)
+ || RecoverySystemService.INIT_SERVICE_CLEAR_BCB.equals(key)) {
+ return null;
+ } else {
+ throw new IllegalArgumentException("unexpected test key: " + key);
+ }
+ }
+
+ public void set(String key, String value) {
+ if ("ctl.start".equals(key)) {
+ mCtlStart = value;
+ } else {
+ throw new IllegalArgumentException("unexpected test key: " + key);
+ }
+ }
+
+ public String getCtlStart() {
+ return mCtlStart;
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigNamedActorTest.kt b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigNamedActorTest.kt
new file mode 100644
index 0000000..b7199d4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigNamedActorTest.kt
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.systemconfig
+
+import android.content.Context
+import androidx.test.InstrumentationRegistry
+import com.android.server.SystemConfig
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.ExpectedException
+import org.junit.rules.TemporaryFolder
+
+class SystemConfigNamedActorTest {
+
+ companion object {
+ private const val NAMESPACE_TEST = "someTestNamespace"
+ private const val NAMESPACE_ANDROID = "android"
+ private const val ACTOR_ONE = "iconShaper"
+ private const val ACTOR_TWO = "colorChanger"
+ private const val PACKAGE_ONE = "com.test.actor.one"
+ private const val PACKAGE_TWO = "com.test.actor.two"
+ }
+
+ private val context: Context = InstrumentationRegistry.getContext()
+
+ @get:Rule
+ val tempFolder = TemporaryFolder(context.filesDir)
+
+ @get:Rule
+ val expected = ExpectedException.none()
+
+ private var uniqueCounter = 0
+
+ @Test
+ fun twoUnique() {
+ """
+ <config>
+ <named-actor
+ namespace="$NAMESPACE_TEST"
+ name="$ACTOR_ONE"
+ package="$PACKAGE_ONE"
+ />
+ <named-actor
+ namespace="$NAMESPACE_TEST"
+ name="$ACTOR_TWO"
+ package="$PACKAGE_TWO"
+ />
+ </config>
+ """.write()
+
+ assertPermissions().containsExactlyEntriesIn(
+ mapOf(
+ NAMESPACE_TEST to mapOf(
+ ACTOR_ONE to PACKAGE_ONE,
+ ACTOR_TWO to PACKAGE_TWO
+ )
+ )
+ )
+ }
+
+ @Test
+ fun twoSamePackage() {
+ """
+ <config>
+ <named-actor
+ namespace="$NAMESPACE_TEST"
+ name="$ACTOR_ONE"
+ package="$PACKAGE_ONE"
+ />
+ <named-actor
+ namespace="$NAMESPACE_TEST"
+ name="$ACTOR_TWO"
+ package="$PACKAGE_ONE"
+ />
+ </config>
+ """.write()
+
+ assertPermissions().containsExactlyEntriesIn(
+ mapOf(
+ NAMESPACE_TEST to mapOf(
+ ACTOR_ONE to PACKAGE_ONE,
+ ACTOR_TWO to PACKAGE_ONE
+ )
+ )
+ )
+ }
+
+ @Test
+ fun missingNamespace() {
+ """
+ <config>
+ <named-actor
+ name="$ACTOR_ONE"
+ package="$PACKAGE_ONE"
+ />
+ <named-actor
+ namespace="$NAMESPACE_TEST"
+ name="$ACTOR_TWO"
+ package="$PACKAGE_TWO"
+ />
+ </config>
+ """.write()
+
+ assertPermissions().containsExactlyEntriesIn(
+ mapOf(
+ NAMESPACE_TEST to mapOf(
+ ACTOR_TWO to PACKAGE_TWO
+ )
+ )
+ )
+ }
+
+ @Test
+ fun missingName() {
+ """
+ <config>
+ <named-actor
+ namespace="$NAMESPACE_TEST"
+ package="$PACKAGE_ONE"
+ />
+ <named-actor
+ namespace="$NAMESPACE_TEST"
+ name="$ACTOR_TWO"
+ package="$PACKAGE_TWO"
+ />
+ </config>
+ """.write()
+
+ assertPermissions().containsExactlyEntriesIn(
+ mapOf(
+ NAMESPACE_TEST to mapOf(
+ ACTOR_TWO to PACKAGE_TWO
+ )
+ )
+ )
+ }
+
+ @Test
+ fun missingPackage() {
+ """
+ <config>
+ <named-actor
+ namespace="$NAMESPACE_TEST"
+ name="$ACTOR_ONE"
+ />
+ <named-actor
+ namespace="$NAMESPACE_TEST"
+ name="$ACTOR_TWO"
+ package="$PACKAGE_TWO"
+ />
+ </config>
+ """.write()
+
+ assertPermissions().containsExactlyEntriesIn(
+ mapOf(
+ NAMESPACE_TEST to mapOf(
+ ACTOR_TWO to PACKAGE_TWO
+ )
+ )
+ )
+ }
+
+ @Test
+ fun androidNamespaceThrows() {
+ """
+ <config>
+ <named-actor
+ namespace="$NAMESPACE_TEST"
+ name="$ACTOR_ONE"
+ package="$PACKAGE_ONE"
+ />
+ <named-actor
+ namespace="$NAMESPACE_ANDROID"
+ name="$ACTOR_ONE"
+ package="$PACKAGE_ONE"
+ />
+ </config>
+ """.write()
+
+ expected.expect(IllegalStateException::class.java)
+ expected.expectMessage("Defining $ACTOR_ONE as $PACKAGE_ONE " +
+ "for the android namespace is not allowed")
+
+ assertPermissions()
+ }
+
+ @Test
+ fun duplicateActorNameThrows() {
+ """
+ <config>
+ <named-actor
+ namespace="$NAMESPACE_TEST"
+ name="$ACTOR_ONE"
+ package="$PACKAGE_ONE"
+ />
+ <named-actor
+ namespace="$NAMESPACE_TEST"
+ name="$ACTOR_ONE"
+ package="$PACKAGE_TWO"
+ />
+ </config>
+ """.write()
+
+ expected.expect(IllegalStateException::class.java)
+ expected.expectMessage("Duplicate actor definition for $NAMESPACE_TEST/$ACTOR_ONE;" +
+ " defined as both $PACKAGE_ONE and $PACKAGE_TWO")
+
+ assertPermissions()
+ }
+
+ private fun String.write() = tempFolder.root.resolve("${uniqueCounter++}.xml")
+ .writeText(this.trimIndent())
+
+ private fun assertPermissions() = SystemConfig(false).apply {
+ readPermissions(tempFolder.root, 0)
+ }. let { assertThat(it.namedActors) }
+}
diff --git a/services/tests/servicestests/src/com/android/server/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
similarity index 98%
rename from services/tests/servicestests/src/com/android/server/SystemConfigTest.java
rename to services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index ff03391..fde0ddf 100644
--- a/services/tests/servicestests/src/com/android/server/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.systemconfig;
import static org.junit.Assert.assertEquals;
@@ -25,6 +25,8 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.SystemConfig;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
index e32103f..e6bb244 100644
--- a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
+++ b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
@@ -45,6 +45,7 @@
import java.io.IOException;
import java.util.List;
import java.util.Locale;
+import java.util.Set;
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -93,6 +94,8 @@
for (File f : usageFiles) {
f.delete();
}
+ } else {
+ intervalDir.delete();
}
}
}
@@ -587,6 +590,7 @@
db.readMappingsLocked();
db.init(1);
db.putUsageStats(interval, mIntervalStats);
+ db.writeMappingsLocked();
final String removedPackage = "fake.package.name0";
// invoke handler call directly from test to remove package
@@ -594,19 +598,19 @@
List<IntervalStats> stats = db.queryUsageStats(interval, 0, mEndTime,
mIntervalStatsVerifier);
- for (int i = 0; i < stats.size(); i++) {
- final IntervalStats stat = stats.get(i);
- if (stat.packageStats.containsKey(removedPackage)) {
- fail("Found removed package " + removedPackage + " in package stats.");
+ assertEquals(1, stats.size(),
+ "Only one interval stats object should exist for the given time range.");
+ final IntervalStats stat = stats.get(0);
+ if (stat.packageStats.containsKey(removedPackage)) {
+ fail("Found removed package " + removedPackage + " in package stats.");
+ return;
+ }
+ for (int i = 0; i < stat.events.size(); i++) {
+ final Event event = stat.events.get(i);
+ if (removedPackage.equals(event.mPackage)) {
+ fail("Found an event from removed package " + removedPackage);
return;
}
- for (int j = 0; j < stat.events.size(); j++) {
- final Event event = stat.events.get(j);
- if (removedPackage.equals(event.mPackage)) {
- fail("Found an event from removed package " + removedPackage);
- return;
- }
- }
}
}
@@ -617,4 +621,90 @@
verifyPackageNotRetained(UsageStatsManager.INTERVAL_MONTHLY);
verifyPackageNotRetained(UsageStatsManager.INTERVAL_YEARLY);
}
+
+ private void verifyPackageDataIsRemoved(UsageStatsDatabase db, int interval,
+ String removedPackage) {
+ List<IntervalStats> stats = db.queryUsageStats(interval, 0, mEndTime,
+ mIntervalStatsVerifier);
+ assertEquals(1, stats.size(),
+ "Only one interval stats object should exist for the given time range.");
+ final IntervalStats stat = stats.get(0);
+ if (stat.packageStats.containsKey(removedPackage)) {
+ fail("Found removed package " + removedPackage + " in package stats.");
+ return;
+ }
+ for (int i = 0; i < stat.events.size(); i++) {
+ final Event event = stat.events.get(i);
+ if (removedPackage.equals(event.mPackage)) {
+ fail("Found an event from removed package " + removedPackage);
+ return;
+ }
+ }
+ }
+
+ private void verifyPackageDataIsNotRemoved(UsageStatsDatabase db, int interval,
+ Set<String> installedPackages) {
+ List<IntervalStats> stats = db.queryUsageStats(interval, 0, mEndTime,
+ mIntervalStatsVerifier);
+ assertEquals(1, stats.size(),
+ "Only one interval stats object should exist for the given time range.");
+ final IntervalStats stat = stats.get(0);
+ if (!stat.packageStats.containsAll(installedPackages)) {
+ fail("Could not find some installed packages in package stats.");
+ return;
+ }
+ // attempt to find an event from each installed package
+ for (String installedPackage : installedPackages) {
+ for (int i = 0; i < stat.events.size(); i++) {
+ if (installedPackage.equals(stat.events.get(i).mPackage)) {
+ break;
+ }
+ if (i == stat.events.size() - 1) {
+ fail("Could not find any event for: " + installedPackage);
+ return;
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testPackageDataIsRemoved() throws IOException {
+ UsageStatsDatabase db = new UsageStatsDatabase(mTestDir);
+ db.readMappingsLocked();
+ db.init(1);
+
+ // write stats to disk for each interval
+ db.putUsageStats(UsageStatsManager.INTERVAL_DAILY, mIntervalStats);
+ db.putUsageStats(UsageStatsManager.INTERVAL_WEEKLY, mIntervalStats);
+ db.putUsageStats(UsageStatsManager.INTERVAL_MONTHLY, mIntervalStats);
+ db.putUsageStats(UsageStatsManager.INTERVAL_YEARLY, mIntervalStats);
+ db.writeMappingsLocked();
+
+ final Set<String> installedPackages = mIntervalStats.packageStats.keySet();
+ final String removedPackage = installedPackages.iterator().next();
+ installedPackages.remove(removedPackage);
+
+ // mimic a package uninstall
+ db.onPackageRemoved(removedPackage, System.currentTimeMillis());
+
+ // mimic the idle prune job being triggered
+ db.pruneUninstalledPackagesData();
+
+ // read data from disk into a new db instance
+ UsageStatsDatabase newDB = new UsageStatsDatabase(mTestDir);
+ newDB.readMappingsLocked();
+ newDB.init(mEndTime);
+
+ // query data for each interval and ensure data for package doesn't exist
+ verifyPackageDataIsRemoved(newDB, UsageStatsManager.INTERVAL_DAILY, removedPackage);
+ verifyPackageDataIsRemoved(newDB, UsageStatsManager.INTERVAL_WEEKLY, removedPackage);
+ verifyPackageDataIsRemoved(newDB, UsageStatsManager.INTERVAL_MONTHLY, removedPackage);
+ verifyPackageDataIsRemoved(newDB, UsageStatsManager.INTERVAL_YEARLY, removedPackage);
+
+ // query data for each interval and ensure some data for installed packages exists
+ verifyPackageDataIsNotRemoved(newDB, UsageStatsManager.INTERVAL_DAILY, installedPackages);
+ verifyPackageDataIsNotRemoved(newDB, UsageStatsManager.INTERVAL_WEEKLY, installedPackages);
+ verifyPackageDataIsNotRemoved(newDB, UsageStatsManager.INTERVAL_MONTHLY, installedPackages);
+ verifyPackageDataIsNotRemoved(newDB, UsageStatsManager.INTERVAL_YEARLY, installedPackages);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java
index d1b6f6f..7e31895 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java
@@ -40,6 +40,10 @@
mLockRule.waitForLocked(mSystemServicesTestRule::waitUntilWindowManagerHandlersIdle);
}
+ void cleanupWindowManagerHandlers() {
+ mLockRule.waitForLocked(mSystemServicesTestRule::cleanupWindowManagerHandlers);
+ }
+
boolean waitHandlerIdle(Handler handler) {
return waitHandlerIdle(handler, 0 /* timeout */);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 2c34f33..d3b68e0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -355,6 +355,8 @@
}
wm.mH.removeCallbacksAndMessages(null);
wm.mAnimationHandler.removeCallbacksAndMessages(null);
+ // This is a different handler object than the wm.mAnimationHandler above.
+ AnimationThread.getHandler().removeCallbacksAndMessages(null);
SurfaceAnimationThread.getHandler().removeCallbacksAndMessages(null);
}
@@ -367,6 +369,8 @@
wm.mH.removeMessages(WindowManagerService.H.FORCE_GC);
waitHandlerIdle(wm.mH);
waitHandlerIdle(wm.mAnimationHandler);
+ // This is a different handler object than the wm.mAnimationHandler above.
+ waitHandlerIdle(AnimationThread.getHandler());
waitHandlerIdle(SurfaceAnimationThread.getHandler());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 0da9dc4..7aa5148 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -175,7 +175,7 @@
}
// Cleaned up everything in Handler.
- mSystemServicesTestRule.cleanupWindowManagerHandlers();
+ cleanupWindowManagerHandlers();
} catch (Exception e) {
Log.e(TAG, "Failed to tear down test", e);
throw e;
diff --git a/services/usage/Android.bp b/services/usage/Android.bp
index 1064b6e..156bf33 100644
--- a/services/usage/Android.bp
+++ b/services/usage/Android.bp
@@ -1,5 +1,12 @@
+filegroup {
+ name: "services.usage-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
java_library_static {
name: "services.usage",
- srcs: ["java/**/*.java"],
+ srcs: [":services.usage-sources"],
libs: ["services.core"],
}
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index 46b261b..8fb283a 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -448,8 +448,11 @@
/**
* Parses all of the tokens to strings in the obfuscated usage stats data. This includes
* deobfuscating each of the package tokens and chooser actions and categories.
+ *
+ * @return {@code true} if any stats were omitted while deobfuscating, {@code false} otherwise.
*/
- private void deobfuscateUsageStats(PackagesTokenData packagesTokenData) {
+ private boolean deobfuscateUsageStats(PackagesTokenData packagesTokenData) {
+ boolean dataOmitted = false;
final int usageStatsSize = packageStatsObfuscated.size();
for (int statsIndex = 0; statsIndex < usageStatsSize; statsIndex++) {
final int packageToken = packageStatsObfuscated.keyAt(statsIndex);
@@ -457,6 +460,7 @@
usageStats.mPackageName = packagesTokenData.getPackageString(packageToken);
if (usageStats.mPackageName == null) {
Slog.e(TAG, "Unable to parse usage stats package " + packageToken);
+ dataOmitted = true;
continue;
}
@@ -489,14 +493,18 @@
}
packageStats.put(usageStats.mPackageName, usageStats);
}
+ return dataOmitted;
}
/**
* Parses all of the tokens to strings in the obfuscated events data. This includes
* deobfuscating the package token, along with any class, task root package/class tokens, and
* shortcut or notification channel tokens.
+ *
+ * @return {@code true} if any events were omitted while deobfuscating, {@code false} otherwise.
*/
- private void deobfuscateEvents(PackagesTokenData packagesTokenData) {
+ private boolean deobfuscateEvents(PackagesTokenData packagesTokenData) {
+ boolean dataOmitted = false;
for (int i = this.events.size() - 1; i >= 0; i--) {
final Event event = this.events.get(i);
final int packageToken = event.mPackageToken;
@@ -504,6 +512,7 @@
if (event.mPackage == null) {
Slog.e(TAG, "Unable to parse event package " + packageToken);
this.events.remove(i);
+ dataOmitted = true;
continue;
}
@@ -543,6 +552,7 @@
Slog.e(TAG, "Unable to parse shortcut " + event.mShortcutIdToken
+ " for package " + packageToken);
this.events.remove(i);
+ dataOmitted = true;
continue;
}
break;
@@ -554,21 +564,25 @@
+ event.mNotificationChannelIdToken + " for package "
+ packageToken);
this.events.remove(i);
+ dataOmitted = true;
continue;
}
break;
}
}
+ return dataOmitted;
}
/**
* Parses the obfuscated tokenized data held in this interval stats object.
*
+ * @return {@code true} if any data was omitted while deobfuscating, {@code false} otherwise.
* @hide
*/
- public void deobfuscateData(PackagesTokenData packagesTokenData) {
- deobfuscateUsageStats(packagesTokenData);
- deobfuscateEvents(packagesTokenData);
+ public boolean deobfuscateData(PackagesTokenData packagesTokenData) {
+ final boolean statsOmitted = deobfuscateUsageStats(packagesTokenData);
+ final boolean eventsOmitted = deobfuscateEvents(packagesTokenData);
+ return statsOmitted || eventsOmitted;
}
/**
diff --git a/services/usage/java/com/android/server/usage/PackagesTokenData.java b/services/usage/java/com/android/server/usage/PackagesTokenData.java
index 4bf08a4..f19abbb 100644
--- a/services/usage/java/com/android/server/usage/PackagesTokenData.java
+++ b/services/usage/java/com/android/server/usage/PackagesTokenData.java
@@ -162,15 +162,18 @@
*
* @param packageName the package to be removed
* @param timeRemoved the time stamp of when the package was removed
+ * @return the token mapped to the package removed or {@code PackagesTokenData.UNASSIGNED_TOKEN}
+ * if not mapped
*/
- public void removePackage(String packageName, long timeRemoved) {
+ public int removePackage(String packageName, long timeRemoved) {
removedPackagesMap.put(packageName, timeRemoved);
if (!packagesToTokensMap.containsKey(packageName)) {
- return;
+ return UNASSIGNED_TOKEN;
}
final int packageToken = packagesToTokensMap.get(packageName).get(packageName);
packagesToTokensMap.remove(packageName);
tokensToPackagesMap.delete(packageToken);
+ return packageToken;
}
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index 27d7360..ce29527 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -52,6 +52,7 @@
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
/**
@@ -122,6 +123,7 @@
private int mCurrentVersion;
private boolean mFirstUpdate;
private boolean mNewUpdate;
+ private boolean mUpgradePerformed;
// The obfuscated packages to tokens mappings file
private final File mPackageMappingsFile;
@@ -325,6 +327,13 @@
return mNewUpdate;
}
+ /**
+ * Was an upgrade performed when this database was initialized?
+ */
+ boolean wasUpgradePerformed() {
+ return mUpgradePerformed;
+ }
+
private void checkVersionAndBuildLocked() {
int version;
String buildFingerprint;
@@ -397,6 +406,8 @@
if (mUpdateBreadcrumb.exists()) {
// Files should be up to date with current version. Clear the version update breadcrumb
mUpdateBreadcrumb.delete();
+ // update mUpgradePerformed after breadcrumb is deleted to indicate a successful upgrade
+ mUpgradePerformed = true;
}
if (mBackupsDir.exists() && !KEEP_BACKUP_DIR) {
@@ -545,12 +556,119 @@
}
}
- void onPackageRemoved(String packageName, long timeRemoved) {
+ /**
+ * Returns the token mapped to the package removed or {@code PackagesTokenData.UNASSIGNED_TOKEN}
+ * if not mapped.
+ */
+ int onPackageRemoved(String packageName, long timeRemoved) {
synchronized (mLock) {
- mPackagesTokenData.removePackage(packageName, timeRemoved);
+ return mPackagesTokenData.removePackage(packageName, timeRemoved);
}
}
+ /**
+ * Reads all the usage stats data on disk and rewrites it with any data related to uninstalled
+ * packages omitted.
+ */
+ boolean pruneUninstalledPackagesData() {
+ synchronized (mLock) {
+ for (int i = 0; i < mIntervalDirs.length; i++) {
+ final File[] files = mIntervalDirs[i].listFiles();
+ if (files == null) {
+ continue;
+ }
+ for (int j = 0; j < files.length; j++) {
+ try {
+ final IntervalStats stats = new IntervalStats();
+ final AtomicFile atomicFile = new AtomicFile(files[j]);
+ if (!readLocked(atomicFile, stats, mCurrentVersion, mPackagesTokenData)) {
+ continue; // no data was omitted when read so no need to rewrite
+ }
+ // Any data related to packages that have been removed would have failed
+ // the deobfuscation step on read so the IntervalStats object here only
+ // contains data for packages that are currently installed - all we need
+ // to do here is write the data back to disk.
+ writeLocked(atomicFile, stats, mCurrentVersion, mPackagesTokenData);
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to prune data from: " + files[j].toString());
+ return false;
+ }
+ }
+ }
+ try {
+ writeMappingsLocked();
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to write package mappings after pruning data.");
+ return false;
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Iterates through all the files on disk and prunes any data that belongs to packages that have
+ * been uninstalled (packages that are not in the given list).
+ * Note: this should only be called once, when there has been a database upgrade.
+ *
+ * @param installedPackages map of installed packages (package_name:package_install_time)
+ */
+ void prunePackagesDataOnUpgrade(HashMap<String, Long> installedPackages) {
+ if (installedPackages == null || installedPackages.isEmpty()) {
+ return;
+ }
+ synchronized (mLock) {
+ for (int i = 0; i < mIntervalDirs.length; i++) {
+ final File[] files = mIntervalDirs[i].listFiles();
+ if (files == null) {
+ continue;
+ }
+ for (int j = 0; j < files.length; j++) {
+ try {
+ final IntervalStats stats = new IntervalStats();
+ final AtomicFile atomicFile = new AtomicFile(files[j]);
+ readLocked(atomicFile, stats, mCurrentVersion, mPackagesTokenData);
+ if (!pruneStats(installedPackages, stats)) {
+ continue; // no stats were pruned so no need to rewrite
+ }
+ writeLocked(atomicFile, stats, mCurrentVersion, mPackagesTokenData);
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to prune data from: " + files[j].toString());
+ }
+ }
+ }
+ }
+ }
+
+ private boolean pruneStats(HashMap<String, Long> installedPackages, IntervalStats stats) {
+ boolean dataPruned = false;
+
+ // prune old package usage stats
+ for (int i = stats.packageStats.size() - 1; i >= 0; i--) {
+ final UsageStats usageStats = stats.packageStats.valueAt(i);
+ final Long timeInstalled = installedPackages.get(usageStats.mPackageName);
+ if (timeInstalled == null || timeInstalled > usageStats.mEndTimeStamp) {
+ stats.packageStats.removeAt(i);
+ dataPruned = true;
+ }
+ }
+ if (dataPruned) {
+ // ensure old stats don't linger around during the obfuscation step on write
+ stats.packageStatsObfuscated.clear();
+ }
+
+ // prune old events
+ for (int i = stats.events.size() - 1; i >= 0; i--) {
+ final UsageEvents.Event event = stats.events.get(i);
+ final Long timeInstalled = installedPackages.get(event.mPackage);
+ if (timeInstalled == null || timeInstalled > event.mTimeStamp) {
+ stats.events.remove(i);
+ dataPruned = true;
+ }
+ }
+
+ return dataPruned;
+ }
+
public void onTimeChanged(long timeDiffMillis) {
synchronized (mLock) {
StringBuilder logBuilder = new StringBuilder();
@@ -645,7 +763,6 @@
}
// filter out events
- final int eventsSize = stats.events.size();
for (int i = stats.events.size() - 1; i >= 0; i--) {
final UsageEvents.Event event = stats.events.get(i);
final Long timeRemoved = removedPackagesMap.get(event.mPackage);
@@ -942,13 +1059,17 @@
readLocked(file, statsOut, mCurrentVersion, mPackagesTokenData);
}
- private static void readLocked(AtomicFile file, IntervalStats statsOut, int version,
+ /**
+ * Returns {@code true} if any stats were omitted while reading, {@code false} otherwise.
+ */
+ private static boolean readLocked(AtomicFile file, IntervalStats statsOut, int version,
PackagesTokenData packagesTokenData) throws IOException {
+ boolean dataOmitted = false;
try {
FileInputStream in = file.openRead();
try {
statsOut.beginTime = parseBeginTime(file);
- readLocked(in, statsOut, version, packagesTokenData);
+ dataOmitted = readLocked(in, statsOut, version, packagesTokenData);
statsOut.lastTimeSaved = file.getLastModifiedTime();
} finally {
try {
@@ -961,10 +1082,15 @@
Slog.e(TAG, "UsageStatsDatabase", e);
throw e;
}
+ return dataOmitted;
}
- private static void readLocked(InputStream in, IntervalStats statsOut, int version,
+ /**
+ * Returns {@code true} if any stats were omitted while reading, {@code false} otherwise.
+ */
+ private static boolean readLocked(InputStream in, IntervalStats statsOut, int version,
PackagesTokenData packagesTokenData) throws IOException {
+ boolean dataOmitted = false;
switch (version) {
case 1:
case 2:
@@ -989,14 +1115,14 @@
} catch (IOException e) {
Slog.e(TAG, "Unable to read interval stats from proto.", e);
}
- statsOut.deobfuscateData(packagesTokenData);
+ dataOmitted = statsOut.deobfuscateData(packagesTokenData);
break;
default:
throw new RuntimeException(
"Unhandled UsageStatsDatabase version: " + Integer.toString(version)
+ " on read.");
}
-
+ return dataOmitted;
}
/**
diff --git a/services/usage/java/com/android/server/usage/UsageStatsIdleService.java b/services/usage/java/com/android/server/usage/UsageStatsIdleService.java
new file mode 100644
index 0000000..8677779
--- /dev/null
+++ b/services/usage/java/com/android/server/usage/UsageStatsIdleService.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usage;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.app.usage.UsageStatsManagerInternal;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.PersistableBundle;
+
+import com.android.server.LocalServices;
+
+/**
+ * JobService used to do any work for UsageStats while the device is idle.
+ */
+public class UsageStatsIdleService extends JobService {
+
+ /**
+ * Base job ID for the pruning job - must be unique within the system server uid.
+ */
+ private static final int PRUNE_JOB_ID = 546357475;
+
+ private static final String USER_ID_KEY = "user_id";
+ private static final String REMOVED_TOKENS_KEY = "removed_tokens";
+
+ static void scheduleJob(Context context, int userId, int token) {
+ final int userJobId = PRUNE_JOB_ID + userId; // unique job id per user
+ final ComponentName component = new ComponentName(context.getPackageName(),
+ UsageStatsIdleService.class.getName());
+ final PersistableBundle bundle = new PersistableBundle();
+ bundle.putInt(USER_ID_KEY, userId);
+ bundle.putIntArray(REMOVED_TOKENS_KEY,
+ getOrCreateRemovedTokens(fetchRemovedTokens(context, userId), token));
+ final JobInfo pruneJob = new JobInfo.Builder(userJobId, component)
+ .setRequiresDeviceIdle(true)
+ .setExtras(bundle)
+ .setPersisted(true)
+ .build();
+
+ final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
+ jobScheduler.schedule(pruneJob);
+ }
+
+ static void cancelJob(Context context, int userId) {
+ final int userJobId = PRUNE_JOB_ID + userId; // unique job id per user
+ final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
+ jobScheduler.cancel(userJobId);
+ }
+
+ /**
+ * Fetches an array of removed tokens from previous prune jobs, if any.
+ */
+ static int[] fetchRemovedTokens(Context context, int userId) {
+ final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
+ final int userJobId = PRUNE_JOB_ID + userId; // unique job id per user
+ final JobInfo pendingJob = jobScheduler.getPendingJob(userJobId);
+ if (pendingJob != null) {
+ final PersistableBundle bundle = pendingJob.getExtras();
+ return bundle.getIntArray(REMOVED_TOKENS_KEY);
+ }
+ return null;
+ }
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ final PersistableBundle bundle = params.getExtras();
+ final int userId = bundle.getInt(USER_ID_KEY, -1);
+ if (userId == -1) {
+ return false;
+ }
+
+ AsyncTask.execute(() -> {
+ final UsageStatsManagerInternal usageStatsManagerInternal = LocalServices.getService(
+ UsageStatsManagerInternal.class);
+ final boolean pruned = usageStatsManagerInternal.pruneUninstalledPackagesData(userId);
+ jobFinished(params, !pruned); // reschedule if data was not pruned
+ });
+ return true;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ // Since the pruning job isn't a heavy job, we don't want to cancel it's execution midway.
+ return false;
+ }
+
+ /**
+ * Helper method to create a cloned array of removed tokens from previous jobs (if any) with
+ * the newly removed token at index 0. If there are no removed tokens from previous jobs, it
+ * simply returns a new array containing the current token.
+ */
+ private static int[] getOrCreateRemovedTokens(int[] previousRemovedTokens, int token) {
+ final int[] removedTokens;
+ if (previousRemovedTokens == null) {
+ removedTokens = new int[1];
+ } else {
+ removedTokens = new int[previousRemovedTokens.length + 1];
+ System.arraycopy(previousRemovedTokens, 0, removedTokens, 1,
+ previousRemovedTokens.length);
+ }
+ removedTokens[0] = token;
+ return removedTokens;
+ }
+}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index f9b3659..5f5e7e8 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -846,6 +846,8 @@
mUserState.remove(userId);
mAppStandby.onUserRemoved(userId);
mAppTimeLimit.onUserRemoved(userId);
+ // Cancel any scheduled jobs for this user since the user is being removed.
+ UsageStatsIdleService.cancelJob(getContext(), userId);
}
}
@@ -855,7 +857,7 @@
private void onPackageRemoved(int userId, String packageName) {
synchronized (mLock) {
final long timeRemoved = System.currentTimeMillis();
- if (!mUserUnlockedStates.get(userId, false)) {
+ if (!mUserUnlockedStates.get(userId)) {
// If user is not unlocked and a package is removed for them, we will handle it
// when the user service is initialized and package manager is queried.
return;
@@ -872,6 +874,24 @@
/**
* Called by the Binder stub.
*/
+ private boolean pruneUninstalledPackagesData(int userId) {
+ synchronized (mLock) {
+ if (!mUserUnlockedStates.get(userId)) {
+ return false; // user is no longer unlocked
+ }
+
+ final UserUsageStatsService userService = mUserState.get(userId);
+ if (userService == null) {
+ return false; // user was stopped or removed
+ }
+
+ return userService.pruneUninstalledPackagesData();
+ }
+ }
+
+ /**
+ * Called by the Binder stub.
+ */
List<UsageStats> queryUsageStats(int userId, int bucketType, long beginTime, long endTime,
boolean obfuscateInstantApps) {
synchronized (mLock) {
@@ -2124,6 +2144,11 @@
public AppUsageLimitData getAppUsageLimit(String packageName, UserHandle user) {
return mAppTimeLimit.getAppUsageLimit(packageName, user);
}
+
+ @Override
+ public boolean pruneUninstalledPackagesData(int userId) {
+ return UsageStatsService.this.pruneUninstalledPackagesData(userId);
+ }
}
private class MyPackageMonitor extends PackageMonitor {
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 5783932..d30f2ad 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -34,10 +34,9 @@
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManagerInternal;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
-import android.os.Process;
import android.os.SystemClock;
import android.text.format.DateUtils;
import android.util.ArrayMap;
@@ -47,7 +46,6 @@
import android.util.SparseIntArray;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.LocalServices;
import com.android.server.usage.UsageStatsDatabase.StatCombiner;
import java.io.File;
@@ -55,7 +53,7 @@
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashSet;
+import java.util.HashMap;
import java.util.List;
/**
@@ -115,6 +113,9 @@
void init(final long currentTimeMillis) {
readPackageMappingsLocked();
mDatabase.init(currentTimeMillis);
+ if (mDatabase.wasUpgradePerformed()) {
+ mDatabase.prunePackagesDataOnUpgrade(getInstalledPackages());
+ }
int nullCount = 0;
for (int i = 0; i < mCurrentStats.length; i++) {
@@ -175,53 +176,70 @@
}
void onPackageRemoved(String packageName, long timeRemoved) {
- mDatabase.onPackageRemoved(packageName, timeRemoved);
+ final int token = mDatabase.onPackageRemoved(packageName, timeRemoved);
+ if (token != PackagesTokenData.UNASSIGNED_TOKEN) {
+ UsageStatsIdleService.scheduleJob(mContext, mUserId, token);
+ }
}
private void readPackageMappingsLocked() {
mDatabase.readMappingsLocked();
- cleanUpPackageMappingsLocked();
+ updatePackageMappingsLocked();
}
/**
- * Queries Package Manager for a list of installed packages and removes those packages from
- * mPackagesTokenData which are not installed any more.
+ * Queries Job Scheduler for any pending data prune jobs and if any exist, it updates the
+ * package mappings in memory by removing those tokens.
* This will only happen once per device boot, when the user is unlocked for the first time.
*/
- private void cleanUpPackageMappingsLocked() {
+ private void updatePackageMappingsLocked() {
final long timeNow = System.currentTimeMillis();
- /*
- Note (b/142501248): PackageManagerInternal#getInstalledApplications is not lightweight.
- Once its implementation is updated, or it's replaced with a better alternative, update
- the call here to use it. For now, using the heavy #getInstalledApplications is okay since
- this clean-up is only performed once every boot.
- */
- final PackageManagerInternal packageManagerInternal =
- LocalServices.getService(PackageManagerInternal.class);
- if (packageManagerInternal == null) {
+ final int[] removedTokens = UsageStatsIdleService.fetchRemovedTokens(mContext, mUserId);
+ if (removedTokens == null) {
return;
}
- final List<ApplicationInfo> installedPackages =
- packageManagerInternal.getInstalledApplications(0, mUserId, Process.SYSTEM_UID);
- // convert the package list to a set for easy look-ups
- final HashSet<String> packagesSet = new HashSet<>(installedPackages.size());
- for (int i = installedPackages.size() - 1; i >= 0; i--) {
- packagesSet.add(installedPackages.get(i).packageName);
- }
- final List<String> removedPackages = new ArrayList<>();
- // populate list of packages that are found in the mappings but not in the installed list
- for (int i = mDatabase.mPackagesTokenData.packagesToTokensMap.size() - 1; i >= 0; i--) {
- if (!packagesSet.contains(mDatabase.mPackagesTokenData.packagesToTokensMap.keyAt(i))) {
- removedPackages.add(mDatabase.mPackagesTokenData.packagesToTokensMap.keyAt(i));
- }
- }
- // remove packages in the mappings that are no longer installed
- for (int i = removedPackages.size() - 1; i >= 0; i--) {
- mDatabase.mPackagesTokenData.removePackage(removedPackages.get(i), timeNow);
+ for (int i = removedTokens.length - 1; i >= 0; i--) {
+ final String packageName =
+ mDatabase.mPackagesTokenData.getPackageString(removedTokens[i]);
+ if (packageName == null) {
+ continue;
+ }
+ /*
+ Note: in most cases, packageName returned will be null since the package mappings file
+ on disk should have been updated when it was last persisted. This is to handle the rare
+ case of system crashing after a package was removed but the package mappings file
+ wasn't persisted to disk.
+ */
+ mDatabase.mPackagesTokenData.removePackage(packageName, timeNow);
}
}
+ /**
+ * Fetches a map of package names to their install times. This includes all installed packages,
+ * including those packages which have been uninstalled with the DONT_DELETE_DATA flag.
+ * Note: this is supposed be a helper method which is only used on database upgrades - it should
+ * not be called otherwise since it's implementation performs a heavy query to package manager.
+ */
+ private HashMap<String, Long> getInstalledPackages() {
+ final PackageManager packageManager = mContext.getPackageManager();
+ if (packageManager == null) {
+ return null;
+ }
+ final List<PackageInfo> installedPackages = packageManager.getInstalledPackagesAsUser(
+ PackageManager.MATCH_UNINSTALLED_PACKAGES, mUserId);
+ final HashMap<String, Long> packagesMap = new HashMap<>();
+ for (int i = installedPackages.size() - 1; i >= 0; i--) {
+ final PackageInfo packageInfo = installedPackages.get(i);
+ packagesMap.put(packageInfo.packageName, packageInfo.firstInstallTime);
+ }
+ return packagesMap;
+ }
+
+ boolean pruneUninstalledPackagesData() {
+ return mDatabase.pruneUninstalledPackagesData();
+ }
+
private void onTimeChanged(long oldTime, long newTime) {
persistActiveStats();
mDatabase.onTimeChanged(newTime - oldTime);
diff --git a/services/usb/Android.bp b/services/usb/Android.bp
index 20855b7..d2c973a 100644
--- a/services/usb/Android.bp
+++ b/services/usb/Android.bp
@@ -1,6 +1,13 @@
+filegroup {
+ name: "services.usb-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
java_library_static {
name: "services.usb",
- srcs: ["java/**/*.java"],
+ srcs: [":services.usb-sources"],
libs: [
"services.core",
diff --git a/services/voiceinteraction/Android.bp b/services/voiceinteraction/Android.bp
index 390406f..85b96f34 100644
--- a/services/voiceinteraction/Android.bp
+++ b/services/voiceinteraction/Android.bp
@@ -1,5 +1,12 @@
+filegroup {
+ name: "services.voiceinteraction-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
java_library_static {
name: "services.voiceinteraction",
- srcs: ["java/**/*.java"],
+ srcs: [":services.voiceinteraction-sources"],
libs: ["services.core"],
}
diff --git a/services/wifi/Android.bp b/services/wifi/Android.bp
index 608fc2c..8a7f73f 100644
--- a/services/wifi/Android.bp
+++ b/services/wifi/Android.bp
@@ -1,14 +1,16 @@
-// Interfaces between the core system and the wifi mainline module.
-java_library_static {
- name: "services.wifi",
+filegroup {
+ name: "services.wifi-sources",
srcs: [
"java/**/*.java",
"java/**/*.aidl",
],
- aidl: {
- local_include_dirs: ["java"]
- },
- libs: [
- "services.net",
- ],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
+// Interfaces between the core system and the wifi mainline module.
+java_library_static {
+ name: "services.wifi",
+ srcs: [":services.wifi-sources"],
+ libs: ["services.net"],
}
diff --git a/startop/iorap/Android.bp b/startop/iorap/Android.bp
index 59a80fb..993d1e1 100644
--- a/startop/iorap/Android.bp
+++ b/startop/iorap/Android.bp
@@ -12,19 +12,24 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+filegroup {
+ name: "services.startop.iorap-javasources",
+ srcs: ["src/**/*.java"],
+ path: "src",
+ visibility: ["//visibility:private"],
+}
+
+filegroup {
+ name: "services.startop.iorap-sources",
+ srcs: [
+ ":services.startop.iorap-javasources",
+ ":iorap-aidl",
+ ],
+ visibility: ["//frameworks/base/services:__subpackages__"],
+}
+
java_library_static {
name: "services.startop.iorap",
-
- aidl: {
- include_dirs: [
- "system/iorap/binder",
- ],
- },
-
+ srcs: [":services.startop.iorap-sources"],
libs: ["services.core"],
-
- srcs: [
- ":iorap-aidl",
- "**/*.java",
- ],
}
diff --git a/telephony/java/android/telephony/TelephonyFrameworkInitializer.java b/telephony/java/android/telephony/TelephonyFrameworkInitializer.java
new file mode 100644
index 0000000..b75d533
--- /dev/null
+++ b/telephony/java/android/telephony/TelephonyFrameworkInitializer.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.annotation.SystemApi;
+import android.app.SystemServiceRegistry;
+import android.content.Context;
+import android.telephony.euicc.EuiccCardManager;
+import android.telephony.euicc.EuiccManager;
+
+
+/**
+ * Class for performing registration for all telephony services.
+ *
+ * @hide
+ */
+@SystemApi
+public class TelephonyFrameworkInitializer {
+
+ private TelephonyFrameworkInitializer() {
+ }
+
+ /**
+ * Called by {@link SystemServiceRegistry}'s static initializer and registers all telephony
+ * services to {@link Context}, so that {@link Context#getSystemService} can return them.
+ *
+ * @throws IllegalStateException if this is called from anywhere besides
+ * {@link SystemServiceRegistry}
+ */
+ public static void registerServiceWrappers() {
+ SystemServiceRegistry.registerContextAwareService(
+ Context.TELEPHONY_SERVICE,
+ TelephonyManager.class,
+ context -> new TelephonyManager(context)
+ );
+ SystemServiceRegistry.registerContextAwareService(
+ Context.TELEPHONY_SUBSCRIPTION_SERVICE,
+ SubscriptionManager.class,
+ context -> new SubscriptionManager(context)
+ );
+ SystemServiceRegistry.registerContextAwareService(
+ Context.CARRIER_CONFIG_SERVICE,
+ CarrierConfigManager.class,
+ context -> new CarrierConfigManager(context)
+ );
+ SystemServiceRegistry.registerContextAwareService(
+ Context.EUICC_SERVICE,
+ EuiccManager.class,
+ context -> new EuiccManager(context)
+ );
+ SystemServiceRegistry.registerContextAwareService(
+ Context.EUICC_CARD_SERVICE,
+ EuiccCardManager.class,
+ context -> new EuiccCardManager(context)
+ );
+ }
+}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 60a2cd0..8759a29 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -8988,7 +8988,10 @@
@Deprecated
public boolean isTtyModeSupported() {
try {
- TelecomManager telecomManager = TelecomManager.from(mContext);
+ TelecomManager telecomManager = null;
+ if (mContext != null) {
+ telecomManager = mContext.getSystemService(TelecomManager.class);
+ }
if (telecomManager != null) {
return telecomManager.isTtySupported();
}
@@ -11298,7 +11301,9 @@
@IntDef(prefix = {"SET_OPPORTUNISTIC_SUB"}, value = {
SET_OPPORTUNISTIC_SUB_SUCCESS,
SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED,
- SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION})
+ SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION,
+ SET_OPPORTUNISTIC_SUB_NO_OPPORTUNISTIC_SUB_AVAILABLE,
+ SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION})
public @interface SetOpportunisticSubscriptionResult {}
/**
@@ -11316,6 +11321,17 @@
*/
public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2;
+ /**
+ * The subscription is not valid. It must be an opportunistic subscription.
+ */
+ public static final int SET_OPPORTUNISTIC_SUB_NO_OPPORTUNISTIC_SUB_AVAILABLE = 3;
+
+ /**
+ * Subscription service happened remote exception.
+ */
+ public static final int SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION = 4;
+
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"UPDATE_AVAILABLE_NETWORKS"}, value = {
@@ -11323,7 +11339,13 @@
UPDATE_AVAILABLE_NETWORKS_UNKNOWN_FAILURE,
UPDATE_AVAILABLE_NETWORKS_ABORTED,
UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS,
- UPDATE_AVAILABLE_NETWORKS_NO_CARRIER_PRIVILEGE})
+ UPDATE_AVAILABLE_NETWORKS_NO_CARRIER_PRIVILEGE,
+ UPDATE_AVAILABLE_NETWORKS_DISABLE_MODEM_FAIL,
+ UPDATE_AVAILABLE_NETWORKS_ENABLE_MODEM_FAIL,
+ UPDATE_AVAILABLE_NETWORKS_MULTIPLE_NETWORKS_NOT_SUPPORTED,
+ UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE,
+ UPDATE_AVAILABLE_NETWORKS_REMOTE_SERVICE_EXCEPTION,
+ UPDATE_AVAILABLE_NETWORKS_SERVICE_IS_DISABLED})
public @interface UpdateAvailableNetworksResult {}
/**
@@ -11352,6 +11374,36 @@
public static final int UPDATE_AVAILABLE_NETWORKS_NO_CARRIER_PRIVILEGE = 4;
/**
+ * Disable modem fail.
+ */
+ public static final int UPDATE_AVAILABLE_NETWORKS_DISABLE_MODEM_FAIL = 5;
+
+ /**
+ * Enable modem fail.
+ */
+ public static final int UPDATE_AVAILABLE_NETWORKS_ENABLE_MODEM_FAIL = 6;
+
+ /**
+ * Carrier app does not support multiple available networks.
+ */
+ public static final int UPDATE_AVAILABLE_NETWORKS_MULTIPLE_NETWORKS_NOT_SUPPORTED = 7;
+
+ /**
+ * The subscription is not valid. It must be an opportunistic subscription.
+ */
+ public static final int UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE = 8;
+
+ /**
+ * There is no OpportunisticNetworkService.
+ */
+ public static final int UPDATE_AVAILABLE_NETWORKS_REMOTE_SERVICE_EXCEPTION = 9;
+
+ /**
+ * OpportunisticNetworkService is disabled.
+ */
+ public static final int UPDATE_AVAILABLE_NETWORKS_SERVICE_IS_DISABLED = 10;
+
+ /**
* Set preferred opportunistic data subscription id.
*
* Switch internet data to preferred opportunistic data subscription id. This api
@@ -11381,7 +11433,7 @@
return;
}
Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
- callback.accept(SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION);
+ callback.accept(SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION);
}));
return;
}
@@ -11467,9 +11519,8 @@
return;
}
if (iOpportunisticNetworkService == null) {
- /* Todo<b/130595455> passing unknown due to lack of good error codes */
Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
- callback.accept(UPDATE_AVAILABLE_NETWORKS_UNKNOWN_FAILURE);
+ callback.accept(UPDATE_AVAILABLE_NETWORKS_REMOTE_SERVICE_EXCEPTION);
}));
} else {
Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
diff --git a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
index 0d4fd0f..e6bebbb 100644
--- a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
@@ -25,10 +25,10 @@
import android.os.RemoteException;
import android.permission.IPermissionManager;
import android.provider.Settings;
+import android.telephony.Rlog;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.Slog;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -78,7 +78,7 @@
IPackageManager packageManager, IPermissionManager permissionManager,
TelephonyManager telephonyManager, ContentResolver contentResolver, int userId) {
if (DEBUG) {
- Slog.d(TAG, "disableCarrierAppsUntilPrivileged");
+ Rlog.d(TAG, "disableCarrierAppsUntilPrivileged");
}
SystemConfig config = SystemConfig.getInstance();
ArraySet<String> systemCarrierAppsDisabledUntilUsed =
@@ -105,7 +105,7 @@
IPackageManager packageManager, IPermissionManager permissionManager,
ContentResolver contentResolver, int userId) {
if (DEBUG) {
- Slog.d(TAG, "disableCarrierAppsUntilPrivileged");
+ Rlog.d(TAG, "disableCarrierAppsUntilPrivileged");
}
SystemConfig config = SystemConfig.getInstance();
ArraySet<String> systemCarrierAppsDisabledUntilUsed =
@@ -174,7 +174,7 @@
|| ai.enabledSetting ==
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
|| (ai.flags & ApplicationInfo.FLAG_INSTALLED) == 0)) {
- Slog.i(TAG, "Update state(" + packageName + "): ENABLED for user "
+ Rlog.i(TAG, "Update state(" + packageName + "): ENABLED for user "
+ userId);
packageManager.setSystemAppInstallState(
packageName,
@@ -197,7 +197,7 @@
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
|| (associatedApp.flags
& ApplicationInfo.FLAG_INSTALLED) == 0) {
- Slog.i(TAG, "Update associated state(" + associatedApp.packageName
+ Rlog.i(TAG, "Update associated state(" + associatedApp.packageName
+ "): ENABLED for user " + userId);
packageManager.setSystemAppInstallState(
associatedApp.packageName,
@@ -222,7 +222,7 @@
&& ai.enabledSetting ==
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
&& (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
- Slog.i(TAG, "Update state(" + packageName
+ Rlog.i(TAG, "Update state(" + packageName
+ "): DISABLED_UNTIL_USED for user " + userId);
packageManager.setSystemAppInstallState(
packageName,
@@ -240,7 +240,7 @@
== PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
&& (associatedApp.flags
& ApplicationInfo.FLAG_INSTALLED) != 0) {
- Slog.i(TAG,
+ Rlog.i(TAG,
"Update associated state(" + associatedApp.packageName
+ "): DISABLED_UNTIL_USED for user " + userId);
packageManager.setSystemAppInstallState(
@@ -268,7 +268,7 @@
permissionManager.grantDefaultPermissionsToEnabledCarrierApps(packageNames, userId);
}
} catch (RemoteException e) {
- Slog.w(TAG, "Could not reach PackageManager", e);
+ Rlog.w(TAG, "Could not reach PackageManager", e);
}
}
@@ -390,7 +390,7 @@
return ai;
}
} catch (RemoteException e) {
- Slog.w(TAG, "Could not reach PackageManager", e);
+ Rlog.w(TAG, "Could not reach PackageManager", e);
}
return null;
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
index 5ce42fd..d03419d 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
@@ -30,10 +30,10 @@
import android.telephony.CbGeoUtils.Geometry;
import android.telephony.CbGeoUtils.LatLng;
import android.telephony.CbGeoUtils.Polygon;
+import android.telephony.Rlog;
import android.telephony.SmsCbLocation;
import android.telephony.SmsCbMessage;
import android.util.Pair;
-import android.util.Slog;
import com.android.internal.R;
import com.android.internal.telephony.GsmAlphabet;
@@ -131,7 +131,7 @@
} catch (Exception ex) {
// Catch the exception here, the message will be considered as having no WAC
// information which means the message will be broadcasted directly.
- Slog.e(TAG, "Can't parse warning area coordinates, ex = " + ex.toString());
+ Rlog.e(TAG, "Can't parse warning area coordinates, ex = " + ex.toString());
}
}
@@ -198,7 +198,7 @@
}
return new GeoFencingTriggerMessage(type, cbIdentifiers);
} catch (Exception ex) {
- Slog.e(TAG, "create geo-fencing trigger failed, ex = " + ex.toString());
+ Rlog.e(TAG, "create geo-fencing trigger failed, ex = " + ex.toString());
return null;
}
}
diff --git a/tests/ApkVerityTest/block_device_writer/Android.bp b/tests/ApkVerityTest/block_device_writer/Android.bp
index deed3a0..e7a63e4 100644
--- a/tests/ApkVerityTest/block_device_writer/Android.bp
+++ b/tests/ApkVerityTest/block_device_writer/Android.bp
@@ -22,7 +22,13 @@
stem: "block_device_writer",
srcs: ["block_device_writer.cpp"],
- cflags: ["-Wall", "-Werror", "-Wextra", "-g"],
+ cflags: [
+ "-D_FILE_OFFSET_BITS=64",
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-g",
+ ],
shared_libs: ["libbase", "libutils"],
test_suites: ["general-tests"],
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
index 176c7a0..339df93 100644
--- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
@@ -32,7 +32,7 @@
- // Code below generated by codegen v1.0.13.
+ // Code below generated by codegen v1.0.14.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -98,8 +98,8 @@
};
@DataClass.Generated(
- time = 1573006405823L,
- codegenVersion = "1.0.13",
+ time = 1574122837821L,
+ codegenVersion = "1.0.14",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java",
inputSignatures = "private int mBaseData\nclass HierrarchicalDataClassBase extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genSetters=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
index e348c77..69e06b2 100644
--- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
@@ -46,7 +46,7 @@
- // Code below generated by codegen v1.0.13.
+ // Code below generated by codegen v1.0.14.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -120,8 +120,8 @@
};
@DataClass.Generated(
- time = 1573006406833L,
- codegenVersion = "1.0.13",
+ time = 1574122838768L,
+ codegenVersion = "1.0.14",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java",
inputSignatures = "private @android.annotation.NonNull java.lang.String mChildData\nclass HierrarchicalDataClassChild extends com.android.codegentest.HierrarchicalDataClassBase implements []\n@com.android.internal.util.DataClass(genParcelable=true, genConstructor=false, genSetters=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
index 112d3df..ca128be 100644
--- a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
@@ -54,7 +54,7 @@
- // Code below generated by codegen v1.0.13.
+ // Code below generated by codegen v1.0.14.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -291,7 +291,7 @@
/** @see #setStringList */
@DataClass.Generated.Member
- public @NonNull Builder addStringList(String value) {
+ public @NonNull Builder addStringList(@NonNull String value) {
// You can refine this method's name by providing item's singular name, e.g.:
// @DataClass.PluralOf("item")) mItems = ...
@@ -310,7 +310,7 @@
/** @see #setMap */
@DataClass.Generated.Member
- public @NonNull Builder addMap(String key, SampleWithCustomBuilder value) {
+ public @NonNull Builder addMap(@NonNull String key, @NonNull SampleWithCustomBuilder value) {
// You can refine this method's name by providing item's singular name, e.g.:
// @DataClass.PluralOf("item")) mItems = ...
@@ -329,7 +329,7 @@
/** @see #setStringMap */
@DataClass.Generated.Member
- public @NonNull Builder addStringMap(String key, String value) {
+ public @NonNull Builder addStringMap(@NonNull String key, @NonNull String value) {
// You can refine this method's name by providing item's singular name, e.g.:
// @DataClass.PluralOf("item")) mItems = ...
@@ -412,8 +412,8 @@
}
@DataClass.Generated(
- time = 1573006404728L,
- codegenVersion = "1.0.13",
+ time = 1574122836960L,
+ codegenVersion = "1.0.14",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java",
inputSignatures = " @android.annotation.NonNull java.lang.String[] mStringArray\n @android.annotation.NonNull int[] mIntArray\n @android.annotation.NonNull java.util.List<java.lang.String> mStringList\n @android.annotation.NonNull java.util.Map<java.lang.String,com.android.codegentest.SampleWithCustomBuilder> mMap\n @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.String> mStringMap\n @android.annotation.NonNull android.util.SparseArray<com.android.codegentest.SampleWithCustomBuilder> mSparseArray\n @android.annotation.NonNull android.util.SparseIntArray mSparseIntArray\n @java.lang.SuppressWarnings({\"WeakerAccess\"}) @android.annotation.Nullable java.lang.Boolean mNullableBoolean\nclass ParcelAllTheThingsDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
index 0fdcf59..c850bf8 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
@@ -342,7 +342,7 @@
- // Code below generated by codegen v1.0.13.
+ // Code below generated by codegen v1.0.14.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -1636,7 +1636,7 @@
/** @see #setLinkAddresses2 */
@DataClass.Generated.Member
- public @NonNull Builder addLinkAddresses2(LinkAddress value) {
+ public @NonNull Builder addLinkAddresses2(@NonNull LinkAddress value) {
// You can refine this method's name by providing item's singular name, e.g.:
// @DataClass.PluralOf("item")) mItems = ...
@@ -1661,7 +1661,7 @@
/** @see #setLinkAddresses */
@DataClass.Generated.Member
- public @NonNull Builder addLinkAddress(LinkAddress value) {
+ public @NonNull Builder addLinkAddress(@NonNull LinkAddress value) {
if (mLinkAddresses == null) setLinkAddresses(new ArrayList<>());
mLinkAddresses.add(value);
return this;
@@ -1872,8 +1872,8 @@
}
@DataClass.Generated(
- time = 1573006402566L,
- codegenVersion = "1.0.13",
+ time = 1574122835009L,
+ codegenVersion = "1.0.14",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java",
inputSignatures = "public static final java.lang.String STATE_NAME_UNDEFINED\npublic static final java.lang.String STATE_NAME_ON\npublic static final java.lang.String STATE_NAME_OFF\npublic static final int STATE_UNDEFINED\npublic static final int STATE_ON\npublic static final int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate int mNum\nprivate int mNum2\nprivate int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient android.net.LinkAddress[] mLinkAddresses6\ntransient int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=6L) int mDayOfWeek\nprivate @android.annotation.Size(2L) @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate static java.lang.String defaultName4()\nprivate int[] lazyInitTmpStorage()\npublic android.net.LinkAddress[] getLinkAddresses4()\nprivate boolean patternEquals(java.util.regex.Pattern)\nprivate int patternHashCode()\nprivate void onConstructed()\npublic void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
index cab477d..2de848c 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
@@ -85,7 +85,7 @@
- // Code below generated by codegen v1.0.13.
+ // Code below generated by codegen v1.0.14.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -253,8 +253,8 @@
}
@DataClass.Generated(
- time = 1573006403628L,
- codegenVersion = "1.0.13",
+ time = 1574122835982L,
+ codegenVersion = "1.0.14",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java",
inputSignatures = " long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n long creationTimestamp\nprivate static java.util.concurrent.TimeUnit unparcelDelayUnit(android.os.Parcel)\nprivate void parcelDelayUnit(android.os.Parcel,int)\nclass SampleWithCustomBuilder extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java b/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
index 6190085..0deffe4 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
@@ -36,7 +36,7 @@
- // Code below generated by codegen v1.0.13.
+ // Code below generated by codegen v1.0.14.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -135,8 +135,8 @@
};
@DataClass.Generated(
- time = 1573006408903L,
- codegenVersion = "1.0.13",
+ time = 1574122840588L,
+ codegenVersion = "1.0.14",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
inputSignatures = " @android.annotation.NonNull java.lang.String mBar\nclass NestedDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
@Deprecated
@@ -160,7 +160,7 @@
- // Code below generated by codegen v1.0.13.
+ // Code below generated by codegen v1.0.14.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -259,8 +259,8 @@
};
@DataClass.Generated(
- time = 1573006408912L,
- codegenVersion = "1.0.13",
+ time = 1574122840597L,
+ codegenVersion = "1.0.14",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
inputSignatures = " @android.annotation.NonNull long mBaz2\nclass NestedDataClass3 extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
@Deprecated
@@ -274,7 +274,7 @@
- // Code below generated by codegen v1.0.13.
+ // Code below generated by codegen v1.0.14.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -373,8 +373,8 @@
};
@DataClass.Generated(
- time = 1573006408917L,
- codegenVersion = "1.0.13",
+ time = 1574122840608L,
+ codegenVersion = "1.0.14",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
inputSignatures = " @android.annotation.NonNull java.lang.String mBaz\nclass NestedDataClass2 extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
@Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
index 5a960d7..712722b 100644
--- a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
+++ b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
@@ -51,7 +51,7 @@
- // Code below generated by codegen v1.0.13.
+ // Code below generated by codegen v1.0.14.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -65,8 +65,8 @@
@DataClass.Generated(
- time = 1573006407900L,
- codegenVersion = "1.0.13",
+ time = 1574122839646L,
+ codegenVersion = "1.0.14",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java",
inputSignatures = "public @android.annotation.NonNull java.lang.String someMethod(int)\nclass StaleDataclassDetectorFalsePositivesTest extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false)")
@Deprecated
diff --git a/tools/codegen/src/com/android/codegen/ClassPrinter.kt b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
index a4fd374..c7c80ba 100644
--- a/tools/codegen/src/com/android/codegen/ClassPrinter.kt
+++ b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
@@ -164,7 +164,13 @@
getSuppressedMembers(classAst)
}
val builderSuppressedMembers by lazy {
- getSuppressedMembers(customBaseBuilderAst)
+ getSuppressedMembers(customBaseBuilderAst) + suppressedMembers.mapNotNull {
+ if (it.startsWith("$CANONICAL_BUILDER_CLASS.")) {
+ it.removePrefix("$CANONICAL_BUILDER_CLASS.")
+ } else {
+ null
+ }
+ }
}
private fun getSuppressedMembers(clazz: ClassOrInterfaceDeclaration?): List<String> {
diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt
index dc1f4c5..8fe243f 100644
--- a/tools/codegen/src/com/android/codegen/Generators.kt
+++ b/tools/codegen/src/com/android/codegen/Generators.kt
@@ -270,7 +270,7 @@
private fun ClassPrinter.generateBuilderMethod(
defVisibility: String,
name: String,
- ParamAnnotations: String? = null,
+ paramAnnotations: String? = null,
paramTypes: List<String>,
paramNames: List<String> = listOf("value"),
genJavadoc: ClassPrinter.() -> Unit,
@@ -292,8 +292,12 @@
+GENERATED_MEMBER_HEADER
if (providedMethod?.isAbstract == true) +"@Override"
if (!Annotations.isNullOrEmpty()) +Annotations
- "$visibility @$NonNull $ReturnType $name(${if_(!ParamAnnotations.isNullOrEmpty(), "$ParamAnnotations ")}${
- paramTypes.zip(paramNames).joinToString(", ") { (Type, paramName) -> "$Type $paramName" }
+ val ParamAnnotations = if (!paramAnnotations.isNullOrEmpty()) "$paramAnnotations " else ""
+
+ "$visibility @$NonNull $ReturnType $name(${
+ paramTypes.zip(paramNames).joinToString(", ") { (Type, paramName) ->
+ "$ParamAnnotations$Type $paramName"
+ }
})" {
genBody()
}
@@ -311,7 +315,7 @@
generateBuilderMethod(
name = setterName,
defVisibility = visibility,
- ParamAnnotations = annotationsNoInternal.joinToString(" "),
+ paramAnnotations = annotationsNoInternal.joinToString(" "),
paramTypes = listOf(SetterParamType),
genJavadoc = { generateFieldJavadoc() }) {
+"checkNotUsed();"
@@ -333,6 +337,7 @@
generateBuilderMethod(
name = adderName,
defVisibility = visibility,
+ paramAnnotations = "@$NonNull",
paramTypes = listOf(FieldInnerType),
genJavadoc = { +javadocSeeSetter }) {
@@ -347,6 +352,7 @@
generateBuilderMethod(
name = adderName,
defVisibility = visibility,
+ paramAnnotations = "@$NonNull",
paramTypes = fieldTypeGenegicArgs,
paramNames = listOf("key", "value"),
genJavadoc = { +javadocSeeSetter }) {
diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt
index 85c832f..74c86f4 100644
--- a/tools/codegen/src/com/android/codegen/SharedConstants.kt
+++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt
@@ -1,7 +1,7 @@
package com.android.codegen
const val CODEGEN_NAME = "codegen"
-const val CODEGEN_VERSION = "1.0.13"
+const val CODEGEN_VERSION = "1.0.14"
const val CANONICAL_BUILDER_CLASS = "Builder"
const val BASE_BUILDER_CLASS = "BaseBuilder"
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index f62fef0..18e2da3 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -1309,7 +1309,7 @@
fprintf(out, " write_non_chained(code");
for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
if (argIndex == attributionArg) {
- fprintf(out, ", ws.get(i), ws.getName(i)");
+ fprintf(out, ", ws.getUid(i), ws.getPackageName(i)");
} else {
fprintf(out, ", arg%d", argIndex);
}
@@ -1318,7 +1318,7 @@
fprintf(out, " }\n"); // close for-loop
// write() component.
- fprintf(out, " ArrayList<WorkSource.WorkChain> workChains = ws.getWorkChains();\n");
+ fprintf(out, " List<WorkSource.WorkChain> workChains = ws.getWorkChains();\n");
fprintf(out, " if (workChains != null) {\n");
fprintf(out, " for (WorkSource.WorkChain wc : workChains) {\n");
fprintf(out, " write(code");
@@ -1407,7 +1407,7 @@
fprintf(out, "\n");
fprintf(out, "import android.os.WorkSource;\n");
fprintf(out, "import android.util.SparseArray;\n");
- fprintf(out, "import java.util.ArrayList;\n");
+ fprintf(out, "import java.util.List;\n");
fprintf(out, "\n");
fprintf(out, "\n");
fprintf(out, "/**\n");
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index bbb8544..4619372 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -161,8 +161,6 @@
boolean setWifiApConfiguration(in WifiConfiguration wifiConfig, String packageName);
- void notifyUserOfApBandConversion(String packageName);
-
void enableTdls(String remoteIPAddress, boolean enable);
void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable);
@@ -242,4 +240,6 @@
void registerSuggestionConnectionStatusListener(in IBinder binder, in ISuggestionConnectionStatusListener listener, int listenerIdentifier, String packageName, String featureId);
void unregisterSuggestionConnectionStatusListener(int listenerIdentifier, String packageName);
+
+ int calculateSignalLevel(int rssi);
}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index f7d2b40..90343d4 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -384,7 +384,12 @@
public void setSecurityParams(@SecurityType int securityType) {
// Clear all the bitsets.
allowedKeyManagement.clear();
+ allowedProtocols.clear();
allowedAuthAlgorithms.clear();
+ allowedPairwiseCiphers.clear();
+ allowedGroupCiphers.clear();
+ allowedGroupManagementCiphers.clear();
+ allowedSuiteBCiphers.clear();
switch (securityType) {
case SECURITY_TYPE_OPEN:
@@ -407,9 +412,6 @@
requirePMF = true;
break;
case SECURITY_TYPE_EAP_SUITE_B:
- allowedGroupCiphers.clear();
- allowedGroupManagementCiphers.clear();
- allowedSuiteBCiphers.clear();
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
allowedGroupManagementCiphers.set(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256);
@@ -945,12 +947,6 @@
public int meteredOverride = METERED_OVERRIDE_NONE;
/**
- * This Wifi configuration is a clone of another network with lower security
- * @hide
- */
- public String clonedNetworkConfigKey;
-
- /**
* Blend together all the various opinions to decide if the given network
* should be considered metered or not.
*
@@ -1808,7 +1804,6 @@
shared = true;
dtimInterval = 0;
mRandomizedMacAddress = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
- clonedNetworkConfigKey = null;
}
/**
@@ -2376,7 +2371,6 @@
/** copy constructor {@hide} */
@UnsupportedAppUsage
-
public WifiConfiguration(WifiConfiguration source) {
if (source != null) {
networkId = source.networkId;
@@ -2460,7 +2454,6 @@
requirePMF = source.requirePMF;
updateIdentifier = source.updateIdentifier;
carrierId = source.carrierId;
- clonedNetworkConfigKey = source.clonedNetworkConfigKey;
}
}
@@ -2536,7 +2529,6 @@
dest.writeInt(osu ? 1 : 0);
dest.writeLong(randomizedMacExpirationTimeMs);
dest.writeInt(carrierId);
- dest.writeString(clonedNetworkConfigKey);
}
/** Implement the Parcelable interface {@hide} */
@@ -2614,7 +2606,6 @@
config.osu = in.readInt() != 0;
config.randomizedMacExpirationTimeMs = in.readLong();
config.carrierId = in.readInt();
- config.clonedNetworkConfigKey = in.readString();
return config;
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 56f152e..77666b0 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1153,8 +1153,6 @@
* @hide
*/
@UnsupportedAppUsage
- // TODO(b/140781184): need to support custom number of RSSI levels, as well as levels that are
- // not evenly spaced
public static final int RSSI_LEVELS = 5;
/**
@@ -2782,11 +2780,13 @@
* is being shown.
*
* @param rssi The power of the signal measured in RSSI.
- * @param numLevels The number of levels to consider in the calculated
- * level.
- * @return A level of the signal, given in the range of 0 to numLevels-1
- * (both inclusive).
+ * @param numLevels The number of levels to consider in the calculated level.
+ * @return A level of the signal, given in the range of 0 to numLevels-1 (both inclusive).
+ * @deprecated Callers should use {@link #calculateSignalLevel(int)} instead to get the
+ * signal level using the system default RSSI thresholds, or otherwise compute the RSSI level
+ * themselves using their own formula.
*/
+ @Deprecated
public static int calculateSignalLevel(int rssi, int numLevels) {
if (rssi <= MIN_RSSI) {
return 0;
@@ -2800,6 +2800,34 @@
}
/**
+ * Given a raw RSSI, return the RSSI signal quality rating using the system default RSSI
+ * quality rating thresholds.
+ * @param rssi a raw RSSI value, in dBm, usually between -55 and -90
+ * @return the RSSI signal quality rating, in the range
+ * [0, {@link #getMaxSignalLevel()}], where 0 is the lowest (worst signal) RSSI
+ * rating and {@link #getMaxSignalLevel()} is the highest (best signal) RSSI rating.
+ */
+ public int calculateSignalLevel(int rssi) {
+ try {
+ IWifiManager iWifiManager = getIWifiManager();
+ if (iWifiManager == null) {
+ throw new RemoteException("Wifi service is not running");
+ }
+ return iWifiManager.calculateSignalLevel(rssi);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get the system default maximum signal level.
+ * This is the maximum RSSI level returned by {@link #calculateSignalLevel(int)}.
+ */
+ public int getMaxSignalLevel() {
+ return calculateSignalLevel(Integer.MAX_VALUE);
+ }
+
+ /**
* Compares two signal strengths.
*
* @param rssiA The power of the first signal measured in RSSI.
@@ -3207,27 +3235,6 @@
}
/**
- * Method that triggers a notification to the user about a band conversion
- * (e.g. 5 GHz to 2.4 GHz) to their saved AP config.
- *
- * @hide
- */
- // TODO(b/144218444): move the notification to Settings instead of making this @SystemApi
- @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- public void notifyUserOfApBandConversion() {
- Log.d(TAG, "apBand was converted, notify the user");
- try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.notifyUserOfApBandConversion(mContext.getOpPackageName());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Enable/Disable TDLS on a specific local route.
*
* <p>
@@ -4327,7 +4334,7 @@
if (ws == null) {
mWorkSource = null;
} else {
- ws.clearNames();
+ ws = ws.withoutNames();
if (mWorkSource == null) {
changed = mWorkSource != null;
mWorkSource = new WorkSource(ws);
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index cf74ff0..ee03c11 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -42,7 +42,6 @@
import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.os.IBinder;
-import android.os.Messenger;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.WorkSource;
@@ -325,7 +324,6 @@
throw new UnsupportedOperationException();
}
- @Override
public void notifyUserOfApBandConversion(String packageName) {
throw new UnsupportedOperationException();
}
@@ -537,4 +535,9 @@
String packageName) {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public int calculateSignalLevel(int rssi) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 06ebc1b..507d502 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -1899,8 +1899,25 @@
*/
@Test
public void testRemoveSuggestionConnectionListener() throws Exception {
-
mWifiManager.removeSuggestionConnectionStatusListener(mListener);
verify(mWifiService).unregisterSuggestionConnectionStatusListener(anyInt(), anyString());
}
+
+ /** Test {@link WifiManager#calculateSignalLevel(int)} */
+ @Test
+ public void testCalculateSignalLevel() throws Exception {
+ when(mWifiService.calculateSignalLevel(anyInt())).thenReturn(3);
+ int actual = mWifiManager.calculateSignalLevel(-60);
+ verify(mWifiService).calculateSignalLevel(-60);
+ assertEquals(3, actual);
+ }
+
+ /** Test {@link WifiManager#getMaxSignalLevel()} */
+ @Test
+ public void testGetMaxSignalLevel() throws Exception {
+ when(mWifiService.calculateSignalLevel(anyInt())).thenReturn(4);
+ int actual = mWifiManager.getMaxSignalLevel();
+ verify(mWifiService).calculateSignalLevel(Integer.MAX_VALUE);
+ assertEquals(4, actual);
+ }
}