Merge "Sharesheet - Give shortcut api results priority"
diff --git a/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java b/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java
index 1f26188..da9ed6e 100644
--- a/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/KernelCpuThreadReaderPerfTest.java
@@ -40,7 +40,7 @@
public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private final KernelCpuThreadReader mKernelCpuThreadReader =
- KernelCpuThreadReader.create(8, uid -> 1000 <= uid && uid < 2000, 0);
+ KernelCpuThreadReader.create(8, uid -> 1000 <= uid && uid < 2000);
@Test
public void timeReadCurrentProcessCpuUsage() {
diff --git a/apct-tests/perftests/textclassifier/AndroidTest.xml b/apct-tests/perftests/textclassifier/AndroidTest.xml
index 29f9f94..3df51b8 100644
--- a/apct-tests/perftests/textclassifier/AndroidTest.xml
+++ b/apct-tests/perftests/textclassifier/AndroidTest.xml
@@ -13,16 +13,16 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<configuration description="Runs AutofillPerfTests metric instrumentation.">
+<configuration description="Runs TextClassifierPerfTests metric instrumentation.">
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="apct-metric-instrumentation" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="AutofillPerfTests.apk" />
+ <option name="test-file-name" value="TextClassifierPerfTests.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="com.android.perftests.autofill" />
+ <option name="package" value="com.android.perftests.textclassifier" />
<option name="hidden-api-checks" value="false"/>
</test>
</configuration>
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 286e76e..df84b6a 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -602,6 +602,19 @@
void StatsLogProcessor::WriteMetricsActivationToDisk(int64_t currentTimeNs) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
+
+ const int64_t timeNs = getElapsedRealtimeNs();
+ // Do not write to disk if we already have in the last few seconds.
+ // This is to avoid overwriting files that would have the same name if we
+ // write twice in the same second.
+ if (static_cast<unsigned long long> (timeNs) <
+ mLastActiveMetricsWriteNs + WRITE_DATA_COOL_DOWN_SEC * NS_PER_SEC) {
+ ALOGI("Statsd skipping writing active metrics to disk. Already wrote data in last %d seconds",
+ WRITE_DATA_COOL_DOWN_SEC);
+ return;
+ }
+ mLastActiveMetricsWriteNs = timeNs;
+
ProtoOutputStream proto;
for (const auto& pair : mMetricsManagers) {
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index e92b897..8de1881 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -207,6 +207,9 @@
// Last time we wrote data to disk.
int64_t mLastWriteTimeNs = 0;
+ // Last time we wrote active metrics to disk.
+ int64_t mLastActiveMetricsWriteNs = 0;
+
#ifdef VERY_VERBOSE_PRINTING
bool mPrintAllLogs = false;
#endif
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 3bcebd9..1433252 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1028,6 +1028,7 @@
ALOGI("StatsService::Terminating");
if (mProcessor != nullptr) {
mProcessor->WriteDataToDisk(TERMINATION_SIGNAL_RECEIVED, FAST);
+ mProcessor->WriteMetricsActivationToDisk(getElapsedRealtimeNs());
}
}
diff --git a/config/hiddenapi-greylist-packages.txt b/config/hiddenapi-greylist-packages.txt
new file mode 100644
index 0000000..cae3bd9
--- /dev/null
+++ b/config/hiddenapi-greylist-packages.txt
@@ -0,0 +1,2 @@
+org.ccil.cowan.tagsoup
+org.ccil.cowan.tagsoup.jaxp
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 95bdc36..c267e77 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -2488,108 +2488,3 @@
Lorg/apache/xpath/XPathContext;->setCurrentNodeStack(Lorg/apache/xml/utils/IntStack;)V
Lorg/apache/xpath/XPathContext;->setSecureProcessing(Z)V
Lorg/apache/xpath/XPathContext;->setVarStack(Lorg/apache/xpath/VariableStack;)V
-Lorg/ccil/cowan/tagsoup/AttributesImpl;-><init>(Lorg/xml/sax/Attributes;)V
-Lorg/ccil/cowan/tagsoup/AttributesImpl;->addAttribute(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/AttributesImpl;->data:[Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/AttributesImpl;->length:I
-Lorg/ccil/cowan/tagsoup/AttributesImpl;->setAttribute(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/AttributesImpl;->setValue(ILjava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/AutoDetector;->autoDetectingReader(Ljava/io/InputStream;)Ljava/io/Reader;
-Lorg/ccil/cowan/tagsoup/Element;-><init>(Lorg/ccil/cowan/tagsoup/ElementType;Z)V
-Lorg/ccil/cowan/tagsoup/Element;->anonymize()V
-Lorg/ccil/cowan/tagsoup/Element;->atts()Lorg/ccil/cowan/tagsoup/AttributesImpl;
-Lorg/ccil/cowan/tagsoup/Element;->canContain(Lorg/ccil/cowan/tagsoup/Element;)Z
-Lorg/ccil/cowan/tagsoup/Element;->clean()V
-Lorg/ccil/cowan/tagsoup/Element;->flags()I
-Lorg/ccil/cowan/tagsoup/Element;->localName()Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Element;->name()Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Element;->namespace()Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Element;->next()Lorg/ccil/cowan/tagsoup/Element;
-Lorg/ccil/cowan/tagsoup/Element;->parent()Lorg/ccil/cowan/tagsoup/ElementType;
-Lorg/ccil/cowan/tagsoup/Element;->preclosed:Z
-Lorg/ccil/cowan/tagsoup/Element;->setAttribute(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/Element;->setNext(Lorg/ccil/cowan/tagsoup/Element;)V
-Lorg/ccil/cowan/tagsoup/Element;->theAtts:Lorg/ccil/cowan/tagsoup/AttributesImpl;
-Lorg/ccil/cowan/tagsoup/Element;->theNext:Lorg/ccil/cowan/tagsoup/Element;
-Lorg/ccil/cowan/tagsoup/Element;->theType:Lorg/ccil/cowan/tagsoup/ElementType;
-Lorg/ccil/cowan/tagsoup/ElementType;-><init>(Ljava/lang/String;IIILorg/ccil/cowan/tagsoup/Schema;)V
-Lorg/ccil/cowan/tagsoup/ElementType;->atts()Lorg/ccil/cowan/tagsoup/AttributesImpl;
-Lorg/ccil/cowan/tagsoup/ElementType;->setAttribute(Lorg/ccil/cowan/tagsoup/AttributesImpl;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/ElementType;->theAtts:Lorg/ccil/cowan/tagsoup/AttributesImpl;
-Lorg/ccil/cowan/tagsoup/ElementType;->theFlags:I
-Lorg/ccil/cowan/tagsoup/ElementType;->theLocalName:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/ElementType;->theMemberOf:I
-Lorg/ccil/cowan/tagsoup/ElementType;->theModel:I
-Lorg/ccil/cowan/tagsoup/ElementType;->theName:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/ElementType;->theNamespace:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/ElementType;->theParent:Lorg/ccil/cowan/tagsoup/ElementType;
-Lorg/ccil/cowan/tagsoup/ElementType;->theSchema:Lorg/ccil/cowan/tagsoup/Schema;
-Lorg/ccil/cowan/tagsoup/HTMLScanner;-><init>()V
-Lorg/ccil/cowan/tagsoup/HTMLSchema;-><init>()V
-Lorg/ccil/cowan/tagsoup/jaxp/SAXFactoryImpl;-><init>()V
-Lorg/ccil/cowan/tagsoup/jaxp/SAXParserImpl;-><init>()V
-Lorg/ccil/cowan/tagsoup/jaxp/SAXParserImpl;->newInstance(Ljava/util/Map;)Lorg/ccil/cowan/tagsoup/jaxp/SAXParserImpl;
-Lorg/ccil/cowan/tagsoup/Parser;-><init>()V
-Lorg/ccil/cowan/tagsoup/Parser;->bogonsEmpty:Z
-Lorg/ccil/cowan/tagsoup/Parser;->CDATAElements:Z
-Lorg/ccil/cowan/tagsoup/Parser;->cleanPublicid(Ljava/lang/String;)Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->defaultAttributes:Z
-Lorg/ccil/cowan/tagsoup/Parser;->etagchars:[C
-Lorg/ccil/cowan/tagsoup/Parser;->expandEntities(Ljava/lang/String;)Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->getInputStream(Ljava/lang/String;Ljava/lang/String;)Ljava/io/InputStream;
-Lorg/ccil/cowan/tagsoup/Parser;->ignorableWhitespace:Z
-Lorg/ccil/cowan/tagsoup/Parser;->ignoreBogons:Z
-Lorg/ccil/cowan/tagsoup/Parser;->lookupEntity([CII)I
-Lorg/ccil/cowan/tagsoup/Parser;->makeName([CII)Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->pop()V
-Lorg/ccil/cowan/tagsoup/Parser;->push(Lorg/ccil/cowan/tagsoup/Element;)V
-Lorg/ccil/cowan/tagsoup/Parser;->rectify(Lorg/ccil/cowan/tagsoup/Element;)V
-Lorg/ccil/cowan/tagsoup/Parser;->restart(Lorg/ccil/cowan/tagsoup/Element;)V
-Lorg/ccil/cowan/tagsoup/Parser;->restartablyPop()V
-Lorg/ccil/cowan/tagsoup/Parser;->rootBogons:Z
-Lorg/ccil/cowan/tagsoup/Parser;->schemaProperty:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->split(Ljava/lang/String;)[Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->theAttributeName:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->theAutoDetector:Lorg/ccil/cowan/tagsoup/AutoDetector;
-Lorg/ccil/cowan/tagsoup/Parser;->theContentHandler:Lorg/xml/sax/ContentHandler;
-Lorg/ccil/cowan/tagsoup/Parser;->theDoctypeIsPresent:Z
-Lorg/ccil/cowan/tagsoup/Parser;->theDoctypeSystemId:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->theFeatures:Ljava/util/HashMap;
-Lorg/ccil/cowan/tagsoup/Parser;->theLexicalHandler:Lorg/xml/sax/ext/LexicalHandler;
-Lorg/ccil/cowan/tagsoup/Parser;->theNewElement:Lorg/ccil/cowan/tagsoup/Element;
-Lorg/ccil/cowan/tagsoup/Parser;->thePCDATA:Lorg/ccil/cowan/tagsoup/Element;
-Lorg/ccil/cowan/tagsoup/Parser;->thePITarget:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->theSaved:Lorg/ccil/cowan/tagsoup/Element;
-Lorg/ccil/cowan/tagsoup/Parser;->theScanner:Lorg/ccil/cowan/tagsoup/Scanner;
-Lorg/ccil/cowan/tagsoup/Parser;->theSchema:Lorg/ccil/cowan/tagsoup/Schema;
-Lorg/ccil/cowan/tagsoup/Parser;->theStack:Lorg/ccil/cowan/tagsoup/Element;
-Lorg/ccil/cowan/tagsoup/Parser;->trimquotes(Ljava/lang/String;)Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->virginStack:Z
-Lorg/ccil/cowan/tagsoup/PYXScanner;-><init>()V
-Lorg/ccil/cowan/tagsoup/PYXWriter;-><init>(Ljava/io/Writer;)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->aname([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->aval([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->entity([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->eof([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->etag([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->gi([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->pcdata([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->pi([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->stagc([CII)V
-Lorg/ccil/cowan/tagsoup/Scanner;->startCDATA()V
-Lorg/ccil/cowan/tagsoup/Schema;->elementType(Ljava/lang/String;III)V
-Lorg/ccil/cowan/tagsoup/Schema;->getElementType(Ljava/lang/String;)Lorg/ccil/cowan/tagsoup/ElementType;
-Lorg/ccil/cowan/tagsoup/Schema;->getEntity(Ljava/lang/String;)I
-Lorg/ccil/cowan/tagsoup/Schema;->getPrefix()Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Schema;->getURI()Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Schema;->parent(Ljava/lang/String;Ljava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/Schema;->theElementTypes:Ljava/util/HashMap;
-Lorg/ccil/cowan/tagsoup/Schema;->theEntities:Ljava/util/HashMap;
-Lorg/ccil/cowan/tagsoup/Schema;->thePrefix:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Schema;->theRoot:Lorg/ccil/cowan/tagsoup/ElementType;
-Lorg/ccil/cowan/tagsoup/Schema;->theURI:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/XMLWriter;-><init>(Ljava/io/Writer;)V
-Lorg/ccil/cowan/tagsoup/XMLWriter;->htmlMode:Z
-Lorg/ccil/cowan/tagsoup/XMLWriter;->setOutput(Ljava/io/Writer;)V
-Lorg/ccil/cowan/tagsoup/XMLWriter;->setOutputProperty(Ljava/lang/String;Ljava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/XMLWriter;->setPrefix(Ljava/lang/String;Ljava/lang/String;)V
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 11fa343..0ab1a85 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5571,7 +5571,7 @@
button.setTextColor(R.id.action0, textColor);
rippleColor = textColor;
} else if (getRawColor(p) != COLOR_DEFAULT && !isColorized(p)
- && mTintActionButtons) {
+ && mTintActionButtons && !mInNightMode) {
rippleColor = resolveContrastColor(p);
button.setTextColor(R.id.action0, rippleColor);
} else {
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index ea245a4..ed7cddc 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -123,6 +123,11 @@
* app must promote itself to the foreground after it's launched or the system
* will shut down the app.
*
+ * <h3>Developer's guide</h3>
+ *
+ * <p>To learn more about developing VPN apps, read the
+ * <a href="{@docRoot}guide/topics/connectivity/vpn">VPN developer's guide</a>.
+ *
* @see Builder
*/
public class VpnService extends Service {
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 43ac574..53503f4 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -337,6 +337,25 @@
}
/**
+ * Check for ANGLE debug package, but only for apps that can load them (dumpable)
+ */
+ private String getAngleDebugPackage(Context context, Bundle coreSettings) {
+ final boolean appIsDebuggable = isDebuggable(context);
+ final boolean appIsProfileable = isProfileable(context);
+ final boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1;
+ if (appIsDebuggable || appIsProfileable || deviceIsDebuggable) {
+
+ String debugPackage =
+ coreSettings.getString(Settings.Global.GLOBAL_SETTINGS_ANGLE_DEBUG_PACKAGE);
+
+ if ((debugPackage != null) && (!debugPackage.isEmpty())) {
+ return debugPackage;
+ }
+ }
+ return "";
+ }
+
+ /**
* Attempt to setup ANGLE with a temporary rules file.
* True: Temporary rules file was loaded.
* False: Temporary rules file was *not* loaded.
@@ -502,11 +521,23 @@
}
final ApplicationInfo angleInfo;
- try {
- angleInfo = pm.getApplicationInfo(anglePkgName, PackageManager.MATCH_SYSTEM_ONLY);
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "ANGLE package '" + anglePkgName + "' not installed");
- return false;
+ String angleDebugPackage = getAngleDebugPackage(context, bundle);
+ if (!angleDebugPackage.isEmpty()) {
+ Log.i(TAG, "ANGLE debug package enabled: " + angleDebugPackage);
+ try {
+ // Note the debug package does not have to be pre-installed
+ angleInfo = pm.getApplicationInfo(angleDebugPackage, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "ANGLE debug package '" + angleDebugPackage + "' not installed");
+ return false;
+ }
+ } else {
+ try {
+ angleInfo = pm.getApplicationInfo(anglePkgName, PackageManager.MATCH_SYSTEM_ONLY);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "ANGLE package '" + anglePkgName + "' not installed");
+ return false;
+ }
}
final String abi = chooseAbi(angleInfo);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 8eac66b..227c9d4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11528,15 +11528,6 @@
"background_activity_starts_enabled";
/**
- * The packages temporarily whitelisted to be able so start activities from background.
- * The list of packages is {@code ":"} colon delimited.
- *
- * @hide
- */
- public static final String BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST =
- "background_activity_starts_package_names_whitelist";
-
- /**
* @hide
* @see com.android.server.appbinding.AppBindingConstants
*/
@@ -12460,6 +12451,14 @@
public static final String GPU_DEBUG_APP = "gpu_debug_app";
/**
+ * Package containing ANGLE libraries other than system, which are only available
+ * to dumpable apps that opt-in.
+ * @hide
+ */
+ public static final String GLOBAL_SETTINGS_ANGLE_DEBUG_PACKAGE =
+ "angle_debug_package";
+
+ /**
* Force all PKGs to use ANGLE, regardless of any other settings
* The value is a boolean (1 or 0).
* @hide
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index da6ef4c..7f6423a 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -55,7 +55,7 @@
DEFAULT_FLAGS.put("settings_dynamic_system", "false");
DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false");
DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
- DEFAULT_FLAGS.put(SAFETY_HUB, "false");
+ DEFAULT_FLAGS.put(SAFETY_HUB, "true");
DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false");
DEFAULT_FLAGS.put(GLOBAL_ACTIONS_GRID_ENABLED, "true");
DEFAULT_FLAGS.put(GLOBAL_ACTIONS_PANEL_ENABLED, "true");
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 0043d32..e3b0b7a 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -978,17 +978,6 @@
}
}
- private static void closeTransaction(boolean sync) {
- synchronized(SurfaceControl.class) {
- if (sTransactionNestCount == 0) {
- Log.e(TAG, "Call to SurfaceControl.closeTransaction without matching openTransaction");
- } else if (--sTransactionNestCount > 0) {
- return;
- }
- sGlobalTransaction.apply(sync);
- }
- }
-
/**
* Merge the supplied transaction in to the deprecated "global" transaction.
* This clears the supplied transaction in an identical fashion to {@link Transaction#merge}.
@@ -1003,19 +992,20 @@
}
}
- /** end a transaction
- * @hide
+ /** end a transaction
+ * @hide
*/
@UnsupportedAppUsage
public static void closeTransaction() {
- closeTransaction(false);
- }
-
- /**
- * @hide
- */
- public static void closeTransactionSync() {
- closeTransaction(true);
+ synchronized(SurfaceControl.class) {
+ if (sTransactionNestCount == 0) {
+ Log.e(TAG,
+ "Call to SurfaceControl.closeTransaction without matching openTransaction");
+ } else if (--sTransactionNestCount > 0) {
+ return;
+ }
+ sGlobalTransaction.apply();
+ }
}
/**
diff --git a/core/java/android/view/textclassifier/ConfigParser.java b/core/java/android/view/textclassifier/ConfigParser.java
index 8e0bdf9..b475412 100644
--- a/core/java/android/view/textclassifier/ConfigParser.java
+++ b/core/java/android/view/textclassifier/ConfigParser.java
@@ -33,6 +33,10 @@
private final KeyValueListParser mParser;
+ // TODO: Re-enable DeviceConfig when it has reasonable performance or just delete the
+ // option of using DeviceConfig entirely.
+ static final boolean ENABLE_DEVICE_CONFIG = false;
+
public ConfigParser(@Nullable String textClassifierConstants) {
final KeyValueListParser parser = new KeyValueListParser(',');
try {
@@ -48,39 +52,55 @@
* Reads a boolean flag.
*/
public boolean getBoolean(String key, boolean defaultValue) {
- return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- key,
- mParser.getBoolean(key, defaultValue));
+ if (ENABLE_DEVICE_CONFIG) {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ key,
+ mParser.getBoolean(key, defaultValue));
+ } else {
+ return mParser.getBoolean(key, defaultValue);
+ }
}
/**
* Reads an integer flag.
*/
public int getInt(String key, int defaultValue) {
- return DeviceConfig.getInt(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- key,
- mParser.getInt(key, defaultValue));
+ if (ENABLE_DEVICE_CONFIG) {
+ return DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ key,
+ mParser.getInt(key, defaultValue));
+ } else {
+ return mParser.getInt(key, defaultValue);
+ }
}
/**
* Reads a float flag.
*/
public float getFloat(String key, float defaultValue) {
- return DeviceConfig.getFloat(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- key,
- mParser.getFloat(key, defaultValue));
+ if (ENABLE_DEVICE_CONFIG) {
+ return DeviceConfig.getFloat(
+ DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ key,
+ mParser.getFloat(key, defaultValue));
+ } else {
+ return mParser.getFloat(key, defaultValue);
+ }
}
/**
* Reads a string flag.
*/
public String getString(String key, String defaultValue) {
- return DeviceConfig.getString(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- key,
- mParser.getString(key, defaultValue));
+ if (ENABLE_DEVICE_CONFIG) {
+ return DeviceConfig.getString(
+ DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ key,
+ mParser.getString(key, defaultValue));
+ } else {
+ return mParser.getString(key, defaultValue);
+ }
}
}
diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
index 868cbb1..fa898c3 100644
--- a/core/java/android/view/textclassifier/TextClassificationManager.java
+++ b/core/java/android/view/textclassifier/TextClassificationManager.java
@@ -197,7 +197,9 @@
if (mSettingsObserver != null) {
getApplicationContext().getContentResolver()
.unregisterContentObserver(mSettingsObserver);
- DeviceConfig.removeOnPropertyChangedListener(mSettingsObserver);
+ if (ConfigParser.ENABLE_DEVICE_CONFIG) {
+ DeviceConfig.removeOnPropertyChangedListener(mSettingsObserver);
+ }
}
} finally {
super.finalize();
@@ -292,10 +294,12 @@
Settings.Global.getUriFor(Settings.Global.TEXT_CLASSIFIER_CONSTANTS),
false /* notifyForDescendants */,
this);
- DeviceConfig.addOnPropertyChangedListener(
- DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
- ActivityThread.currentApplication().getMainExecutor(),
- this);
+ if (ConfigParser.ENABLE_DEVICE_CONFIG) {
+ DeviceConfig.addOnPropertyChangedListener(
+ DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
+ ActivityThread.currentApplication().getMainExecutor(),
+ this);
+ }
}
@Override
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index cc7a7a3..a1d0cdc 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -942,8 +942,6 @@
if (isSendAction(in)) {
in.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
-
- in.fixUris(getUserId());
}
}
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 3811fe4..a5f055f 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -115,6 +115,7 @@
// At this point, innerIntent is not null. Otherwise, canForward would have returned
// false.
innerIntent.prepareToLeaveUser(callingUserId);
+ innerIntent.fixUris(callingUserId);
} else {
newIntent.prepareToLeaveUser(callingUserId);
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index f47469a..f671a75 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -509,10 +509,11 @@
@Nullable abstract String getAppSubLabelInternal();
private Context mCtx;
- protected PackageManager mPm;
- private final ApplicationInfo mAi;
private final int mIconDpi;
private final boolean mHasSubstitutePermission;
+ private final ApplicationInfo mAi;
+
+ protected PackageManager mPm;
TargetPresentationGetter(Context ctx, int iconDpi, ApplicationInfo ai) {
mCtx = ctx;
@@ -590,10 +591,10 @@
* Loads the icon and label for the provided ResolveInfo.
*/
@VisibleForTesting
- public static class ResolveInfoPresentationGetter extends TargetPresentationGetter {
+ public static class ResolveInfoPresentationGetter extends ActivityInfoPresentationGetter {
private final ResolveInfo mRi;
public ResolveInfoPresentationGetter(Context ctx, int iconDpi, ResolveInfo ri) {
- super(ctx, iconDpi, ri.activityInfo.applicationInfo);
+ super(ctx, iconDpi, ri.activityInfo);
mRi = ri;
}
@@ -611,6 +612,9 @@
+ "couldn't find resources for package", e);
}
+ // Fall back to ActivityInfo if no icon is found via ResolveInfo
+ if (dr == null) dr = super.getIconSubstituteInternal();
+
return dr;
}
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReader.java b/core/java/com/android/internal/os/KernelCpuThreadReader.java
index e4de158..3686048 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReader.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReader.java
@@ -92,24 +92,12 @@
/** Value returned when there was an error getting an integer ID value (e.g. PID, UID) */
private static final int ID_ERROR = -1;
- /** Thread ID used when reporting CPU used by other threads */
- private static final int OTHER_THREADS_ID = -1;
-
- /** Thread name used when reporting CPU used by other threads */
- private static final String OTHER_THREADS_NAME = "__OTHER_THREADS";
-
/**
* When checking whether to report data for a thread, we check the UID of the thread's owner
* against this predicate
*/
private Predicate<Integer> mUidPredicate;
- /**
- * If a thread has strictly less than {@code minimumTotalCpuUsageMillis} total CPU usage, it
- * will not be reported
- */
- private int mMinimumTotalCpuUsageMillis;
-
/** Where the proc filesystem is mounted */
private final Path mProcPath;
@@ -138,13 +126,11 @@
public KernelCpuThreadReader(
int numBuckets,
Predicate<Integer> uidPredicate,
- int minimumTotalCpuUsageMillis,
Path procPath,
Path initialTimeInStatePath,
Injector injector)
throws IOException {
mUidPredicate = uidPredicate;
- mMinimumTotalCpuUsageMillis = minimumTotalCpuUsageMillis;
mProcPath = procPath;
mProcTimeInStateReader = new ProcTimeInStateReader(initialTimeInStatePath);
mInjector = injector;
@@ -157,13 +143,11 @@
* @return the reader, null if an exception was thrown during creation
*/
@Nullable
- public static KernelCpuThreadReader create(
- int numBuckets, Predicate<Integer> uidPredicate, int minimumTotalCpuUsageMillis) {
+ public static KernelCpuThreadReader create(int numBuckets, Predicate<Integer> uidPredicate) {
try {
return new KernelCpuThreadReader(
numBuckets,
uidPredicate,
- minimumTotalCpuUsageMillis,
DEFAULT_PROC_PATH,
DEFAULT_INITIAL_TIME_IN_STATE_PATH,
new Injector());
@@ -259,18 +243,6 @@
}
/**
- * If a thread has strictly less than {@code minimumTotalCpuUsageMillis} total CPU usage, it
- * will not be reported
- */
- void setMinimumTotalCpuUsageMillis(int minimumTotalCpuUsageMillis) {
- if (minimumTotalCpuUsageMillis < 0) {
- Slog.w(TAG, "Negative minimumTotalCpuUsageMillis: " + minimumTotalCpuUsageMillis);
- return;
- }
- mMinimumTotalCpuUsageMillis = minimumTotalCpuUsageMillis;
- }
-
- /**
* Read all of the CPU usage statistics for each child thread of a process
*
* @param processPath the {@code /proc} path of the thread
@@ -292,7 +264,6 @@
+ uid);
}
- int[] filteredThreadsCpuUsage = null;
final Path allThreadsPath = processPath.resolve("task");
final ArrayList<ThreadCpuUsage> threadCpuUsages = new ArrayList<>();
try (DirectoryStream<Path> threadPaths = Files.newDirectoryStream(allThreadsPath)) {
@@ -301,14 +272,6 @@
if (threadCpuUsage == null) {
continue;
}
- if (mMinimumTotalCpuUsageMillis > totalCpuUsage(threadCpuUsage.usageTimesMillis)) {
- if (filteredThreadsCpuUsage == null) {
- filteredThreadsCpuUsage = new int[mFrequenciesKhz.length];
- }
- filteredThreadsCpuUsage =
- sumCpuUsage(filteredThreadsCpuUsage, threadCpuUsage.usageTimesMillis);
- continue;
- }
threadCpuUsages.add(threadCpuUsage);
}
} catch (IOException e) {
@@ -320,14 +283,6 @@
if (threadCpuUsages.isEmpty()) {
return null;
}
-
- // Add the filtered out thread CPU usage under an "other threads" ThreadCpuUsage
- if (filteredThreadsCpuUsage != null) {
- threadCpuUsages.add(
- new ThreadCpuUsage(
- OTHER_THREADS_ID, OTHER_THREADS_NAME, filteredThreadsCpuUsage));
- }
-
if (DEBUG) {
Slog.d(TAG, "Read CPU usage of " + threadCpuUsages.size() + " threads");
}
@@ -404,25 +359,6 @@
}
}
- /** Get the sum of all CPU usage across all frequencies */
- @SuppressWarnings("ForLoopReplaceableByForEach")
- private static int totalCpuUsage(int[] cpuUsage) {
- int total = 0;
- for (int i = 0; i < cpuUsage.length; i++) {
- total += cpuUsage[i];
- }
- return total;
- }
-
- /** Add two CPU frequency usages together */
- private static int[] sumCpuUsage(int[] a, int[] b) {
- int[] summed = new int[a.length];
- for (int i = 0; i < a.length; i++) {
- summed[i] = a[i] + b[i];
- }
- return summed;
- }
-
/** Puts frequencies and usage times into buckets */
@VisibleForTesting
public static class FrequencyBucketCreator {
@@ -553,9 +489,10 @@
public final int processId;
public final String processName;
public final int uid;
- public final ArrayList<ThreadCpuUsage> threadCpuUsages;
+ public ArrayList<ThreadCpuUsage> threadCpuUsages;
- ProcessCpuUsage(
+ @VisibleForTesting
+ public ProcessCpuUsage(
int processId,
String processName,
int uid,
@@ -571,9 +508,10 @@
public static class ThreadCpuUsage {
public final int threadId;
public final String threadName;
- public final int[] usageTimesMillis;
+ public int[] usageTimesMillis;
- ThreadCpuUsage(int threadId, String threadName, int[] usageTimesMillis) {
+ @VisibleForTesting
+ public ThreadCpuUsage(int threadId, String threadName, int[] usageTimesMillis) {
this.threadId = threadId;
this.threadName = threadName;
this.usageTimesMillis = usageTimesMillis;
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReaderDiff.java b/core/java/com/android/internal/os/KernelCpuThreadReaderDiff.java
new file mode 100644
index 0000000..ffdc33c
--- /dev/null
+++ b/core/java/com/android/internal/os/KernelCpuThreadReaderDiff.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.annotation.Nullable;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Delegates per-thread CPU collection to {@link KernelCpuThreadReader}, and calculates the
+ * difference between CPU usage at each call of {@link #getProcessCpuUsageDiffed()}.
+ *
+ * <p>Some notes on the diff calculation:
+ *
+ * <ul>
+ * <li>The diffing is done between each call of {@link #getProcessCpuUsageDiffed()}, i.e. call N
+ * of this method will return CPU used by threads between call N-1 and N.
+ * <li>The first call of {@link #getProcessCpuUsageDiffed()} will return no processes ("first
+ * call" is the first call in the lifetime of a {@link KernelCpuThreadReaderDiff} object).
+ * <li>If a thread does not exist at call N, but does exist at call N+1, the diff will assume that
+ * the CPU usage at call N was zero. Thus, the diff reported will be equivalent to the value
+ * returned by {@link KernelCpuThreadReader#getProcessCpuUsage()} at call N+1.
+ * <li>If an error occurs in {@link KernelCpuThreadReader} at call N, we will return no
+ * information for CPU usage between call N-1 and N (as we don't know the start value) and
+ * between N and N+1 (as we don't know the end value). Assuming all other calls are
+ * successful, the next call to return data will be N+2, for the period between N+1 and N+2.
+ * <li>If an error occurs in this class (but not in {@link KernelCpuThreadReader}) at call N, the
+ * data will only be dropped for call N, as we can still use the CPU data for the surrounding
+ * calls.
+ * </ul>
+ *
+ * <p>Additionally to diffing, this class also contains logic for thresholding reported threads. A
+ * thread will not be reported unless its total CPU usage is at least equal to the value set in
+ * {@link #setMinimumTotalCpuUsageMillis}. Filtered thread CPU usage is summed and reported under
+ * one "other threads" thread. This reduces the cardinality of the {@link
+ * #getProcessCpuUsageDiffed()} result.
+ *
+ * <p>Thresholding is done in this class, instead of {@link KernelCpuThreadReader}, and instead of
+ * WestWorld, because the thresholding should be done after diffing, not before. This is because of
+ * two issues with thresholding before diffing:
+ *
+ * <ul>
+ * <li>We would threshold less and less threads as thread uptime increases.
+ * <li>We would encounter errors as the filtered threads become unfiltered, as the "other threads"
+ * result could have negative diffs, and the newly unfiltered threads would have incorrect
+ * diffs that include CPU usage from when they were filtered.
+ * </ul>
+ *
+ * @hide Only for use within the system server
+ */
+@SuppressWarnings("ForLoopReplaceableByForEach")
+public class KernelCpuThreadReaderDiff {
+ private static final String TAG = "KernelCpuThreadReaderDiff";
+
+ /** Thread ID used when reporting CPU used by other threads */
+ private static final int OTHER_THREADS_ID = -1;
+
+ /** Thread name used when reporting CPU used by other threads */
+ private static final String OTHER_THREADS_NAME = "__OTHER_THREADS";
+
+ private final KernelCpuThreadReader mReader;
+
+ /**
+ * CPU usage from the previous call of {@link #getProcessCpuUsageDiffed()}. Null if there was no
+ * previous call, or if the previous call failed
+ *
+ * <p>Maps the thread's identifier to the per-frequency CPU usage for that thread. The
+ * identifier contains the minimal amount of information to identify a thread (see {@link
+ * ThreadKey} for more information), thus reducing memory consumption.
+ */
+ @Nullable private Map<ThreadKey, int[]> mPreviousCpuUsage;
+
+ /**
+ * If a thread has strictly less than {@code minimumTotalCpuUsageMillis} total CPU usage, it
+ * will not be reported
+ */
+ private int mMinimumTotalCpuUsageMillis;
+
+ @VisibleForTesting
+ public KernelCpuThreadReaderDiff(KernelCpuThreadReader reader, int minimumTotalCpuUsageMillis) {
+ mReader = reader;
+ mMinimumTotalCpuUsageMillis = minimumTotalCpuUsageMillis;
+ mPreviousCpuUsage = null;
+ }
+
+ /**
+ * Returns the difference in CPU usage since the last time this method was called.
+ *
+ * @see KernelCpuThreadReader#getProcessCpuUsage()
+ */
+ @Nullable
+ public ArrayList<KernelCpuThreadReader.ProcessCpuUsage> getProcessCpuUsageDiffed() {
+ Map<ThreadKey, int[]> newCpuUsage = null;
+ try {
+ // Get the thread CPU usage and index them by ThreadKey
+ final ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsages =
+ mReader.getProcessCpuUsage();
+ newCpuUsage = createCpuUsageMap(processCpuUsages);
+ // If there is no previous CPU usage, return nothing
+ if (mPreviousCpuUsage == null) {
+ return null;
+ }
+
+ // Do diffing and thresholding for each process
+ for (int i = 0; i < processCpuUsages.size(); i++) {
+ KernelCpuThreadReader.ProcessCpuUsage processCpuUsage = processCpuUsages.get(i);
+ changeToDiffs(mPreviousCpuUsage, processCpuUsage);
+ applyThresholding(processCpuUsage);
+ }
+ return processCpuUsages;
+ } finally {
+ // Always update the previous CPU usage. If we haven't got an update, it will be set to
+ // null, so the next call knows there no previous values
+ mPreviousCpuUsage = newCpuUsage;
+ }
+ }
+
+ /** @see KernelCpuThreadReader#getCpuFrequenciesKhz() */
+ @Nullable
+ public int[] getCpuFrequenciesKhz() {
+ return mReader.getCpuFrequenciesKhz();
+ }
+
+ /**
+ * If a thread has strictly less than {@code minimumTotalCpuUsageMillis} total CPU usage, it
+ * will not be reported
+ */
+ void setMinimumTotalCpuUsageMillis(int minimumTotalCpuUsageMillis) {
+ if (minimumTotalCpuUsageMillis < 0) {
+ Slog.w(TAG, "Negative minimumTotalCpuUsageMillis: " + minimumTotalCpuUsageMillis);
+ return;
+ }
+ mMinimumTotalCpuUsageMillis = minimumTotalCpuUsageMillis;
+ }
+
+ /**
+ * Create a map of a thread's identifier to a thread's CPU usage. Used for fast indexing when
+ * calculating diffs
+ */
+ private static Map<ThreadKey, int[]> createCpuUsageMap(
+ List<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsages) {
+ final Map<ThreadKey, int[]> cpuUsageMap = new ArrayMap<>();
+ for (int i = 0; i < processCpuUsages.size(); i++) {
+ KernelCpuThreadReader.ProcessCpuUsage processCpuUsage = processCpuUsages.get(i);
+ for (int j = 0; j < processCpuUsage.threadCpuUsages.size(); j++) {
+ KernelCpuThreadReader.ThreadCpuUsage threadCpuUsage =
+ processCpuUsage.threadCpuUsages.get(j);
+ cpuUsageMap.put(
+ new ThreadKey(
+ processCpuUsage.processId,
+ threadCpuUsage.threadId,
+ processCpuUsage.processName,
+ threadCpuUsage.threadName),
+ threadCpuUsage.usageTimesMillis);
+ }
+ }
+ return cpuUsageMap;
+ }
+
+ /**
+ * Calculate the difference in per-frequency CPU usage for all threads in a process
+ *
+ * @param previousCpuUsage CPU usage from the last call, the base of the diff
+ * @param processCpuUsage CPU usage from the current call, this value is modified to contain the
+ * diffed values
+ */
+ private static void changeToDiffs(
+ Map<ThreadKey, int[]> previousCpuUsage,
+ KernelCpuThreadReader.ProcessCpuUsage processCpuUsage) {
+ for (int i = 0; i < processCpuUsage.threadCpuUsages.size(); i++) {
+ KernelCpuThreadReader.ThreadCpuUsage threadCpuUsage =
+ processCpuUsage.threadCpuUsages.get(i);
+ final ThreadKey key =
+ new ThreadKey(
+ processCpuUsage.processId,
+ threadCpuUsage.threadId,
+ processCpuUsage.processName,
+ threadCpuUsage.threadName);
+ int[] previous = previousCpuUsage.get(key);
+ if (previous == null) {
+ // If there's no previous CPU usage, assume that it's zero
+ previous = new int[threadCpuUsage.usageTimesMillis.length];
+ }
+ threadCpuUsage.usageTimesMillis =
+ cpuTimeDiff(threadCpuUsage.usageTimesMillis, previous);
+ }
+ }
+
+ /**
+ * Filter out any threads with less than {@link #mMinimumTotalCpuUsageMillis} total CPU usage
+ *
+ * <p>The sum of the CPU usage of filtered threads is added under a single thread, labeled with
+ * {@link #OTHER_THREADS_ID} and {@link #OTHER_THREADS_NAME}.
+ *
+ * @param processCpuUsage CPU usage to apply thresholding to, this value is modified to change
+ * the threads it contains
+ */
+ private void applyThresholding(KernelCpuThreadReader.ProcessCpuUsage processCpuUsage) {
+ int[] filteredThreadsCpuUsage = null;
+ final ArrayList<KernelCpuThreadReader.ThreadCpuUsage> thresholded = new ArrayList<>();
+ for (int i = 0; i < processCpuUsage.threadCpuUsages.size(); i++) {
+ KernelCpuThreadReader.ThreadCpuUsage threadCpuUsage =
+ processCpuUsage.threadCpuUsages.get(i);
+ if (mMinimumTotalCpuUsageMillis > totalCpuUsage(threadCpuUsage.usageTimesMillis)) {
+ if (filteredThreadsCpuUsage == null) {
+ filteredThreadsCpuUsage = new int[threadCpuUsage.usageTimesMillis.length];
+ }
+ addToCpuUsage(filteredThreadsCpuUsage, threadCpuUsage.usageTimesMillis);
+ continue;
+ }
+ thresholded.add(threadCpuUsage);
+ }
+ if (filteredThreadsCpuUsage != null) {
+ thresholded.add(
+ new KernelCpuThreadReader.ThreadCpuUsage(
+ OTHER_THREADS_ID, OTHER_THREADS_NAME, filteredThreadsCpuUsage));
+ }
+ processCpuUsage.threadCpuUsages = thresholded;
+ }
+
+ /** Get the sum of all CPU usage across all frequencies */
+ private static int totalCpuUsage(int[] cpuUsage) {
+ int total = 0;
+ for (int i = 0; i < cpuUsage.length; i++) {
+ total += cpuUsage[i];
+ }
+ return total;
+ }
+
+ /** Add two CPU frequency usages together */
+ private static void addToCpuUsage(int[] a, int[] b) {
+ for (int i = 0; i < a.length; i++) {
+ a[i] += b[i];
+ }
+ }
+
+ /** Subtract two CPU frequency usages from each other */
+ private static int[] cpuTimeDiff(int[] a, int[] b) {
+ int[] difference = new int[a.length];
+ for (int i = 0; i < a.length; i++) {
+ difference[i] = a[i] - b[i];
+ }
+ return difference;
+ }
+
+ /**
+ * Identifies a thread
+ *
+ * <p>Only stores the minimum amount of information to identify a thread. This includes the
+ * PID/TID, but as both are recycled as processes/threads end and begin, we also store the hash
+ * of the name of the process/thread.
+ */
+ private static class ThreadKey {
+ private final int mProcessId;
+ private final int mThreadId;
+ private final int mProcessNameHash;
+ private final int mThreadNameHash;
+
+ ThreadKey(int processId, int threadId, String processName, String threadName) {
+ this.mProcessId = processId;
+ this.mThreadId = threadId;
+ // Only store the hash to reduce memory consumption
+ this.mProcessNameHash = Objects.hash(processName);
+ this.mThreadNameHash = Objects.hash(threadName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mProcessId, mThreadId, mProcessNameHash, mThreadNameHash);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ThreadKey)) {
+ return false;
+ }
+ ThreadKey other = (ThreadKey) obj;
+ return mProcessId == other.mProcessId
+ && mThreadId == other.mThreadId
+ && mProcessNameHash == other.mProcessNameHash
+ && mThreadNameHash == other.mThreadNameHash;
+ }
+ }
+}
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java b/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
index 3851ce6..f8c0d9e 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
@@ -67,12 +67,14 @@
@Nullable private final KernelCpuThreadReader mKernelCpuThreadReader;
+ @Nullable private final KernelCpuThreadReaderDiff mKernelCpuThreadReaderDiff;
+
/**
* @return returns a created {@link KernelCpuThreadReader} that will be modified by any change
* in settings, returns null if creation failed
*/
@Nullable
- public static KernelCpuThreadReader getSettingsModifiedReader(Context context) {
+ public static KernelCpuThreadReaderDiff getSettingsModifiedReader(Context context) {
// Create the observer
KernelCpuThreadReaderSettingsObserver settingsObserver =
new KernelCpuThreadReaderSettingsObserver(context);
@@ -82,7 +84,7 @@
.registerContentObserver(
settingsUri, false, settingsObserver, UserHandle.USER_SYSTEM);
// Return the observer's reader
- return settingsObserver.mKernelCpuThreadReader;
+ return settingsObserver.mKernelCpuThreadReaderDiff;
}
private KernelCpuThreadReaderSettingsObserver(Context context) {
@@ -90,9 +92,10 @@
mContext = context;
mKernelCpuThreadReader =
KernelCpuThreadReader.create(
- NUM_BUCKETS_DEFAULT,
- UidPredicate.fromString(COLLECTED_UIDS_DEFAULT),
- MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT);
+ NUM_BUCKETS_DEFAULT, UidPredicate.fromString(COLLECTED_UIDS_DEFAULT));
+ mKernelCpuThreadReaderDiff =
+ new KernelCpuThreadReaderDiff(
+ mKernelCpuThreadReader, MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT);
}
@Override
@@ -130,7 +133,7 @@
mKernelCpuThreadReader.setNumBuckets(
parser.getInt(NUM_BUCKETS_SETTINGS_KEY, NUM_BUCKETS_DEFAULT));
mKernelCpuThreadReader.setUidPredicate(uidPredicate);
- mKernelCpuThreadReader.setMinimumTotalCpuUsageMillis(
+ mKernelCpuThreadReaderDiff.setMinimumTotalCpuUsageMillis(
parser.getInt(
MINIMUM_TOTAL_CPU_USAGE_MILLIS_SETTINGS_KEY,
MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT));
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index d124feb..b47097d 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -455,6 +455,8 @@
optional SettingProto show_angle_in_use_dialog = 15;
// Game Driver - List of libraries in sphal accessible by Game Driver
optional SettingProto game_driver_sphal_libraries = 16;
+ // ANGLE - External package containing ANGLE libraries
+ optional SettingProto angle_debug_package = 17;
}
optional Gpu gpu = 59;
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 0673e75..c36ca82 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -131,7 +131,6 @@
Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS,
Settings.Global.AUTOMATIC_POWER_SAVE_MODE,
Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED,
- Settings.Global.BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST,
Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY,
Settings.Global.BROADCAST_BG_CONSTANTS,
Settings.Global.BROADCAST_FG_CONSTANTS,
@@ -488,6 +487,7 @@
Settings.Global.GPU_DEBUG_APP,
Settings.Global.GPU_DEBUG_LAYERS,
Settings.Global.GPU_DEBUG_LAYERS_GLES,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_DEBUG_PACKAGE,
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE,
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS,
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES,
diff --git a/core/tests/coretests/src/android/view/textclassifier/ConfigParserTest.java b/core/tests/coretests/src/android/view/textclassifier/ConfigParserTest.java
index 1b3c724..f1cfe24 100644
--- a/core/tests/coretests/src/android/view/textclassifier/ConfigParserTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/ConfigParserTest.java
@@ -26,6 +26,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -58,6 +59,7 @@
}
@Test
+ @Ignore // TODO: Re-enable once ConfigParser#ENABLE_DEVICE_CONFIG is finalized
public void getBoolean_deviceConfig() {
DeviceConfig.setProperty(
DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
@@ -77,6 +79,7 @@
}
@Test
+ @Ignore // TODO: Re-enable once ConfigParser#ENABLE_DEVICE_CONFIG is finalized
public void getInt_deviceConfig() {
DeviceConfig.setProperty(
DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
@@ -94,6 +97,7 @@
}
@Test
+ @Ignore // TODO: Re-enable once ConfigParser#ENABLE_DEVICE_CONFIG is finalized
public void getFloat_deviceConfig() {
DeviceConfig.setProperty(
DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
@@ -111,6 +115,7 @@
}
@Test
+ @Ignore // TODO: Re-enable once ConfigParser#ENABLE_DEVICE_CONFIG is finalized
public void getString_deviceConfig() {
DeviceConfig.setProperty(
DeviceConfig.NAMESPACE_TEXTCLASSIFIER,
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderDiffTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderDiffTest.java
new file mode 100644
index 0000000..460fe47
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderDiffTest.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mockitoSession;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import static java.util.stream.Collectors.toList;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KernelCpuThreadReaderDiffTest {
+
+ private MockitoSession mMockingSessions;
+ @Mock KernelCpuThreadReader mMockReader;
+
+ @Before
+ public void setUp() {
+ mMockingSessions = mockitoSession().initMocks(this).startMocking();
+ }
+
+ @After
+ public void tearDown() {
+ if (mMockingSessions != null) {
+ mMockingSessions.finishMocking();
+ }
+ }
+
+ @Test
+ public void test_empty() {
+ KernelCpuThreadReaderDiff kernelCpuThreadReaderDiff =
+ new KernelCpuThreadReaderDiff(mMockReader, 0);
+ assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isNull();
+ assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isEmpty();
+ }
+
+ @Test
+ public void test_simple() {
+ when(mMockReader.getProcessCpuUsage())
+ .thenReturn(createProcess(new int[] {100, 100, 100}))
+ .thenReturn(createProcess(new int[] {150, 160, 170}));
+ KernelCpuThreadReaderDiff kernelCpuThreadReaderDiff =
+ new KernelCpuThreadReaderDiff(mMockReader, 0);
+ assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isNull();
+ assertThat(cpuUsages(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()))
+ .containsExactly(Arrays.asList(50, 60, 70));
+ }
+
+ @Test
+ public void test_failure() {
+ when(mMockReader.getProcessCpuUsage())
+ .thenReturn(createProcess(new int[] {1}))
+ .thenReturn(createProcess(new int[] {2}))
+ .thenThrow(new RuntimeException())
+ .thenReturn(createProcess(new int[] {4}))
+ .thenReturn(createProcess(new int[] {6}));
+ KernelCpuThreadReaderDiff kernelCpuThreadReaderDiff =
+ new KernelCpuThreadReaderDiff(mMockReader, 0);
+ assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isNull();
+ assertThat(cpuUsages(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()))
+ .containsExactly(Collections.singletonList(1));
+ assertThrows(
+ RuntimeException.class,
+ () -> cpuUsages(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()));
+ assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isNull();
+ assertThat(cpuUsages(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()))
+ .containsExactly(Collections.singletonList(2));
+ }
+
+ @Test
+ public void test_twoFailures() {
+ when(mMockReader.getProcessCpuUsage())
+ .thenReturn(createProcess(new int[] {1}))
+ .thenReturn(createProcess(new int[] {2}))
+ .thenThrow(new RuntimeException())
+ .thenThrow(new RuntimeException())
+ .thenReturn(createProcess(new int[] {4}))
+ .thenReturn(createProcess(new int[] {6}));
+ KernelCpuThreadReaderDiff kernelCpuThreadReaderDiff =
+ new KernelCpuThreadReaderDiff(mMockReader, 0);
+ assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isNull();
+ assertThat(cpuUsages(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()))
+ .containsExactly(Collections.singletonList(1));
+ assertThrows(
+ RuntimeException.class,
+ () -> cpuUsages(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()));
+ assertThrows(
+ RuntimeException.class,
+ () -> cpuUsages(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()));
+ assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isNull();
+ assertThat(cpuUsages(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()))
+ .containsExactly(Collections.singletonList(2));
+ }
+
+ @Test
+ public void test_negativeDiff() {
+ when(mMockReader.getProcessCpuUsage())
+ .thenReturn(createProcess(new int[] {2}))
+ .thenReturn(createProcess(new int[] {1}));
+ KernelCpuThreadReaderDiff kernelCpuThreadReaderDiff =
+ new KernelCpuThreadReaderDiff(mMockReader, 0);
+ assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isNull();
+ assertThat(cpuUsages(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()))
+ .containsExactly(Collections.singletonList(-1));
+ }
+
+ @Test
+ public void test_threshold() {
+ when(mMockReader.getProcessCpuUsage())
+ .thenReturn(createProcess(new int[] {1}))
+ .thenReturn(createProcess(new int[] {10}))
+ .thenReturn(createProcess(new int[] {12}))
+ .thenReturn(createProcess(new int[] {20}));
+ KernelCpuThreadReaderDiff kernelCpuThreadReaderDiff =
+ new KernelCpuThreadReaderDiff(mMockReader, 5);
+ assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isNull();
+
+ ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processes1 =
+ kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed();
+ assertThat(cpuUsages(processes1)).containsExactly(Collections.singletonList(9));
+ assertThat(threadNames(processes1)).containsExactly("thread0");
+
+ ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processes2 =
+ kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed();
+ assertThat(cpuUsages(processes2)).containsExactly(Collections.singletonList(2));
+ assertThat(threadNames(processes2)).containsExactly("__OTHER_THREADS");
+
+ ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processes3 =
+ kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed();
+ assertThat(cpuUsages(processes3)).containsExactly(Collections.singletonList(8));
+ assertThat(threadNames(processes3)).containsExactly("thread0");
+ }
+
+ @Test
+ public void test_newThread() {
+ when(mMockReader.getProcessCpuUsage())
+ .thenReturn(createProcess(new int[] {1}))
+ .thenReturn(createProcess(new int[] {2}))
+ .thenReturn(createProcess(new int[] {4}, new int[] {5}));
+ KernelCpuThreadReaderDiff kernelCpuThreadReaderDiff =
+ new KernelCpuThreadReaderDiff(mMockReader, 0);
+ assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isNull();
+
+ ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processes1 =
+ kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed();
+ assertThat(cpuUsages(processes1)).containsExactly(Collections.singletonList(1));
+ assertThat(threadNames(processes1)).containsExactly("thread0");
+
+ ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processes2 =
+ kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed();
+ assertThat(cpuUsages(processes2))
+ .containsExactly(Collections.singletonList(2), Collections.singletonList(5));
+ assertThat(threadNames(processes2)).containsExactly("thread0", "thread1");
+ }
+
+ @Test
+ public void test_stoppedThread() {
+ when(mMockReader.getProcessCpuUsage())
+ .thenReturn(createProcess(new int[] {1}, new int[] {1}))
+ .thenReturn(createProcess(new int[] {2}, new int[] {3}))
+ .thenReturn(createProcess(new int[] {4}));
+ KernelCpuThreadReaderDiff kernelCpuThreadReaderDiff =
+ new KernelCpuThreadReaderDiff(mMockReader, 0);
+ assertThat(kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed()).isNull();
+
+ ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processes1 =
+ kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed();
+ assertThat(cpuUsages(processes1))
+ .containsExactly(Collections.singletonList(1), Collections.singletonList(2));
+ assertThat(threadNames(processes1)).containsExactly("thread0", "thread1");
+
+ ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processes2 =
+ kernelCpuThreadReaderDiff.getProcessCpuUsageDiffed();
+ assertThat(cpuUsages(processes2)).containsExactly(Collections.singletonList(2));
+ assertThat(threadNames(processes2)).containsExactly("thread0");
+ }
+
+ private ArrayList<KernelCpuThreadReader.ProcessCpuUsage> createProcess(
+ int[]... cpuUsageMillis) {
+ ArrayList<KernelCpuThreadReader.ThreadCpuUsage> threadCpuUsages = new ArrayList<>();
+ for (int i = 0; i < cpuUsageMillis.length; i++) {
+ int[] cpuUsage = cpuUsageMillis[i];
+ threadCpuUsages.add(
+ new KernelCpuThreadReader.ThreadCpuUsage(0, "thread" + i, cpuUsage));
+ }
+ return new ArrayList<>(
+ Collections.singletonList(
+ new KernelCpuThreadReader.ProcessCpuUsage(
+ 0, "process", 0, threadCpuUsages)));
+ }
+
+ private Collection<Collection<Integer>> cpuUsages(
+ Collection<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsages) {
+ return processCpuUsages.stream()
+ .flatMap(p -> p.threadCpuUsages.stream())
+ .map(t -> Arrays.stream(t.usageTimesMillis).boxed().collect(toList()))
+ .collect(toList());
+ }
+
+ private Collection<String> threadNames(
+ Collection<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsages) {
+ return processCpuUsages.stream()
+ .flatMap(p -> p.threadCpuUsages.stream())
+ .map(t -> t.threadName)
+ .collect(toList());
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
index e9cad0a..d43989c 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java
@@ -125,7 +125,7 @@
// Get thread data from KernelCpuThreadReader
final KernelCpuThreadReader kernelCpuThreadReader =
- KernelCpuThreadReader.create(8, uid -> uid == Process.myUid(), 0);
+ KernelCpuThreadReader.create(8, uid -> uid == Process.myUid());
assertNotNull(kernelCpuThreadReader);
kernelCpuThreadReader.setUidPredicate(uid -> uid == Process.myUid());
final Optional<ProcessCpuUsage> currentProcessCpuUsage =
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
index 61209e2..ae847c1 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
@@ -84,7 +84,6 @@
final KernelCpuThreadReader kernelCpuThreadReader = new KernelCpuThreadReader(
8,
uidPredicate,
- 0,
mProcDirectory.toPath(),
mProcDirectory.toPath().resolve(uids[0] + "/task/" + uids[0] + "/time_in_state"),
processUtils);
@@ -103,90 +102,6 @@
}
}
- @Test
- public void testReader_filtersLowUsage() throws IOException {
- int[] uids = new int[]{0, 1, 2, 3, 4};
- int[] cpuUsage = new int[]{10, 0, 2, 100, 3};
- int[] expectedUids = new int[]{0, 3, 4};
- Predicate<Integer> uidPredicate = uid -> true;
- KernelCpuThreadReader.Injector processUtils =
- new KernelCpuThreadReader.Injector() {
- @Override
- public int getUidForPid(int pid) {
- return pid;
- }
- };
-
- for (int i = 0; i < uids.length; i++) {
- int uid = uids[i];
- setupDirectory(
- mProcDirectory.toPath().resolve(String.valueOf(uid)),
- new int[]{uid * 10},
- "process" + uid,
- new String[]{"thread" + uid},
- new int[]{1000},
- new int[][]{{cpuUsage[i]}});
- }
- final KernelCpuThreadReader kernelCpuThreadReader = new KernelCpuThreadReader(
- 8,
- uidPredicate,
- 30,
- mProcDirectory.toPath(),
- mProcDirectory.toPath().resolve(uids[0] + "/task/" + uids[0] + "/time_in_state"),
- processUtils);
- ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsageByUids =
- kernelCpuThreadReader.getProcessCpuUsage();
- processCpuUsageByUids.sort(Comparator.comparing(usage -> usage.uid));
-
- assertEquals(expectedUids.length, processCpuUsageByUids.size());
- for (int i = 0; i < expectedUids.length; i++) {
- KernelCpuThreadReader.ProcessCpuUsage processCpuUsage =
- processCpuUsageByUids.get(i);
- assertEquals(expectedUids[i], processCpuUsage.uid);
- }
-
- }
-
- @Test
- public void testReader_otherThreads() throws IOException {
- final Path processPath = mProcDirectory.toPath().resolve("1000");
- setupDirectory(
- processPath,
- new int[]{1, 2, 3},
- "process",
- new String[]{"thread1", "thread2", "thread3"},
- new int[]{1000, 2000},
- new int[][]{{0, 100}, {10, 0}, {0, 300}});
- KernelCpuThreadReader.Injector injector =
- new KernelCpuThreadReader.Injector() {
- @Override
- public int getUidForPid(int pid) {
- return 0;
- }
- };
- final KernelCpuThreadReader kernelCpuThreadReader =
- new KernelCpuThreadReader(
- 8,
- uid -> true,
- 2000,
- mProcDirectory.toPath(),
- processPath.resolve("task/1/time_in_state"),
- injector);
- ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsages =
- kernelCpuThreadReader.getProcessCpuUsage();
- assertEquals(1, processCpuUsages.size());
- checkResults(
- processCpuUsages.get(0),
- kernelCpuThreadReader.getCpuFrequenciesKhz(),
- 0,
- 1000,
- new int[] {-1, 3},
- "process",
- new String[] {"__OTHER_THREADS", "thread3"},
- new int[] {1000, 2000},
- new int[][] {{10, 100}, {0, 300}});
- }
-
private void setupDirectory(Path processPath, int[] threadIds, String processName,
String[] threadNames, int[] cpuFrequencies, int[][] cpuTimes) throws IOException {
// Make /proc/$PID
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index bfce17c..f21fa5e 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -17,7 +17,6 @@
package android.security;
import android.annotation.UnsupportedAppUsage;
-import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.Application;
import android.app.KeyguardManager;
@@ -45,24 +44,24 @@
import android.security.keystore.KeyNotYetValidException;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
-import android.security.keystore.KeyProtection;
import android.security.keystore.KeystoreResponse;
-import android.security.keystore.StrongBoxUnavailableException;
import android.security.keystore.UserNotAuthenticatedException;
import android.util.Log;
+
import com.android.org.bouncycastle.asn1.ASN1InputStream;
import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import java.math.BigInteger;
+
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
+
import sun.security.util.ObjectIdentifier;
import sun.security.x509.AlgorithmId;
@@ -492,8 +491,9 @@
}
public boolean addRngEntropy(byte[] data, int flags) {
+ KeystoreResultPromise promise = new KeystoreResultPromise();
try {
- KeystoreResultPromise promise = new KeystoreResultPromise();
+ mBinder.asBinder().linkToDeath(promise, 0);
int errorCode = mBinder.addRngEntropy(promise, data, flags);
if (errorCode == NO_ERROR) {
return promise.getFuture().get().getErrorCode() == NO_ERROR;
@@ -506,6 +506,8 @@
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "AddRngEntropy completed with exception", e);
return false;
+ } finally {
+ mBinder.asBinder().unlinkToDeath(promise, 0);
}
}
@@ -537,7 +539,8 @@
}
private class KeyCharacteristicsPromise
- extends android.security.keystore.IKeystoreKeyCharacteristicsCallback.Stub {
+ extends android.security.keystore.IKeystoreKeyCharacteristicsCallback.Stub
+ implements IBinder.DeathRecipient {
final private CompletableFuture<KeyCharacteristicsCallbackResult> future =
new CompletableFuture<KeyCharacteristicsCallbackResult>();
@Override
@@ -550,19 +553,30 @@
public final CompletableFuture<KeyCharacteristicsCallbackResult> getFuture() {
return future;
}
+ @Override
+ public void binderDied() {
+ future.completeExceptionally(new RemoteException("Keystore died"));
+ }
};
private int generateKeyInternal(String alias, KeymasterArguments args, byte[] entropy, int uid,
int flags, KeyCharacteristics outCharacteristics)
throws RemoteException, ExecutionException, InterruptedException {
KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
- int error = mBinder.generateKey(promise, alias, args, entropy, uid, flags);
- if (error != NO_ERROR) {
- Log.e(TAG, "generateKeyInternal failed on request " + error);
- return error;
+ int error = NO_ERROR;
+ KeyCharacteristicsCallbackResult result = null;
+ try {
+ mBinder.asBinder().linkToDeath(promise, 0);
+ error = mBinder.generateKey(promise, alias, args, entropy, uid, flags);
+ if (error != NO_ERROR) {
+ Log.e(TAG, "generateKeyInternal failed on request " + error);
+ return error;
+ }
+ result = promise.getFuture().get();
+ } finally {
+ mBinder.asBinder().unlinkToDeath(promise, 0);
}
- KeyCharacteristicsCallbackResult result = promise.getFuture().get();
error = result.getKeystoreResponse().getErrorCode();
if (error != NO_ERROR) {
Log.e(TAG, "generateKeyInternal failed on response " + error);
@@ -604,10 +618,12 @@
public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
int uid, KeyCharacteristics outCharacteristics) {
+ KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
try {
+ mBinder.asBinder().linkToDeath(promise, 0);
clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
- KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
+
int error = mBinder.getKeyCharacteristics(promise, alias, clientId, appId, uid);
if (error != NO_ERROR) return error;
@@ -625,6 +641,8 @@
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "GetKeyCharacteristics completed with exception", e);
return SYSTEM_ERROR;
+ } finally {
+ mBinder.asBinder().unlinkToDeath(promise, 0);
}
}
@@ -637,17 +655,23 @@
int uid, int flags, KeyCharacteristics outCharacteristics)
throws RemoteException, ExecutionException, InterruptedException {
KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
- int error = mBinder.importKey(promise, alias, args, format, keyData, uid, flags);
- if (error != NO_ERROR) return error;
+ mBinder.asBinder().linkToDeath(promise, 0);
+ try {
+ int error = mBinder.importKey(promise, alias, args, format, keyData, uid, flags);
+ if (error != NO_ERROR) return error;
- KeyCharacteristicsCallbackResult result = promise.getFuture().get();
- error = result.getKeystoreResponse().getErrorCode();
- if (error != NO_ERROR) return error;
+ KeyCharacteristicsCallbackResult result = promise.getFuture().get();
- KeyCharacteristics characteristics = result.getKeyCharacteristics();
- if (characteristics == null) return SYSTEM_ERROR;
- outCharacteristics.shallowCopyFrom(characteristics);
- return NO_ERROR;
+ error = result.getKeystoreResponse().getErrorCode();
+ if (error != NO_ERROR) return error;
+
+ KeyCharacteristics characteristics = result.getKeyCharacteristics();
+ if (characteristics == null) return SYSTEM_ERROR;
+ outCharacteristics.shallowCopyFrom(characteristics);
+ return NO_ERROR;
+ } finally {
+ mBinder.asBinder().unlinkToDeath(promise, 0);
+ }
}
public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
@@ -738,18 +762,25 @@
KeyCharacteristics outCharacteristics)
throws RemoteException, ExecutionException, InterruptedException {
KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
- int error = mBinder.importWrappedKey(promise, wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
- maskingKey, args, rootSid, fingerprintSid);
- if (error != NO_ERROR) return error;
+ mBinder.asBinder().linkToDeath(promise, 0);
+ try {
+ KeyCharacteristicsCallbackResult result = null;
+ int error = mBinder.importWrappedKey(promise, wrappedKeyAlias, wrappedKey,
+ wrappingKeyAlias, maskingKey, args, rootSid, fingerprintSid);
+ if (error != NO_ERROR) return error;
- KeyCharacteristicsCallbackResult result = promise.getFuture().get();
- error = result.getKeystoreResponse().getErrorCode();
- if (error != NO_ERROR) return error;
+ KeyCharacteristicsCallbackResult esult = promise.getFuture().get();
- KeyCharacteristics characteristics = result.getKeyCharacteristics();
- if (characteristics == null) return SYSTEM_ERROR;
- outCharacteristics.shallowCopyFrom(characteristics);
- return NO_ERROR;
+ error = result.getKeystoreResponse().getErrorCode();
+ if (error != NO_ERROR) return error;
+
+ KeyCharacteristics characteristics = result.getKeyCharacteristics();
+ if (characteristics == null) return SYSTEM_ERROR;
+ outCharacteristics.shallowCopyFrom(characteristics);
+ return NO_ERROR;
+ } finally {
+ mBinder.asBinder().unlinkToDeath(promise, 0);
+ }
}
public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey,
@@ -776,7 +807,8 @@
}
private class ExportKeyPromise
- extends android.security.keystore.IKeystoreExportKeyCallback.Stub {
+ extends android.security.keystore.IKeystoreExportKeyCallback.Stub
+ implements IBinder.DeathRecipient {
final private CompletableFuture<ExportResult> future = new CompletableFuture<ExportResult>();
@Override
public void onFinished(ExportResult exportKeyResult) throws android.os.RemoteException {
@@ -785,14 +817,19 @@
public final CompletableFuture<ExportResult> getFuture() {
return future;
}
+ @Override
+ public void binderDied() {
+ future.completeExceptionally(new RemoteException("Keystore died"));
+ }
};
public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
KeymasterBlob appId, int uid) {
+ ExportKeyPromise promise = new ExportKeyPromise();
try {
+ mBinder.asBinder().linkToDeath(promise, 0);
clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
- ExportKeyPromise promise = new ExportKeyPromise();
int error = mBinder.exportKey(promise, alias, format, clientId, appId, uid);
if (error == NO_ERROR) {
return promise.getFuture().get();
@@ -805,6 +842,8 @@
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "ExportKey completed with exception", e);
return null;
+ } finally {
+ mBinder.asBinder().unlinkToDeath(promise, 0);
}
}
public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
@@ -813,7 +852,8 @@
}
private class OperationPromise
- extends android.security.keystore.IKeystoreOperationResultCallback.Stub {
+ extends android.security.keystore.IKeystoreOperationResultCallback.Stub
+ implements IBinder.DeathRecipient {
final private CompletableFuture<OperationResult> future = new CompletableFuture<OperationResult>();
@Override
public void onFinished(OperationResult operationResult) throws android.os.RemoteException {
@@ -822,14 +862,19 @@
public final CompletableFuture<OperationResult> getFuture() {
return future;
}
+ @Override
+ public void binderDied() {
+ future.completeExceptionally(new RemoteException("Keystore died"));
+ }
};
public OperationResult begin(String alias, int purpose, boolean pruneable,
KeymasterArguments args, byte[] entropy, int uid) {
+ OperationPromise promise = new OperationPromise();
try {
+ mBinder.asBinder().linkToDeath(promise, 0);
args = args != null ? args : new KeymasterArguments();
entropy = entropy != null ? entropy : new byte[0];
- OperationPromise promise = new OperationPromise();
int errorCode = mBinder.begin(promise, getToken(), alias, purpose, pruneable, args,
entropy, uid);
if (errorCode == NO_ERROR) {
@@ -843,6 +888,8 @@
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "Begin completed with exception", e);
return null;
+ } finally {
+ mBinder.asBinder().unlinkToDeath(promise, 0);
}
}
@@ -854,10 +901,11 @@
}
public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
+ OperationPromise promise = new OperationPromise();
try {
+ mBinder.asBinder().linkToDeath(promise, 0);
arguments = arguments != null ? arguments : new KeymasterArguments();
input = input != null ? input : new byte[0];
- OperationPromise promise = new OperationPromise();
int errorCode = mBinder.update(promise, token, arguments, input);
if (errorCode == NO_ERROR) {
return promise.getFuture().get();
@@ -870,16 +918,19 @@
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "Update completed with exception", e);
return null;
+ } finally {
+ mBinder.asBinder().unlinkToDeath(promise, 0);
}
}
public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature,
byte[] entropy) {
+ OperationPromise promise = new OperationPromise();
try {
+ mBinder.asBinder().linkToDeath(promise, 0);
arguments = arguments != null ? arguments : new KeymasterArguments();
entropy = entropy != null ? entropy : new byte[0];
signature = signature != null ? signature : new byte[0];
- OperationPromise promise = new OperationPromise();
int errorCode = mBinder.finish(promise, token, arguments, signature, entropy);
if (errorCode == NO_ERROR) {
return promise.getFuture().get();
@@ -892,6 +943,8 @@
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "Finish completed with exception", e);
return null;
+ } finally {
+ mBinder.asBinder().unlinkToDeath(promise, 0);
}
}
@@ -900,7 +953,8 @@
}
private class KeystoreResultPromise
- extends android.security.keystore.IKeystoreResponseCallback.Stub {
+ extends android.security.keystore.IKeystoreResponseCallback.Stub
+ implements IBinder.DeathRecipient {
final private CompletableFuture<KeystoreResponse> future = new CompletableFuture<KeystoreResponse>();
@Override
public void onFinished(KeystoreResponse keystoreResponse) throws android.os.RemoteException {
@@ -909,11 +963,16 @@
public final CompletableFuture<KeystoreResponse> getFuture() {
return future;
}
+ @Override
+ public void binderDied() {
+ future.completeExceptionally(new RemoteException("Keystore died"));
+ }
};
public int abort(IBinder token) {
+ KeystoreResultPromise promise = new KeystoreResultPromise();
try {
- KeystoreResultPromise promise = new KeystoreResultPromise();
+ mBinder.asBinder().linkToDeath(promise, 0);
int errorCode = mBinder.abort(promise, token);
if (errorCode == NO_ERROR) {
return promise.getFuture().get().getErrorCode();
@@ -926,6 +985,8 @@
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "Abort completed with exception", e);
return SYSTEM_ERROR;
+ } finally {
+ mBinder.asBinder().unlinkToDeath(promise, 0);
}
}
@@ -1035,7 +1096,8 @@
}
private class CertificateChainPromise
- extends android.security.keystore.IKeystoreCertificateChainCallback.Stub {
+ extends android.security.keystore.IKeystoreCertificateChainCallback.Stub
+ implements IBinder.DeathRecipient {
final private CompletableFuture<KeyAttestationCallbackResult> future = new CompletableFuture<KeyAttestationCallbackResult>();
@Override
public void onFinished(KeystoreResponse keystoreResponse,
@@ -1045,19 +1107,24 @@
public final CompletableFuture<KeyAttestationCallbackResult> getFuture() {
return future;
}
+ @Override
+ public void binderDied() {
+ future.completeExceptionally(new RemoteException("Keystore died"));
+ }
};
public int attestKey(
String alias, KeymasterArguments params, KeymasterCertificateChain outChain) {
+ CertificateChainPromise promise = new CertificateChainPromise();
try {
+ mBinder.asBinder().linkToDeath(promise, 0);
if (params == null) {
params = new KeymasterArguments();
}
if (outChain == null) {
outChain = new KeymasterCertificateChain();
}
- CertificateChainPromise promise = new CertificateChainPromise();
int error = mBinder.attestKey(promise, alias, params);
if (error != NO_ERROR) return error;
KeyAttestationCallbackResult result = promise.getFuture().get();
@@ -1072,18 +1139,21 @@
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "AttestKey completed with exception", e);
return SYSTEM_ERROR;
+ } finally {
+ mBinder.asBinder().unlinkToDeath(promise, 0);
}
}
public int attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain) {
+ CertificateChainPromise promise = new CertificateChainPromise();
try {
+ mBinder.asBinder().linkToDeath(promise, 0);
if (params == null) {
params = new KeymasterArguments();
}
if (outChain == null) {
outChain = new KeymasterCertificateChain();
}
- CertificateChainPromise promise = new CertificateChainPromise();
int error = mBinder.attestDeviceIds(promise, params);
if (error != NO_ERROR) return error;
KeyAttestationCallbackResult result = promise.getFuture().get();
@@ -1098,6 +1168,8 @@
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "AttestDevicdeIds completed with exception", e);
return SYSTEM_ERROR;
+ } finally {
+ mBinder.asBinder().unlinkToDeath(promise, 0);
}
}
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index ac62ff4..4011329 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -172,6 +172,8 @@
LOG_ALWAYS_FATAL_IF(physDeviceProperties.apiVersion < VK_MAKE_VERSION(1, 1, 0));
mDriverVersion = physDeviceProperties.driverVersion;
+ mIsQualcomm = physDeviceProperties.vendorID == 20803;
+
// query to get the initial queue props size
uint32_t queueCount;
mGetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice, &queueCount, nullptr);
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 54333f3..a7a43cc 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -181,6 +181,13 @@
SwapBehavior mSwapBehavior = SwapBehavior::Discard;
GrVkExtensions mExtensions;
uint32_t mDriverVersion = 0;
+
+ // TODO: Remove once fix has landed. Temporaryly needed for workaround for setting up AHB
+ // surfaces on Qualcomm. Currently if you don't use VkSwapchain Qualcomm is not setting
+ // reporting that we need to use one of their private vendor usage bits which greatly effects
+ // performance if it is not used.
+ bool mIsQualcomm = false;
+ bool isQualcomm() const { return mIsQualcomm; }
};
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index 3fed6b0..36f540c 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -299,6 +299,10 @@
}
windowInfo.windowUsageFlags = hwbUsage.androidHardwareBufferUsage;
+ if (vkManager.isQualcomm()) {
+ windowInfo.windowUsageFlags =
+ windowInfo.windowUsageFlags | AHARDWAREBUFFER_USAGE_VENDOR_0;
+ }
} else {
ALOGE("VulkanSurface::Create() vkmGetPhysicalDeviceImageFormatProperties2 is missing");
diff --git a/packages/SettingsLib/res/values/colors.xml b/packages/SettingsLib/res/values/colors.xml
index 4b91bbb..209b2cb 100644
--- a/packages/SettingsLib/res/values/colors.xml
+++ b/packages/SettingsLib/res/values/colors.xml
@@ -20,13 +20,13 @@
<color name="usage_graph_dots">@*android:color/tertiary_device_default_settings</color>
<color name="list_divider_color">#64000000</color>
- <color name="bt_color_icon_1">#48a50e0e</color> <!-- 72% Material Red 900 -->
- <color name="bt_color_icon_2">#480d652d</color> <!-- 72% Material Green 900 -->
- <color name="bt_color_icon_3">#48e37400</color> <!-- 72% Material Yellow 900 -->
- <color name="bt_color_icon_4">#48b06000</color> <!-- 72% Material Orange 900 -->
- <color name="bt_color_icon_5">#489c166b</color> <!-- 72% Material Pink 900 -->
- <color name="bt_color_icon_6">#48681da8</color> <!-- 72% Material Purple 900 -->
- <color name="bt_color_icon_7">#48007b83</color> <!-- 72% Material Cyan 900 -->
+ <color name="bt_color_icon_1">#b4a50e0e</color> <!-- 72% Material Red 900 -->
+ <color name="bt_color_icon_2">#b40d652d</color> <!-- 72% Material Green 900 -->
+ <color name="bt_color_icon_3">#b4e37400</color> <!-- 72% Material Yellow 900 -->
+ <color name="bt_color_icon_4">#b4b06000</color> <!-- 72% Material Orange 900 -->
+ <color name="bt_color_icon_5">#b49c166b</color> <!-- 72% Material Pink 900 -->
+ <color name="bt_color_icon_6">#b4681da8</color> <!-- 72% Material Purple 900 -->
+ <color name="bt_color_icon_7">#b4007b83</color> <!-- 72% Material Cyan 900 -->
<color name="bt_color_bg_1">#fad2cf</color> <!-- Material Red 100 -->
<color name="bt_color_bg_2">#ceead6</color> <!-- Material Green 100 -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index 867efb4..148046b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -6,7 +6,6 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.provider.MediaStore;
@@ -135,7 +134,7 @@
final BluetoothDevice bluetoothDevice = cachedDevice.getDevice();
final boolean untetheredHeadset = bluetoothDevice != null
? Boolean.parseBoolean(bluetoothDevice.getMetadata(
- BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET))
+ BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET))
: false;
final int iconSize = context.getResources().getDimensionPixelSize(
R.dimen.bt_nearby_icon_size);
@@ -181,8 +180,8 @@
final int[] iconBgColors = resources.getIntArray(R.array.bt_icon_bg_colors);
// get color index based on mac address
- final int index = Math.abs(hashCode % iconBgColors.length);
- drawable.setColorFilter(iconFgColors[index], PorterDuff.Mode.SRC_ATOP);
+ final int index = Math.abs(hashCode % iconBgColors.length);
+ drawable.setTint(iconFgColors[index]);
final Drawable adaptiveIcon = new AdaptiveIcon(context, drawable);
((AdaptiveIcon) adaptiveIcon).setBackgroundColor(iconBgColors[index]);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index e374db3..f597a1a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -686,6 +686,9 @@
Settings.Global.GPU_DEBUG_LAYERS,
GlobalSettingsProto.Gpu.DEBUG_LAYERS);
dumpSetting(s, p,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_DEBUG_PACKAGE,
+ GlobalSettingsProto.Gpu.ANGLE_DEBUG_PACKAGE);
+ dumpSetting(s, p,
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE,
GlobalSettingsProto.Gpu.ANGLE_GL_DRIVER_ALL_ANGLE);
dumpSetting(s, p,
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index d0fff74..64e56f9 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -41,6 +41,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.function.Supplier;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -52,14 +53,9 @@
public final class ClockManager {
private static final String TAG = "ClockOptsProvider";
- private static final String DEFAULT_CLOCK_ID = "default";
- private final List<ClockInfo> mClockInfos = new ArrayList<>();
- /**
- * Map from expected value stored in settings to supplier of custom clock face.
- */
- private final Map<String, ClockPlugin> mClocks = new ArrayMap<>();
- @Nullable private ClockPlugin mCurrentClock;
+ private final AvailableClocks mPreviewClocks;
+ private final List<Supplier<ClockPlugin>> mBuiltinClocks = new ArrayList<>();
private final Context mContext;
private final ContentResolver mContentResolver;
@@ -78,21 +74,6 @@
}
};
- private final PluginListener<ClockPlugin> mClockPluginListener =
- new PluginListener<ClockPlugin>() {
- @Override
- public void onPluginConnected(ClockPlugin plugin, Context pluginContext) {
- addClockPlugin(plugin);
- reload();
- }
-
- @Override
- public void onPluginDisconnected(ClockPlugin plugin) {
- removeClockPlugin(plugin);
- reload();
- }
- };
-
private final PluginManager mPluginManager;
/**
@@ -108,13 +89,22 @@
}
};
@Nullable private DockManager mDockManager;
+
/**
* When docked, the DOCKED_CLOCK_FACE setting will be checked for the custom clock face
* to show.
*/
private boolean mIsDocked;
- private final List<ClockChangedListener> mListeners = new ArrayList<>();
+ /**
+ * Listeners for onClockChanged event.
+ *
+ * Each listener must receive a separate clock plugin instance. Otherwise, there could be
+ * problems like attempting to attach a view that already has a parent. To deal with this issue,
+ * each listener is associated with a collection of available clocks. When onClockChanged is
+ * fired the current clock plugin instance is retrieved from that listeners available clocks.
+ */
+ private final Map<ClockChangedListener, AvailableClocks> mListeners = new ArrayMap<>();
private final int mWidth;
private final int mHeight;
@@ -133,14 +123,16 @@
mPluginManager = pluginManager;
mContentResolver = contentResolver;
mSettingsWrapper = settingsWrapper;
+ mPreviewClocks = new AvailableClocks();
Resources res = context.getResources();
LayoutInflater layoutInflater = injectionInflater.injectable(LayoutInflater.from(context));
- addClockPlugin(new DefaultClockController(res, layoutInflater, colorExtractor));
- addClockPlugin(new BubbleClockController(res, layoutInflater, colorExtractor));
- addClockPlugin(new StretchAnalogClockController(res, layoutInflater, colorExtractor));
- addClockPlugin(new TypeClockController(res, layoutInflater, colorExtractor));
+ addBuiltinClock(() -> new DefaultClockController(res, layoutInflater, colorExtractor));
+ addBuiltinClock(() -> new BubbleClockController(res, layoutInflater, colorExtractor));
+ addBuiltinClock(() -> new StretchAnalogClockController(res, layoutInflater,
+ colorExtractor));
+ addBuiltinClock(() -> new TypeClockController(res, layoutInflater, colorExtractor));
// Store the size of the display for generation of clock preview.
DisplayMetrics dm = res.getDisplayMetrics();
@@ -155,7 +147,12 @@
if (mListeners.isEmpty()) {
register();
}
- mListeners.add(listener);
+ AvailableClocks availableClocks = new AvailableClocks();
+ for (int i = 0; i < mBuiltinClocks.size(); i++) {
+ availableClocks.addClockPlugin(mBuiltinClocks.get(i).get());
+ }
+ mListeners.put(listener, availableClocks);
+ mPluginManager.addPluginListener(availableClocks, ClockPlugin.class, true);
reload();
}
@@ -163,7 +160,8 @@
* Remove listener added with {@link addOnClockChangedListener}.
*/
public void removeOnClockChangedListener(ClockChangedListener listener) {
- mListeners.remove(listener);
+ AvailableClocks availableClocks = mListeners.remove(listener);
+ mPluginManager.removePluginListener(availableClocks);
if (mListeners.isEmpty()) {
unregister();
}
@@ -173,16 +171,16 @@
* Get information about available clock faces.
*/
List<ClockInfo> getClockInfos() {
- return mClockInfos;
+ return mPreviewClocks.getInfo();
}
/**
* Get the current clock.
- * @returns current custom clock or null for default.
+ * @return current custom clock or null for default.
*/
@Nullable
ClockPlugin getCurrentClock() {
- return mCurrentClock;
+ return mPreviewClocks.getCurrentClock();
}
@VisibleForTesting
@@ -195,39 +193,14 @@
return mContentObserver;
}
- private void addClockPlugin(ClockPlugin plugin) {
- final String id = plugin.getClass().getName();
- mClocks.put(plugin.getClass().getName(), plugin);
- mClockInfos.add(ClockInfo.builder()
- .setName(plugin.getName())
- .setTitle(plugin.getTitle())
- .setId(id)
- .setThumbnail(() -> plugin.getThumbnail())
- .setPreview(() -> plugin.getPreview(mWidth, mHeight))
- .build());
- }
-
- private void removeClockPlugin(ClockPlugin plugin) {
- final String id = plugin.getClass().getName();
- mClocks.remove(id);
- for (int i = 0; i < mClockInfos.size(); i++) {
- if (id.equals(mClockInfos.get(i).getId())) {
- mClockInfos.remove(i);
- break;
- }
- }
- }
-
- private void notifyClockChanged(ClockPlugin plugin) {
- for (int i = 0; i < mListeners.size(); i++) {
- // It probably doesn't make sense to supply the same plugin instances to multiple
- // listeners. This should be fine for now since there is only a single listener.
- mListeners.get(i).onClockChanged(plugin);
- }
+ private void addBuiltinClock(Supplier<ClockPlugin> pluginSupplier) {
+ ClockPlugin plugin = pluginSupplier.get();
+ mPreviewClocks.addClockPlugin(plugin);
+ mBuiltinClocks.add(pluginSupplier);
}
private void register() {
- mPluginManager.addPluginListener(mClockPluginListener, ClockPlugin.class, true);
+ mPluginManager.addPluginListener(mPreviewClocks, ClockPlugin.class, true);
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE),
false, mContentObserver);
@@ -243,7 +216,7 @@
}
private void unregister() {
- mPluginManager.removePluginListener(mClockPluginListener);
+ mPluginManager.removePluginListener(mPreviewClocks);
mContentResolver.unregisterContentObserver(mContentObserver);
if (mDockManager != null) {
mDockManager.removeListener(mDockEventListener);
@@ -251,30 +224,16 @@
}
private void reload() {
- mCurrentClock = getClockPlugin();
- if (mCurrentClock instanceof DefaultClockController) {
- notifyClockChanged(null);
- } else {
- notifyClockChanged(mCurrentClock);
- }
- }
-
- private ClockPlugin getClockPlugin() {
- ClockPlugin plugin = null;
- if (mIsDocked) {
- final String name = mSettingsWrapper.getDockedClockFace();
- if (name != null) {
- plugin = mClocks.get(name);
- if (plugin != null) {
- return plugin;
- }
+ mPreviewClocks.reload();
+ mListeners.forEach((listener, clocks) -> {
+ clocks.reload();
+ ClockPlugin clock = clocks.getCurrentClock();
+ if (clock instanceof DefaultClockController) {
+ listener.onClockChanged(null);
+ } else {
+ listener.onClockChanged(clock);
}
- }
- final String name = mSettingsWrapper.getLockScreenCustomClockFace();
- if (name != null) {
- plugin = mClocks.get(name);
- }
- return plugin;
+ });
}
/**
@@ -288,4 +247,106 @@
*/
void onClockChanged(ClockPlugin clock);
}
+
+ /**
+ * Collection of available clocks.
+ */
+ private final class AvailableClocks implements PluginListener<ClockPlugin> {
+
+ /**
+ * Map from expected value stored in settings to plugin for custom clock face.
+ */
+ private final Map<String, ClockPlugin> mClocks = new ArrayMap<>();
+
+ /**
+ * Metadata about available clocks, such as name and preview images.
+ */
+ private final List<ClockInfo> mClockInfo = new ArrayList<>();
+
+ /**
+ * Active ClockPlugin.
+ */
+ @Nullable private ClockPlugin mCurrentClock;
+
+ @Override
+ public void onPluginConnected(ClockPlugin plugin, Context pluginContext) {
+ addClockPlugin(plugin);
+ reload();
+ }
+
+ @Override
+ public void onPluginDisconnected(ClockPlugin plugin) {
+ removeClockPlugin(plugin);
+ reload();
+ }
+
+ /**
+ * Get the current clock.
+ * @return current custom clock or null for default.
+ */
+ @Nullable
+ ClockPlugin getCurrentClock() {
+ return mCurrentClock;
+ }
+
+ /**
+ * Get information about available clock faces.
+ */
+ List<ClockInfo> getInfo() {
+ return mClockInfo;
+ }
+
+ /**
+ * Adds a clock plugin to the collection of available clocks.
+ *
+ * @param plugin The plugin to add.
+ */
+ void addClockPlugin(ClockPlugin plugin) {
+ final String id = plugin.getClass().getName();
+ mClocks.put(plugin.getClass().getName(), plugin);
+ mClockInfo.add(ClockInfo.builder()
+ .setName(plugin.getName())
+ .setTitle(plugin.getTitle())
+ .setId(id)
+ .setThumbnail(plugin::getThumbnail)
+ .setPreview(() -> plugin.getPreview(mWidth, mHeight))
+ .build());
+ }
+
+ private void removeClockPlugin(ClockPlugin plugin) {
+ final String id = plugin.getClass().getName();
+ mClocks.remove(id);
+ for (int i = 0; i < mClockInfo.size(); i++) {
+ if (id.equals(mClockInfo.get(i).getId())) {
+ mClockInfo.remove(i);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Update the current clock.
+ */
+ void reload() {
+ mCurrentClock = getClockPlugin();
+ }
+
+ private ClockPlugin getClockPlugin() {
+ ClockPlugin plugin = null;
+ if (ClockManager.this.isDocked()) {
+ final String name = mSettingsWrapper.getDockedClockFace();
+ if (name != null) {
+ plugin = mClocks.get(name);
+ if (plugin != null) {
+ return plugin;
+ }
+ }
+ }
+ final String name = mSettingsWrapper.getLockScreenCustomClockFace();
+ if (name != null) {
+ plugin = mClocks.get(name);
+ }
+ return plugin;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index f07887e..dcacd0f 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -439,6 +439,9 @@
@Override
public void onUiModeChanged() {
mContext.getTheme().applyStyle(mContext.getThemeResId(), true);
+ if (mDialog.isShowing()) {
+ mDialog.refreshDialog();
+ }
}
public void destroy() {
@@ -1577,7 +1580,9 @@
boolean panelEnabled = initializePanel();
if (!panelEnabled) {
- mBackgroundDrawable = new GradientDrawable(mContext);
+ if (mBackgroundDrawable == null) {
+ mBackgroundDrawable = new GradientDrawable(mContext);
+ }
mScrimAlpha = ScrimController.GRADIENT_SCRIM_ALPHA;
} else {
mBackgroundDrawable = mContext.getDrawable(
@@ -1720,10 +1725,14 @@
mKeyguardShowing = keyguardShowing;
}
+ public void refreshDialog() {
+ initializeLayout();
+ mGlobalActionsLayout.updateList();
+ }
+
public void onRotate(int from, int to) {
if (mShowing && isGridEnabled(mContext)) {
- initializeLayout();
- mGlobalActionsLayout.updateList();
+ refreshDialog();
}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
index 46b1833..f2ad958 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
@@ -18,6 +18,8 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
@@ -31,6 +33,7 @@
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerFake;
+import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.util.InjectionInflationController;
@@ -38,6 +41,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -57,7 +61,8 @@
@Mock SysuiColorExtractor mMockColorExtractor;
@Mock ContentResolver mMockContentResolver;
@Mock SettingsWrapper mMockSettingsWrapper;
- @Mock ClockManager.ClockChangedListener mMockListener;
+ @Mock ClockManager.ClockChangedListener mMockListener1;
+ @Mock ClockManager.ClockChangedListener mMockListener2;
@Before
public void setUp() {
@@ -73,13 +78,17 @@
mMockPluginManager, mMockColorExtractor, mMockContentResolver,
mMockSettingsWrapper);
- mClockManager.addOnClockChangedListener(mMockListener);
+ mClockManager.addOnClockChangedListener(mMockListener1);
+ mClockManager.addOnClockChangedListener(mMockListener2);
+ reset(mMockListener1, mMockListener2);
+
mContentObserver = mClockManager.getContentObserver();
}
@After
public void tearDown() {
- mClockManager.removeOnClockChangedListener(mMockListener);
+ mClockManager.removeOnClockChangedListener(mMockListener1);
+ mClockManager.removeOnClockChangedListener(mMockListener2);
}
@Test
@@ -116,6 +125,34 @@
}
@Test
+ public void onClockChanged_customClock() {
+ // GIVEN that settings is set to the bubble clock face
+ when(mMockSettingsWrapper.getLockScreenCustomClockFace()).thenReturn(BUBBLE_CLOCK);
+ // WHEN settings change event is fired
+ mContentObserver.onChange(false);
+ // THEN the plugin is the bubble clock face.
+ ArgumentCaptor<ClockPlugin> captor = ArgumentCaptor.forClass(ClockPlugin.class);
+ verify(mMockListener1).onClockChanged(captor.capture());
+ assertThat(captor.getValue()).isInstanceOf(BUBBLE_CLOCK_CLASS);
+ }
+
+ @Test
+ public void onClockChanged_uniqueInstances() {
+ // GIVEN that settings is set to the bubble clock face
+ when(mMockSettingsWrapper.getLockScreenCustomClockFace()).thenReturn(BUBBLE_CLOCK);
+ // WHEN settings change event is fired
+ mContentObserver.onChange(false);
+ // THEN the listeners receive separate instances of the Bubble clock plugin.
+ ArgumentCaptor<ClockPlugin> captor1 = ArgumentCaptor.forClass(ClockPlugin.class);
+ ArgumentCaptor<ClockPlugin> captor2 = ArgumentCaptor.forClass(ClockPlugin.class);
+ verify(mMockListener1).onClockChanged(captor1.capture());
+ verify(mMockListener2).onClockChanged(captor2.capture());
+ assertThat(captor1.getValue()).isInstanceOf(BUBBLE_CLOCK_CLASS);
+ assertThat(captor2.getValue()).isInstanceOf(BUBBLE_CLOCK_CLASS);
+ assertThat(captor1.getValue()).isNotSameAs(captor2.getValue());
+ }
+
+ @Test
public void getCurrentClock_badSettingsValue() {
// GIVEN that settings contains a value that doesn't correspond to a
// custom clock face.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
index 096f205..50fadef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
@@ -199,6 +199,7 @@
}
@Test
+ @Ignore("Flaky")
public void testRestoredAtRestingPosition() throws InterruptedException {
mStackController.flingStackThenSpringToEdge(0, 5000, 5000);
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_airplanemode_active.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_airplanemode_active.xml
index 1646cc1e..6212a51 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_airplanemode_active.xml
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_airplanemode_active.xml
@@ -15,6 +15,6 @@
limitations under the License.
-->
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+<vector android:height="24dp" android:tint="?android:attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M22,15.89v-2.57c0-1.1-0.65-2.09-1.67-2.53L14.5,8.28V3.75c0-1.38-1.12-2.5-2.5-2.5s-2.5,1.12-2.5,2.5v4.53l-5.83,2.51 C2.65,11.22,2,12.22,2,13.32v2.57l7.5-1.28v3.03l-1.47,1.17C7.38,19.34,7,20.12,7,20.96v1.33l4.96-0.3L17,22.3v-1.33 c0-0.84-0.38-1.62-1.03-2.15l-1.47-1.17v-3.03L22,15.89z M15.03,19.98c0.23,0.18,0.38,0.44,0.44,0.72l-3.52-0.2l-3.43,0.2 c0.06-0.28,0.21-0.53,0.44-0.72L11,18.36v-5.53l-7.5,1.28v-0.79c0-0.5,0.3-0.95,0.76-1.15L11,9.27V3.75c0-0.55,0.45-1,1-1 s1,0.45,1,1v5.52l6.74,2.9c0.46,0.2,0.76,0.65,0.76,1.15v0.79L13,12.83v5.53L15.03,19.98z"/>
</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_data_saver.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_data_saver.xml
index 545e0dd..ccbaecd 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_data_saver.xml
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_data_saver.xml
@@ -15,7 +15,7 @@
limitations under the License.
-->
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+<vector android:height="24dp" android:tint="?android:attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,7a0.76 0.76 ,0,0,0-0.75 0.75 v3.5H7.75a0.75 0.75 ,0,0,0,0,1.5h3.5v3.5a0.75 0.75 ,0,0,0,1.5,0v-3.5h3.5a0.75 0.75 ,0,0,0,0-1.5h-3.5V7.75A0.76 0.76 ,0,0,0,12,7Z"/>
<path android:fillColor="@android:color/white" android:pathData="M3.36,7A10,10,0,0,0,20.27,17.64L18.1,16.39A7.5,7.5,0,1,1,11.25,4.56V2.05A10,10,0,0,0,3.36,7Z"/>
<path android:fillColor="@android:color/white" android:pathData="M21,16.35a10,10,0,0,0-8.27-14.3V4.56a7.48,7.48,0,0,1,6.1,10.54Z"/>
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_wifi_tethering.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_wifi_tethering.xml
index b5cde8f..dcf507a 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_wifi_tethering.xml
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_wifi_tethering.xml
@@ -15,7 +15,7 @@
limitations under the License.
-->
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+<vector android:height="24dp" android:tint="?android:attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,14c-0.83,0-1.5-0.67-1.5-1.5S11.17,11,12,11s1.5,0.67,1.5,1.5S12.83,14,12,14z"/>
<path android:fillColor="@android:color/white" android:pathData="M8.46,16.79c-0.19,0-0.38-0.07-0.53-0.22c-1.09-1.09-1.68-2.53-1.68-4.07s0.6-2.98,1.68-4.07 c2.24-2.24,5.89-2.24,8.13,0c1.09,1.09,1.68,2.53,1.68,4.07s-0.6,2.98-1.68,4.07c-0.29,0.29-0.77,0.29-1.06,0 s-0.29-0.77,0-1.06c0.8-0.8,1.24-1.87,1.24-3c0-1.14-0.44-2.2-1.24-3.01c-1.66-1.66-4.35-1.66-6.01,0 c-0.8,0.8-1.24,1.87-1.24,3c0,1.14,0.44,2.2,1.24,3.01c0.29,0.29,0.29,0.77,0,1.06C8.85,16.71,8.66,16.79,8.46,16.79z"/>
<path android:fillColor="@android:color/white" android:pathData="M18.36,19.61c-0.19,0-0.38-0.07-0.53-0.22c-0.29-0.29-0.29-0.77,0-1.06c1.56-1.56,2.42-3.63,2.42-5.83 s-0.86-4.28-2.42-5.83c-3.22-3.22-8.45-3.22-11.67,0C4.61,8.22,3.75,10.3,3.75,12.5s0.86,4.28,2.42,5.83 c0.29,0.29,0.29,0.77,0,1.06s-0.77,0.29-1.06,0c-1.84-1.84-2.86-4.29-2.86-6.89s1.01-5.05,2.86-6.89c3.8-3.8,9.99-3.8,13.79,0 c1.84,1.84,2.86,4.29,2.86,6.89s-1.01,5.05-2.86,6.89C18.75,19.54,18.56,19.61,18.36,19.61z"/>
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_dialog_close.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_dialog_close.xml
deleted file mode 100644
index 4c2e143..0000000
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_dialog_close.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-<!--
- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
- <path android:fillColor="@android:color/white" android:pathData="M20.03,3.97c-0.29-0.29-0.77-0.29-1.06,0L12,10.94L5.03,3.97c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06L10.94,12 l-6.97,6.97c-0.29,0.29-0.29,0.77,0,1.06c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22L12,13.06l6.97,6.97 c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22c0.29-0.29,0.29-0.77,0-1.06L13.06,12l6.97-6.97 C20.32,4.74,20.32,4.26,20.03,3.97z"/>
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_airplanemode_active.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_airplanemode_active.xml
index 533b5f9..ebd7a28 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_airplanemode_active.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_airplanemode_active.xml
@@ -15,6 +15,6 @@
limitations under the License.
-->
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+<vector android:height="24dp" android:tint="?android:attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M2.65,15.8L10,13.5V19l-1.6,1.2C8.15,20.39,8,20.69,8,21v0.67c0,0.17,0.14,0.28,0.31,0.24c1.94-0.55,1.3-0.37,3.19-0.91 c1.21,0.35,1.99,0.57,3.19,0.91c0.17,0.04,0.31-0.07,0.31-0.24V21c0-0.31-0.15-0.61-0.4-0.8L13,19v-5.5l7.35,2.3 c0.32,0.1,0.65-0.14,0.65-0.48v-0.49c0-0.52-0.27-1-0.7-1.27L13,9V3.5C13,2.67,12.33,2,11.5,2S10,2.67,10,3.5V9l-7.3,4.56 C2.27,13.83,2,14.31,2,14.83v0.49C2,15.66,2.33,15.9,2.65,15.8z"/>
</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_data_saver.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_data_saver.xml
index 3079539..103985b 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_data_saver.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_data_saver.xml
@@ -15,7 +15,7 @@
limitations under the License.
-->
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+<vector android:height="24dp" android:tint="?android:attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M11,11H9c-0.55,0-1,0.45-1,1s0.45,1,1,1h2v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2h2c0.55,0,1-0.45,1-1s-0.45-1-1-1h-2V9 c0-0.55-0.45-1-1-1s-1,0.45-1,1V11z"/>
<path android:fillColor="@android:color/white" android:pathData="M13,2.05v2.52c3.66,0.49,6.5,3.63,6.5,7.43c0,1.01-0.2,1.97-0.56,2.85l2.18,1.26C21.68,14.85,22,13.46,22,12 C22,6.81,18.05,2.55,13,2.05z"/>
<path android:fillColor="@android:color/white" android:pathData="M12,19.5c-4.14,0-7.5-3.36-7.5-7.5c0-3.8,2.84-6.93,6.5-7.43V2.05C5.95,2.55,2,6.81,2,12c0,5.52,4.48,10,10,10 c3.34,0,6.3-1.65,8.11-4.17l-2.18-1.26C16.56,18.35,14.41,19.5,12,19.5z"/>
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_wifi_tethering.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_wifi_tethering.xml
index f6ae09b..43ca3cfae 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_wifi_tethering.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_wifi_tethering.xml
@@ -15,7 +15,7 @@
limitations under the License.
-->
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+<vector android:height="24dp" android:tint="?android:attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M15.46,16.46L15.46,16.46c0.44,0.44,1.17,0.4,1.51-0.1C17.62,15.4,18,14.25,18,13c0-3.75-3.45-6.7-7.34-5.86 c-2.24,0.48-4.04,2.3-4.52,4.54c-0.37,1.75,0.02,3.38,0.89,4.67c0.34,0.51,1.08,0.54,1.51,0.11l0.01-0.01 c0.34-0.34,0.37-0.88,0.1-1.28c-0.5-0.76-0.75-1.71-0.61-2.74c0.23-1.74,1.67-3.17,3.41-3.4C13.9,8.71,16,10.61,16,13 c0,0.8-0.24,1.54-0.64,2.17C15.09,15.58,15.11,16.11,15.46,16.46z"/>
<path android:fillColor="@android:color/white" android:pathData="M10.86,3.06c-4.65,0.51-8.39,4.34-8.82,9c-0.25,2.72,0.6,5.25,2.15,7.18c0.37,0.46,1.07,0.49,1.49,0.07 C6.04,18.96,6.07,18.4,5.75,18c-1.4-1.75-2.09-4.1-1.6-6.61c0.61-3.13,3.14-5.65,6.28-6.24C15.54,4.18,20,8.07,20,13 c0,1.9-0.66,3.63-1.77,5c-0.32,0.39-0.28,0.96,0.08,1.31l0,0c0.42,0.42,1.12,0.39,1.49-0.08c1.38-1.7,2.2-3.88,2.2-6.24 C22,7.1,16.89,2.4,10.86,3.06z"/>
<path android:fillColor="@android:color/white" android:pathData="M 12 11 C 13.1045694997 11 14 11.8954305003 14 13 C 14 14.1045694997 13.1045694997 15 12 15 C 10.8954305003 15 10 14.1045694997 10 13 C 10 11.8954305003 10.8954305003 11 12 11 Z"/>
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_dialog_close.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_dialog_close.xml
deleted file mode 100644
index 2047109..0000000
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_dialog_close.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-<!--
- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
- <path android:fillColor="@android:color/white" android:pathData="M5.7,18.3c0.39,0.39,1.02,0.39,1.41,0L12,13.41l4.89,4.89c0.39,0.39,1.02,0.39,1.41,0s0.39-1.02,0-1.41L13.41,12l4.89-4.89 c0.38-0.38,0.38-1.02,0-1.4c-0.39-0.39-1.02-0.39-1.41,0c0,0,0,0,0,0L12,10.59L7.11,5.7c-0.39-0.39-1.02-0.39-1.41,0 s-0.39,1.02,0,1.41L10.59,12L5.7,16.89C5.31,17.28,5.31,17.91,5.7,18.3z"/>
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_airplanemode_active.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_airplanemode_active.xml
index 9182207..ed64277 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_airplanemode_active.xml
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_airplanemode_active.xml
@@ -15,6 +15,6 @@
limitations under the License.
-->
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+<vector android:height="24dp" android:tint="?android:attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M2.52,16.17c0.32,0.23,0.74,0.31,1.11,0.19l5.87-1.84v3.87L8,19.52c-0.31,0.24-0.5,0.61-0.5,1v0.75 c0,0.69,0.56,1.25,1.25,1.25h6.5c0.69,0,1.25-0.56,1.25-1.25v-0.75c0-0.39-0.19-0.76-0.5-1l-1.5-1.12v-3.87l5.88,1.84 c0.38,0.12,0.79,0.05,1.11-0.19c0.32-0.23,0.51-0.61,0.51-1.01l0-1.84c0-0.63-0.34-1.21-0.89-1.52L14.5,8.06V4 c0-1.38-1.12-2.5-2.5-2.5S9.5,2.62,9.5,4v4.07L2.89,11.8C2.35,12.11,2,12.7,2,13.33l0,1.83C2.01,15.56,2.2,15.94,2.52,16.17z M3.63,13.11L11,8.94V4c0-0.55,0.45-1,1-1s1,0.45,1,1v4.94l7.37,4.17c0.08,0.04,0.13,0.13,0.13,0.22l0,1.5L13,12.48v6.66l2,1.5 v0.38H9v-0.38l2-1.5v-6.66l-7.5,2.34l0-1.49C3.5,13.24,3.55,13.15,3.63,13.11z"/>
</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_data_saver.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_data_saver.xml
index 29f6ccb..5fa15f4 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_data_saver.xml
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_data_saver.xml
@@ -15,7 +15,7 @@
limitations under the License.
-->
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+<vector android:height="24dp" android:tint="?android:attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M3.36,7A10,10,0,0,0,20.27,17.64L18.1,16.39A7.5,7.5,0,1,1,11.25,4.56V2.05A10,10,0,0,0,3.36,7Z"/>
<path android:fillColor="@android:color/white" android:pathData="M21,16.35a10,10,0,0,0-8.27-14.3V4.56a7.48,7.48,0,0,1,6.1,10.54Z"/>
<path android:fillColor="@android:color/white" android:pathData="M8,12a0.76 0.76 ,0,0,0,0.75 0.75 h2.5v2.5a0.75 0.75 ,0,0,0,1.5,0v-2.5h2.5a0.75 0.75 ,0,0,0,0-1.5h-2.5V8.75a0.75 0.75 ,0,0,0-1.5,0v2.5H8.75A0.76 0.76 ,0,0,0,8,12Z"/>
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_wifi_tethering.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_wifi_tethering.xml
index 6b2d8f0..419710d 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_wifi_tethering.xml
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_wifi_tethering.xml
@@ -15,7 +15,7 @@
limitations under the License.
-->
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+<vector android:height="24dp" android:tint="?android:attr/colorControlNormal" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M 12 11 C 12.8284271247 11 13.5 11.6715728753 13.5 12.5 C 13.5 13.3284271247 12.8284271247 14 12 14 C 11.1715728753 14 10.5 13.3284271247 10.5 12.5 C 10.5 11.6715728753 11.1715728753 11 12 11 Z"/>
<path android:fillColor="@android:color/white" android:pathData="M15.01,16.57c0.29,0.29,0.77,0.29,1.06,0c1.09-1.09,1.68-2.53,1.68-4.07s-0.6-2.98-1.68-4.07c-2.24-2.24-5.89-2.24-8.13,0 c-1.09,1.09-1.68,2.53-1.68,4.07s0.6,2.98,1.68,4.07c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22 c0.29-0.29,0.29-0.77,0-1.06c-0.8-0.8-1.24-1.87-1.24-3.01c0-1.13,0.44-2.2,1.24-3c1.66-1.66,4.35-1.66,6.01,0 c0.8,0.8,1.24,1.87,1.24,3.01c0,1.13-0.44,2.2-1.24,3C14.71,15.8,14.71,16.27,15.01,16.57z"/>
<path android:fillColor="@android:color/white" android:pathData="M18.36,19.61c0.19,0,0.38-0.07,0.53-0.22c1.84-1.84,2.86-4.29,2.86-6.89s-1.01-5.05-2.86-6.89c-3.8-3.8-9.99-3.8-13.79,0 C3.26,7.45,2.25,9.9,2.25,12.5s1.01,5.05,2.86,6.89c0.29,0.29,0.77,0.29,1.06,0s0.29-0.77,0-1.06c-1.56-1.56-2.42-3.63-2.42-5.83 s0.86-4.28,2.42-5.83c3.22-3.22,8.45-3.22,11.67,0c1.56,1.56,2.42,3.63,2.42,5.83s-0.86,4.28-2.42,5.83 c-0.29,0.29-0.29,0.77,0,1.06C17.98,19.54,18.17,19.61,18.36,19.61z"/>
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_dialog_close.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_dialog_close.xml
deleted file mode 100644
index 2243cab..0000000
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_dialog_close.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-<!--
- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<vector android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
- <path android:fillColor="@android:color/white" android:pathData="M18.78,5.22c-0.29-0.29-0.77-0.29-1.06,0L12,10.94L6.28,5.22c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06L10.94,12 l-5.72,5.72c-0.29,0.29-0.29,0.77,0,1.06C5.37,18.93,5.56,19,5.75,19s0.38-0.07,0.53-0.22L12,13.06l5.72,5.72 c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22c0.29-0.29,0.29-0.77,0-1.06L13.06,12l5.72-5.72 C19.07,5.99,19.07,5.51,18.78,5.22z"/>
-</vector>
\ No newline at end of file
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index b759dd4..d7decb4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -116,6 +116,22 @@
*/
private static final String KEY_MAX_CACHED_PROCESSES = "max_cached_processes";
+ /**
+ * Default value for mFlagBackgroundActivityStartsEnabled if not explicitly set in
+ * Settings.Global. This allows it to be set experimentally unless it has been
+ * enabled/disabled in developer options. Defaults to true.
+ */
+ private static final String KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED =
+ "default_background_activity_starts_enabled";
+
+ /**
+ * The packages temporarily whitelisted to be able to start activities from background.
+ * The list of packages is {@code ":"} colon delimited.
+ */
+ private static final String KEY_BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST =
+ "background_activity_starts_package_names_whitelist";
+
+
// Maximum number of cached processes we will allow.
public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
@@ -242,7 +258,8 @@
volatile boolean mFlagActivityStartsLoggingEnabled;
// Indicates whether the background activity starts is enabled.
- // Controlled by Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED
+ // Controlled by Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED.
+ // If not set explicitly the default is controlled by DeviceConfig.
volatile boolean mFlagBackgroundActivityStartsEnabled;
volatile ArraySet<String> mPackageNamesWhitelistedForBgActivityStarts = new ArraySet<>();
@@ -295,10 +312,6 @@
Settings.Global.getUriFor(
Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED);
- private static final Uri BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST_URI =
- Settings.Global.getUriFor(
- Settings.Global.BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST);
-
private static final Uri ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI =
Settings.Global.getUriFor(Settings.Global.ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS);
@@ -306,8 +319,19 @@
new OnPropertyChangedListener() {
@Override
public void onPropertyChanged(String namespace, String name, String value) {
- if (KEY_MAX_CACHED_PROCESSES.equals(name)) {
- updateMaxCachedProcesses();
+ if (name == null) {
+ return;
+ }
+ switch (name) {
+ case KEY_MAX_CACHED_PROCESSES:
+ updateMaxCachedProcesses();
+ break;
+ case KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED:
+ case KEY_BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST:
+ updateBackgroundActivityStarts();
+ break;
+ default:
+ break;
}
}
};
@@ -330,16 +354,11 @@
mResolver.registerContentObserver(ACTIVITY_MANAGER_CONSTANTS_URI, false, this);
mResolver.registerContentObserver(ACTIVITY_STARTS_LOGGING_ENABLED_URI, false, this);
mResolver.registerContentObserver(BACKGROUND_ACTIVITY_STARTS_ENABLED_URI, false, this);
- mResolver.registerContentObserver(BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST_URI,
- false, this);
if (mSystemServerAutomaticHeapDumpEnabled) {
mResolver.registerContentObserver(ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI,
false, this);
}
updateConstants();
- updateActivityStartsLoggingEnabled();
- updateBackgroundActivityStartsEnabled();
- updateBackgroundActivityStartsPackageNamesWhitelist();
if (mSystemServerAutomaticHeapDumpEnabled) {
updateEnableAutomaticSystemServerHeapDumps();
}
@@ -347,7 +366,8 @@
ActivityThread.currentApplication().getMainExecutor(),
mOnDeviceConfigChangedListener);
updateMaxCachedProcesses();
-
+ updateActivityStartsLoggingEnabled();
+ updateBackgroundActivityStarts();
}
public void setOverrideMaxCachedProcesses(int value) {
@@ -371,9 +391,7 @@
} else if (ACTIVITY_STARTS_LOGGING_ENABLED_URI.equals(uri)) {
updateActivityStartsLoggingEnabled();
} else if (BACKGROUND_ACTIVITY_STARTS_ENABLED_URI.equals(uri)) {
- updateBackgroundActivityStartsEnabled();
- } else if (BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST_URI.equals(uri)) {
- updateBackgroundActivityStartsPackageNamesWhitelist();
+ updateBackgroundActivityStarts();
} else if (ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI.equals(uri)) {
updateEnableAutomaticSystemServerHeapDumps();
}
@@ -463,24 +481,40 @@
Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED, 1) == 1;
}
- private void updateBackgroundActivityStartsEnabled() {
- mFlagBackgroundActivityStartsEnabled = Settings.Global.getInt(mResolver,
- Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED, 1) == 1;
- }
+ private void updateBackgroundActivityStarts() {
+ String whitelistedPackageNames = null;
+ int settingsValue = Settings.Global.getInt(mResolver,
+ Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED, -1);
- private void updateBackgroundActivityStartsPackageNamesWhitelist() {
- final String setting = Settings.Global.getString(mResolver,
- Settings.Global.BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST);
- if (TextUtils.isEmpty(setting)) {
- return;
+ // If the user has explicitly enabled or disabled, that affects all apps.
+ // Otherwise we take the default state and whitelist from DeviceConfig.
+ if (settingsValue >= 0) {
+ mFlagBackgroundActivityStartsEnabled = settingsValue != 0;
+ } else {
+ boolean enabledInDeviceConfig = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_DEFAULT_BACKGROUND_ACTIVITY_STARTS_ENABLED,
+ /*defaultValue*/ true);
+ mFlagBackgroundActivityStartsEnabled = enabledInDeviceConfig;
+ if (!enabledInDeviceConfig) {
+ whitelistedPackageNames = DeviceConfig.getProperty(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_BACKGROUND_ACTIVITY_STARTS_PACKAGE_NAMES_WHITELIST);
+ }
}
- ArraySet<String> newSet = new ArraySet<>();
- SimpleStringSplitter splitter = new SimpleStringSplitter(':');
- splitter.setString(setting);
- while (splitter.hasNext()) {
- newSet.add(splitter.next());
+ if (TextUtils.isEmpty(whitelistedPackageNames)) {
+ if (!mPackageNamesWhitelistedForBgActivityStarts.isEmpty()) {
+ mPackageNamesWhitelistedForBgActivityStarts = new ArraySet<>();
+ }
+ } else {
+ ArraySet<String> newSet = new ArraySet<>();
+ SimpleStringSplitter splitter = new SimpleStringSplitter(':');
+ splitter.setString(whitelistedPackageNames);
+ while (splitter.hasNext()) {
+ newSet.add(splitter.next());
+ }
+ mPackageNamesWhitelistedForBgActivityStarts = newSet;
}
- mPackageNamesWhitelistedForBgActivityStarts = newSet;
}
private void updateEnableAutomaticSystemServerHeapDumps() {
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 06d0152..cb587de0 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -58,6 +58,8 @@
sGlobalSettingToTypeMap.put(
Settings.Global.DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE, String.class);
sGlobalSettingToTypeMap.put(
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_DEBUG_PACKAGE, String.class);
+ sGlobalSettingToTypeMap.put(
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE, String.class);
sGlobalSettingToTypeMap.put(
Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS, String.class);
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index d7a57b9..35f7ea3 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -132,6 +132,7 @@
private static final int NOT_STARTED = 1;
private static final int STARTING = 2;
private static final int STARTED = 3;
+ private static final int STOPPING = 4;
private int mStartedState = NOT_STARTED;
KeepaliveInfo(@NonNull ISocketKeepaliveCallback callback,
@@ -314,6 +315,7 @@
}
}
if (NOT_STARTED != mStartedState) {
+ mStartedState = STOPPING;
Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.name());
if (mType == TYPE_NATT) {
mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot);
@@ -456,8 +458,8 @@
ki = mKeepalives.get(nai).get(slot);
} catch(NullPointerException e) {}
if (ki == null) {
- Log.e(TAG, "Event " + message.what + " for unknown keepalive " + slot + " on "
- + nai.name());
+ Log.e(TAG, "Event " + message.what + "," + slot + "," + reason
+ + " for unknown keepalive " + slot + " on " + nai.name());
return;
}
@@ -476,27 +478,30 @@
// messages in order.
// TODO : clarify this code and get rid of mStartedState. Using a StateMachine is an
// option.
- if (reason == SUCCESS && KeepaliveInfo.STARTING == ki.mStartedState) {
- // Keepalive successfully started.
- if (DBG) Log.d(TAG, "Started keepalive " + slot + " on " + nai.name());
- ki.mStartedState = KeepaliveInfo.STARTED;
- try {
- ki.mCallback.onStarted(slot);
- } catch (RemoteException e) {
- Log.w(TAG, "Discarded onStarted(" + slot + ") callback");
- }
- } else {
- // Keepalive successfully stopped, or error.
- if (reason == SUCCESS) {
- // The message indicated success stopping : don't call handleStopKeepalive.
- if (DBG) Log.d(TAG, "Successfully stopped keepalive " + slot + " on " + nai.name());
+ if (KeepaliveInfo.STARTING == ki.mStartedState) {
+ if (SUCCESS == reason) {
+ // Keepalive successfully started.
+ if (DBG) Log.d(TAG, "Started keepalive " + slot + " on " + nai.name());
+ ki.mStartedState = KeepaliveInfo.STARTED;
+ try {
+ ki.mCallback.onStarted(slot);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Discarded onStarted(" + slot + ") callback");
+ }
} else {
- // The message indicated some error trying to start or during the course of
- // keepalive : do call handleStopKeepalive.
+ Log.d(TAG, "Failed to start keepalive " + slot + " on " + nai.name()
+ + ": " + reason);
+ // The message indicated some error trying to start: do call handleStopKeepalive.
handleStopKeepalive(nai, slot, reason);
- if (DBG) Log.d(TAG, "Keepalive " + slot + " on " + nai.name() + " error " + reason);
}
+ } else if (KeepaliveInfo.STOPPING == ki.mStartedState) {
+ // The message indicated result of stopping : don't call handleStopKeepalive.
+ Log.d(TAG, "Stopped keepalive " + slot + " on " + nai.name()
+ + " stopped: " + reason);
ki.mStartedState = KeepaliveInfo.NOT_STARTED;
+ } else {
+ Log.wtf(TAG, "Event " + message.what + "," + slot + "," + reason
+ + " for keepalive in wrong state: " + ki.toString());
}
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 190610c..a0f0a31 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -384,8 +384,10 @@
PackageInstaller.SessionParams params = originalSession.params.copy();
params.isStaged = false;
params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;
+ // TODO(b/129744602): use the userid from the original session.
int apkSessionId = mPi.createSession(
- params, originalSession.getInstallerPackageName(), originalSession.userId);
+ params, originalSession.getInstallerPackageName(),
+ 0 /* UserHandle.SYSTEM */);
PackageInstallerSession apkSession = mPi.getSession(apkSessionId);
try {
@@ -465,8 +467,10 @@
}
PackageInstaller.SessionParams params = session.params.copy();
params.isStaged = false;
+ // TODO(b/129744602): use the userid from the original session.
int apkParentSessionId = mPi.createSession(
- params, session.getInstallerPackageName(), session.userId);
+ params, session.getInstallerPackageName(),
+ 0 /* UserHandle.SYSTEM */);
PackageInstallerSession apkParentSession = mPi.getSession(apkParentSessionId);
try {
apkParentSession.open();
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 15148f3..f83b3ea 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -110,6 +110,7 @@
import com.android.internal.os.BinderCallsStats.ExportedCallStat;
import com.android.internal.os.KernelCpuSpeedReader;
import com.android.internal.os.KernelCpuThreadReader;
+import com.android.internal.os.KernelCpuThreadReaderDiff;
import com.android.internal.os.KernelCpuThreadReaderSettingsObserver;
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeReader;
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader;
@@ -262,7 +263,7 @@
private StoragedUidIoStatsReader mStoragedUidIoStatsReader =
new StoragedUidIoStatsReader();
@Nullable
- private final KernelCpuThreadReader mKernelCpuThreadReader;
+ private final KernelCpuThreadReaderDiff mKernelCpuThreadReader;
private long mDebugElapsedClockPreviousValue = 0;
private long mDebugElapsedClockPullCount = 0;
@@ -1726,7 +1727,7 @@
throw new IllegalStateException("mKernelCpuThreadReader is null");
}
ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsages =
- this.mKernelCpuThreadReader.getProcessCpuUsage();
+ this.mKernelCpuThreadReader.getProcessCpuUsageDiffed();
if (processCpuUsages == null) {
throw new IllegalStateException("processCpuUsages is null");
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index bd28be1..cfa9944 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -15,17 +15,10 @@
*/
package com.android.server.devicepolicy;
-import android.app.admin.DevicePolicyManager;
import android.app.admin.IDevicePolicyManager;
-import android.app.admin.StartInstallingUpdateCallback;
-import android.content.ComponentName;
-import android.os.ParcelFileDescriptor;
import com.android.server.SystemService;
-import java.util.Collections;
-import java.util.List;
-
/**
* Defines the required interface for IDevicePolicyManager implemenation.
*
@@ -63,82 +56,4 @@
public void clearSystemUpdatePolicyFreezePeriodRecord() {
}
-
- @Override
- public long forceNetworkLogs() {
- return 0;
- }
-
- @Override
- public long forceSecurityLogs() {
- return 0;
- }
-
- @Override
- public boolean checkDeviceIdentifierAccess(String packageName, int pid, int uid) {
- return false;
- }
-
- @Override
- public int setGlobalPrivateDns(ComponentName who, int mode, String privateDnsHost) {
- return DevicePolicyManager.PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
- }
-
- @Override
- public int getGlobalPrivateDnsMode(ComponentName who) {
- return DevicePolicyManager.PRIVATE_DNS_MODE_UNKNOWN;
- }
-
- @Override
- public String getGlobalPrivateDnsHost(ComponentName who) {
- return null;
- }
-
- @Override
- public void grantDeviceIdsAccessToProfileOwner(ComponentName who, int userId) { }
-
- @Override
- public int getPasswordComplexity() {
- return DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
- }
-
- @Override
- public void installUpdateFromFile(ComponentName admin,
- ParcelFileDescriptor updateFileDescriptor, StartInstallingUpdateCallback listener) {}
-
- @Override
- public void setCrossProfileCalendarPackages(ComponentName admin, List<String> packageNames) {
- }
-
- @Override
- public List<String> getCrossProfileCalendarPackages(ComponentName admin) {
- return Collections.emptyList();
- }
-
- @Override
- public boolean isPackageAllowedToAccessCalendarForUser(String packageName,
- int userHandle) {
- return false;
- }
-
- @Override
- public List<String> getCrossProfileCalendarPackagesForUser(int userHandle) {
- return Collections.emptyList();
- }
-
- @Override
- public boolean isManagedKiosk() {
- return false;
- }
-
- @Override
- public boolean isUnattendedManagedKiosk() {
- return false;
- }
-
- @Override
- public boolean startViewCalendarEventInManagedProfile(String packageName, long eventId,
- long start, long end, boolean allDay, int flags) {
- return false;
- }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
index 042c9d9..3b15376 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ScheduleCalendarTest.java
@@ -415,6 +415,39 @@
}
@Test
+ public void testIsAlarmInSchedule_alarmAndNowInSchedule_sameScheduleTrigger_daylightSavings() {
+ Calendar alarm = getDaylightSavingsDay();
+ alarm.set(Calendar.HOUR_OF_DAY, 23);
+ alarm.set(Calendar.MINUTE, 15);
+ alarm.set(Calendar.SECOND, 0);
+ alarm.set(Calendar.MILLISECOND, 0);
+
+ Calendar now = getDaylightSavingsDay();
+ now.set(Calendar.HOUR_OF_DAY, 2);
+ now.set(Calendar.MINUTE, 10);
+ now.set(Calendar.SECOND, 0);
+ now.set(Calendar.MILLISECOND, 0);
+ now.add(Calendar.DATE, 1); // add a day, on daylight savings this becomes 3:10am
+
+ final Calendar tempToday = getDaylightSavingsDay();
+ final Calendar tempTomorrow = getDaylightSavingsDay();
+ tempTomorrow.add(Calendar.DATE, 1);
+ mScheduleInfo.days = new int[] {tempToday.get(Calendar.DAY_OF_WEEK),
+ tempTomorrow.get(Calendar.DAY_OF_WEEK)};
+
+ mScheduleInfo.startHour = 22;
+ mScheduleInfo.startMinute = 15;
+ mScheduleInfo.endHour = 3;
+ mScheduleInfo.endMinute = 15;
+ mScheduleCalendar.setSchedule(mScheduleInfo);
+
+ assertTrue(mScheduleCalendar.isInSchedule(alarm.getTimeInMillis()));
+ assertTrue(mScheduleCalendar.isInSchedule(now.getTimeInMillis()));
+ assertTrue(mScheduleCalendar.isAlarmInSchedule(alarm.getTimeInMillis(),
+ now.getTimeInMillis()));
+ }
+
+ @Test
public void testIsAlarmInSchedule_alarmAndNowInSchedule_sameScheduleTrigger() {
Calendar alarm = new GregorianCalendar();
alarm.set(Calendar.HOUR_OF_DAY, 23);
@@ -424,10 +457,10 @@
Calendar now = new GregorianCalendar();
now.set(Calendar.HOUR_OF_DAY, 2);
- now.set(Calendar.MINUTE, 15);
+ now.set(Calendar.MINUTE, 10);
now.set(Calendar.SECOND, 0);
now.set(Calendar.MILLISECOND, 0);
- now.add(Calendar.DATE, 1); // add a day
+ now.add(Calendar.DATE, 1); // add a day, on daylight savings this becomes 3:10am
mScheduleInfo.days = new int[] {getTodayDay(), getTodayDay(1)};
mScheduleInfo.startHour = 22;
@@ -481,4 +514,11 @@
cal.add(Calendar.DATE, offset);
return cal.get(Calendar.DAY_OF_WEEK);
}
+
+
+ private Calendar getDaylightSavingsDay() {
+ // the day before daylight savings in the US - March 9, 2019
+ Calendar daylightSavingsDay = new GregorianCalendar(2019, 2, 9);
+ return daylightSavingsDay;
+ }
}
diff --git a/tools/hiddenapi/generate_hiddenapi_lists.py b/tools/hiddenapi/generate_hiddenapi_lists.py
index 6781eba..c856cc3 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists.py
@@ -21,6 +21,7 @@
import os
import sys
import re
+import functools
# Names of flags recognized by the `hiddenapi` tool.
FLAG_WHITELIST = "whitelist"
@@ -58,6 +59,10 @@
# script to skip any entries which do not exist any more.
FLAG_IGNORE_CONFLICTS_SUFFIX = "-ignore-conflicts"
+# Suffix used in command line args to express that all apis within a given set
+# of packages should be assign the given flag.
+FLAG_PACKAGES_SUFFIX = "-packages"
+
# Regex patterns of fields/methods used in serialization. These are
# considered public API despite being hidden.
SERIALIZATION_PATTERNS = [
@@ -91,12 +96,16 @@
for flag in ALL_FLAGS:
ignore_conflicts_flag = flag + FLAG_IGNORE_CONFLICTS_SUFFIX
+ packages_flag = flag + FLAG_PACKAGES_SUFFIX
parser.add_argument('--' + flag, dest=flag, nargs='*', default=[], metavar='TXT_FILE',
help='lists of entries with flag "' + flag + '"')
parser.add_argument('--' + ignore_conflicts_flag, dest=ignore_conflicts_flag, nargs='*',
default=[], metavar='TXT_FILE',
help='lists of entries with flag "' + flag +
'". skip entry if missing or flag conflict.')
+ parser.add_argument('--' + packages_flag, dest=packages_flag, nargs='*',
+ default=[], metavar='TXT_FILE',
+ help='lists of packages to be added to ' + flag + ' list')
return parser.parse_args()
@@ -128,6 +137,19 @@
with open(filename, 'w') as f:
f.writelines(lines)
+def extract_package(signature):
+ """Extracts the package from a signature.
+
+ Args:
+ signature (string): JNI signature of a method or field.
+
+ Returns:
+ The package name of the class containing the field/method.
+ """
+ full_class_name = signature.split(";->")[0]
+ package_name = full_class_name[1:full_class_name.rindex("/")]
+ return package_name.replace('/', '.')
+
class FlagsDict:
def __init__(self):
self._dict_keyset = set()
@@ -206,7 +228,10 @@
self._dict_keyset.update([ csv[0] for csv in csv_values ])
# Check that all flags are known.
- csv_flags = set(reduce(lambda x, y: set(x).union(y), [ csv[1:] for csv in csv_values ], []))
+ csv_flags = set(functools.reduce(
+ lambda x, y: set(x).union(y),
+ [ csv[1:] for csv in csv_values ],
+ []))
self._check_flags_set(csv_flags, source)
# Iterate over all CSV lines, find entry in dict and append flags to it.
@@ -273,6 +298,15 @@
valid_entries = flags.get_valid_subset_of_unassigned_apis(read_lines(filename))
flags.assign_flag(flag, valid_entries, filename)
+ # All members in the specified packages will be assigned the appropriate flag.
+ for flag in ALL_FLAGS:
+ for filename in args[flag + FLAG_PACKAGES_SUFFIX]:
+ packages_needing_list = set(read_lines(filename))
+ should_add_signature_to_list = lambda sig,lists: extract_package(
+ sig) in packages_needing_list and not lists
+ valid_entries = flags.filter_apis(should_add_signature_to_list)
+ flags.assign_flag(flag, valid_entries)
+
# Assign all remaining entries to the blacklist.
flags.assign_flag(FLAG_BLACKLIST, flags.filter_apis(HAS_NO_API_LIST_ASSIGNED))
diff --git a/tools/hiddenapi/generate_hiddenapi_lists_test.py b/tools/hiddenapi/generate_hiddenapi_lists_test.py
index 249f37d..4dc880b 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists_test.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists_test.py
@@ -18,33 +18,23 @@
from generate_hiddenapi_lists import *
class TestHiddenapiListGeneration(unittest.TestCase):
- def test_init(self):
- # Check empty lists
- flags = FlagsDict([], [])
- self.assertEquals(flags.generate_csv(), [])
-
- # Check valid input - two public and two private API signatures.
- flags = FlagsDict(['A', 'B'], ['C', 'D'])
- self.assertEquals(flags.generate_csv(),
- [ 'A,' + FLAG_WHITELIST, 'B,' + FLAG_WHITELIST, 'C', 'D' ])
-
- # Check invalid input - overlapping public/private API signatures.
- with self.assertRaises(AssertionError):
- flags = FlagsDict(['A', 'B'], ['B', 'C', 'D'])
def test_filter_apis(self):
# Initialize flags so that A and B are put on the whitelist and
# C, D, E are left unassigned. Try filtering for the unassigned ones.
- flags = FlagsDict(['A', 'B'], ['C', 'D', 'E'])
+ flags = FlagsDict()
+ flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B,' + FLAG_WHITELIST,
+ 'C', 'D', 'E'])
filter_set = flags.filter_apis(lambda api, flags: not flags)
self.assertTrue(isinstance(filter_set, set))
self.assertEqual(filter_set, set([ 'C', 'D', 'E' ]))
def test_get_valid_subset_of_unassigned_keys(self):
# Create flags where only A is unassigned.
- flags = FlagsDict(['A'], ['B', 'C'])
+ flags = FlagsDict()
+ flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B', 'C'])
flags.assign_flag(FLAG_GREYLIST, set(['C']))
- self.assertEquals(flags.generate_csv(),
+ self.assertEqual(flags.generate_csv(),
[ 'A,' + FLAG_WHITELIST, 'B', 'C,' + FLAG_GREYLIST ])
# Check three things:
@@ -55,44 +45,30 @@
flags.get_valid_subset_of_unassigned_apis(set(['A', 'B', 'D'])), set([ 'B' ]))
def test_parse_and_merge_csv(self):
- flags = FlagsDict(['A'], ['B'])
- self.assertEquals(flags.generate_csv(), [ 'A,' + FLAG_WHITELIST, 'B' ])
+ flags = FlagsDict()
# Test empty CSV entry.
- flags.parse_and_merge_csv(['B'])
- self.assertEquals(flags.generate_csv(), [ 'A,' + FLAG_WHITELIST, 'B' ])
-
- # Test assigning an already assigned flag.
- flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST])
- self.assertEquals(flags.generate_csv(), [ 'A,' + FLAG_WHITELIST, 'B' ])
+ self.assertEqual(flags.generate_csv(), [])
# Test new additions.
flags.parse_and_merge_csv([
'A,' + FLAG_GREYLIST,
'B,' + FLAG_BLACKLIST + ',' + FLAG_GREYLIST_MAX_O ])
self.assertEqual(flags.generate_csv(),
- [ 'A,' + FLAG_GREYLIST + "," + FLAG_WHITELIST,
+ [ 'A,' + FLAG_GREYLIST,
'B,' + FLAG_BLACKLIST + "," + FLAG_GREYLIST_MAX_O ])
- # Test unknown API signature.
- with self.assertRaises(AssertionError):
- flags.parse_and_merge_csv([ 'C' ])
-
# Test unknown flag.
with self.assertRaises(AssertionError):
- flags.parse_and_merge_csv([ 'A,foo' ])
+ flags.parse_and_merge_csv([ 'C,foo' ])
def test_assign_flag(self):
- flags = FlagsDict(['A'], ['B'])
- self.assertEquals(flags.generate_csv(), [ 'A,' + FLAG_WHITELIST, 'B' ])
-
- # Test assigning an already assigned flag.
- flags.assign_flag(FLAG_WHITELIST, set([ 'A' ]))
- self.assertEquals(flags.generate_csv(), [ 'A,' + FLAG_WHITELIST, 'B' ])
+ flags = FlagsDict()
+ flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B'])
# Test new additions.
flags.assign_flag(FLAG_GREYLIST, set([ 'A', 'B' ]))
- self.assertEquals(flags.generate_csv(),
+ self.assertEqual(flags.generate_csv(),
[ 'A,' + FLAG_GREYLIST + "," + FLAG_WHITELIST, 'B,' + FLAG_GREYLIST ])
# Test invalid API signature.
@@ -103,5 +79,18 @@
with self.assertRaises(AssertionError):
flags.assign_flag('foo', set([ 'A' ]))
+ def test_extract_package(self):
+ signature = 'Lcom/foo/bar/Baz;->method1()Lcom/bar/Baz;'
+ expected_package = 'com.foo.bar'
+ self.assertEqual(extract_package(signature), expected_package)
+
+ signature = 'Lcom/foo1/bar/MyClass;->method2()V'
+ expected_package = 'com.foo1.bar'
+ self.assertEqual(extract_package(signature), expected_package)
+
+ signature = 'Lcom/foo_bar/baz/MyClass;->method3()V'
+ expected_package = 'com.foo_bar.baz'
+ self.assertEqual(extract_package(signature), expected_package)
+
if __name__ == '__main__':
unittest.main()