Merge "Catch Activity Not Found Exception when switching to specific TV input."
diff --git a/api/current.txt b/api/current.txt
index ff93504..0652fdd 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12388,7 +12388,7 @@
method public String getPositionDescription();
method @AnyRes public int getResourceId(@StyleableRes int, int);
method public android.content.res.Resources getResources();
- method @StyleRes public int getSourceStyleResourceId(@StyleableRes int, @StyleRes int);
+ method @StyleRes public int getSourceResourceId(@StyleableRes int, @StyleRes int);
method @Nullable public String getString(@StyleableRes int);
method public CharSequence getText(@StyleableRes int);
method public CharSequence[] getTextArray(@StyleableRes int);
@@ -43848,12 +43848,12 @@
public class TelecomManager {
method public void acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle);
- method @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall();
- method @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall(int);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall();
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall(int);
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void cancelMissedCallsNotification();
method public android.content.Intent createManageBlockedNumbersIntent();
- method @RequiresPermission(android.Manifest.permission.ANSWER_PHONE_CALLS) public boolean endCall();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.ANSWER_PHONE_CALLS) public boolean endCall();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts();
method public String getDefaultDialerPackage();
@@ -48449,6 +48449,7 @@
method public static boolean logEvent(int);
method public static boolean logStart(int);
method public static boolean logStop(int);
+ method public static void write(int, @NonNull java.lang.Object...);
}
public class StringBuilderPrinter implements android.util.Printer {
@@ -48534,7 +48535,7 @@
field public int data;
field public int density;
field @AnyRes public int resourceId;
- field public int sourceStyleResourceId;
+ field public int sourceResourceId;
field public CharSequence string;
field public int type;
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 8714c0f..8d98bc1 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -9208,6 +9208,21 @@
method public int getUid();
}
+ public class StatsLogAtoms {
+ field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED = 170; // 0xaa
+ field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_DENIED = 8; // 0x8
+ field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED = 5; // 0x5
+ field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED = 1; // 0x1
+ field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED = 3; // 0x3
+ field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_FIXED = 2; // 0x2
+ field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED = 6; // 0x6
+ field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE = 7; // 0x7
+ field public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED = 4; // 0x4
+ }
+
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(prefix="PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__", value={android.util.StatsLogAtoms.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED, android.util.StatsLogAtoms.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_FIXED, android.util.StatsLogAtoms.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED, android.util.StatsLogAtoms.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED, android.util.StatsLogAtoms.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED, android.util.StatsLogAtoms.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED, android.util.StatsLogAtoms.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE, android.util.StatsLogAtoms.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_DENIED}) public static @interface StatsLogAtoms.PermissionGrantRequestResultReported_Result {
+ }
+
}
package android.view {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 9a6387a..751b3e4 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -236,6 +236,7 @@
BluetoothSmpPairingEventReported bluetooth_smp_pairing_event_reported = 167;
ScreenTimeoutExtensionReported screen_timeout_extension_reported = 168;
ProcessStartTime process_start_time = 169;
+ PermissionGrantRequestResultReported permission_grant_request_result_reported = 170;
}
// Pulled events will start at field 10000.
@@ -5097,6 +5098,48 @@
}
/**
+ * Information about a permission grant request
+ */
+message PermissionGrantRequestResultReported {
+ // unique value identifying an API call. A API call might result in multiple of these atoms
+ optional int64 request_id = 1;
+
+ // UID of package requesting the permission grant
+ optional int32 requesting_uid = 2 [(is_uid) = true];
+
+ // Name of package requesting the permission grant
+ optional string requesting_package_name = 3;
+
+ // The permission to be granted
+ optional string permission_name = 4;
+
+ // If the permission was explicitly requested via the API or added by the system
+ optional bool is_implicit = 5;
+
+ enum Result {
+ UNDEFINED = 0;
+ // permission request was ignored
+ IGNORED = 1;
+ // permission request was ignored because it was user fixed
+ IGNORED_USER_FIXED = 2;
+ // permission request was ignored because it was policy fixed
+ IGNORED_POLICY_FIXED = 3;
+ // permission was granted by user action
+ USER_GRANTED = 4;
+ // permission was automatically granted
+ AUTO_GRANTED = 5;
+ // permission was denied by user action
+ USER_DENIED = 6;
+ // permission was denied with prejudice by the user
+ USER_DENIED_WITH_PREJUDICE = 7;
+ // permission was automatically denied
+ AUTO_DENIED = 8;
+ }
+ // The result of the permission grant
+ optional Result result = 6;
+}
+
+/**
* Logs when Omapi API used
* Logged from:
* packages/apps/SecureElement/src/com/android/se/Terminal.java
diff --git a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
index d9aba61..fc7b778 100644
--- a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
+++ b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
@@ -32,7 +32,8 @@
import java.io.File;
import java.io.IOException;
-import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
@@ -60,6 +61,7 @@
};
private static final Logger LOGGER = Logger.getLogger(TestDrive.class.getName());
+ private String mAdditionalAllowedPackage;
private final Set<Long> mTrackedMetrics = new HashSet<>();
public static void main(String[] args) {
@@ -69,11 +71,16 @@
String remoteConfigPath = null;
if (args.length < 1) {
- LOGGER.log(Level.SEVERE, "Usage: ./test_drive <atomId1> <atomId2> ... <atomIdN>");
+ LOGGER.log(Level.SEVERE, "Usage: ./test_drive [-p additional_allowed_package] "
+ + "<atomId1> <atomId2> ... <atomIdN>");
return;
}
- for (int i = 0; i < args.length; i++) {
+ if (args.length >= 3 && args[0].equals("-p")) {
+ testDrive.mAdditionalAllowedPackage = args[1];
+ }
+
+ for (int i = testDrive.mAdditionalAllowedPackage == null ? 0 : 2; i < args.length; i++) {
try {
int atomId = Integer.valueOf(args[i]);
if (Atom.getDescriptor().findFieldByNumber(atomId) == null) {
@@ -137,9 +144,15 @@
long metricId = METRIC_ID_BASE;
long atomMatcherId = ATOM_MATCHER_ID_BASE;
+ ArrayList<String> allowedSources = new ArrayList<>();
+ Collections.addAll(allowedSources, ALLOWED_LOG_SOURCES);
+ if (mAdditionalAllowedPackage != null) {
+ allowedSources.add(mAdditionalAllowedPackage);
+ }
+
StatsdConfig.Builder builder = StatsdConfig.newBuilder();
builder
- .addAllAllowedLogSource(Arrays.asList(ALLOWED_LOG_SOURCES))
+ .addAllAllowedLogSource(allowedSources)
.setHashStringsInMetricReport(false);
for (int atomId : atomIds) {
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index d53834c..d36e076 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -72,7 +72,7 @@
static final int STYLE_RESOURCE_ID = 3;
static final int STYLE_CHANGING_CONFIGURATIONS = 4;
static final int STYLE_DENSITY = 5;
- static final int SYTLE_SOURCE_STYLE_RESOURCE_ID = 6;
+ static final int SYTLE_SOURCE_RESOURCE_ID = 6;
@UnsupportedAppUsage
private final Resources mResources;
@@ -1101,28 +1101,51 @@
}
/**
- * Returns the resource ID of the style against which the specified attribute was resolved,
- * otherwise returns defValue.
+ * Returns the resource ID of the style or layout against which the specified attribute was
+ * resolved, otherwise returns defValue.
+ *
+ * For example, if you we resolving two attributes {@code android:attribute1} and
+ * {@code android:attribute2} and you were inflating a {@link android.view.View} from
+ * {@code layout/my_layout.xml}:
+ * <pre>
+ * <View
+ * style="@style/viewStyle"
+ * android:layout_width="wrap_content"
+ * android:layout_height="wrap_content"
+ * android:attribute1="foo"/>
+ * </pre>
+ *
+ * and {@code @style/viewStyle} is:
+ * <pre>
+ * <style android:name="viewStyle">
+ * <item name="android:attribute2">bar<item/>
+ * <style/>
+ * </pre>
+ *
+ * then resolved {@link TypedArray} will have values that return source resource ID of
+ * {@code R.layout.my_layout} for {@code android:attribute1} and {@code R.style.viewStyle} for
+ * {@code android:attribute2}.
*
* @param index Index of attribute whose source style to retrieve.
- * @param defValue Value to return if the attribute is not defined or
- * not a resource.
+ * @param defaultValue Value to return if the attribute is not defined or
+ * not a resource.
*
- * @return Attribute source style resource ID or defValue if it was not resolved in any style.
+ * @return Either a style resource ID, layout resource ID, or defaultValue if it was not
+ * resolved in a style or layout.
* @throws RuntimeException if the TypedArray has already been recycled.
*/
@StyleRes
- public int getSourceStyleResourceId(@StyleableRes int index, @StyleRes int defValue) {
+ public int getSourceResourceId(@StyleableRes int index, @StyleRes int defaultValue) {
if (mRecycled) {
throw new RuntimeException("Cannot make calls to a recycled instance!");
}
index *= STYLE_NUM_ENTRIES;
- final int resid = mData[index + SYTLE_SOURCE_STYLE_RESOURCE_ID];
+ final int resid = mData[index + SYTLE_SOURCE_RESOURCE_ID];
if (resid != 0) {
return resid;
}
- return defValue;
+ return defaultValue;
}
/**
@@ -1337,7 +1360,7 @@
data[index + STYLE_CHANGING_CONFIGURATIONS]);
outValue.density = data[index + STYLE_DENSITY];
outValue.string = (type == TypedValue.TYPE_STRING) ? loadStringValueAt(index) : null;
- outValue.sourceStyleResourceId = data[index + SYTLE_SOURCE_STYLE_RESOURCE_ID];
+ outValue.sourceResourceId = data[index + SYTLE_SOURCE_RESOURCE_ID];
return true;
}
diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java
index d8c3dde..626bf77 100644
--- a/core/java/android/content/res/XmlBlock.java
+++ b/core/java/android/content/res/XmlBlock.java
@@ -82,23 +82,22 @@
public XmlResourceParser newParser(@AnyRes int resId) {
synchronized (this) {
if (mNative != 0) {
- return new Parser(nativeCreateParseState(mNative), this, resId);
+ return new Parser(nativeCreateParseState(mNative, resId), this);
}
return null;
}
}
/*package*/ final class Parser implements XmlResourceParser {
- Parser(long parseState, XmlBlock block, @AnyRes int sourceResId) {
+ Parser(long parseState, XmlBlock block) {
mParseState = parseState;
mBlock = block;
block.mOpenCount++;
- mSourceResId = sourceResId;
}
@AnyRes
public int getSourceResId() {
- return mSourceResId;
+ return nativeGetSourceResId(mParseState);
}
public void setFeature(String name, boolean state) throws XmlPullParserException {
@@ -486,7 +485,6 @@
private boolean mDecNextDepth = false;
private int mDepth = 0;
private int mEventType = START_DOCUMENT;
- private @AnyRes int mSourceResId;
}
protected void finalize() throws Throwable {
@@ -515,7 +513,7 @@
int offset,
int size);
private static final native long nativeGetStringBlock(long obj);
- private static final native long nativeCreateParseState(long obj);
+ private static final native long nativeCreateParseState(long obj, int resId);
private static final native void nativeDestroyParseState(long state);
private static final native void nativeDestroy(long obj);
@@ -553,4 +551,6 @@
private static final native int nativeGetStyleAttribute(long state);
@FastNative
private static final native int nativeGetAttributeIndex(long state, String namespace, String name);
+ @FastNative
+ private static final native int nativeGetSourceResId(long state);
}
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 850d020..c59e573 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -269,6 +269,7 @@
public void getRuntimePermissionBackup(@NonNull UserHandle user,
@NonNull @CallbackExecutor Executor executor,
@NonNull OnGetRuntimePermissionBackupCallback callback) {
+ checkNotNull(user);
checkNotNull(executor);
checkNotNull(callback);
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 70404c3..482f4a8 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -56,7 +56,7 @@
/**
* This service is meant to be implemented by the app controlling permissions.
*
- * @see PermissionController
+ * @see PermissionControllerManager
*
* @hide
*/
@@ -98,10 +98,10 @@
* Create a backup of the runtime permissions.
*
* @param user The user to back up
- * @param out The stream to write the backup to
+ * @param backup The stream to write the backup to
*/
public abstract void onGetRuntimePermissionsBackup(@NonNull UserHandle user,
- @NonNull OutputStream out);
+ @NonNull OutputStream backup);
/**
* Gets the runtime permissions for an app.
@@ -297,11 +297,11 @@
}
private void getRuntimePermissionsBackup(@NonNull UserHandle user,
- @NonNull ParcelFileDescriptor outFile) {
- try (OutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(outFile)) {
- onGetRuntimePermissionsBackup(user, out);
+ @NonNull ParcelFileDescriptor backupFile) {
+ try (OutputStream backup = new ParcelFileDescriptor.AutoCloseOutputStream(backupFile)) {
+ onGetRuntimePermissionsBackup(user, backup);
} catch (IOException e) {
- Log.e(LOG_TAG, "Could not open pipe to write backup tp", e);
+ Log.e(LOG_TAG, "Could not open pipe to write backup to", e);
}
}
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index bec654a..bff118e 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -958,13 +958,15 @@
if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_MESSAGES,
isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_MESSAGES, defaultPolicy))) {
priorityCategories |= Policy.PRIORITY_CATEGORY_MESSAGES;
- messageSenders = getNotificationPolicySenders(zenPolicy.getPriorityMessageSenders());
+ messageSenders = getNotificationPolicySenders(zenPolicy.getPriorityMessageSenders(),
+ messageSenders);
}
if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_CALLS,
isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_CALLS, defaultPolicy))) {
priorityCategories |= Policy.PRIORITY_CATEGORY_CALLS;
- callSenders = getNotificationPolicySenders(zenPolicy.getPriorityCallSenders());
+ callSenders = getNotificationPolicySenders(zenPolicy.getPriorityCallSenders(),
+ callSenders);
}
if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS,
@@ -1056,16 +1058,17 @@
return (policy.suppressedVisualEffects & visualEffect) == 0;
}
- private int getNotificationPolicySenders(@ZenPolicy.PeopleType int senders) {
+ private int getNotificationPolicySenders(@ZenPolicy.PeopleType int senders,
+ int defaultPolicySender) {
switch (senders) {
case ZenPolicy.PEOPLE_TYPE_ANYONE:
return Policy.PRIORITY_SENDERS_ANY;
case ZenPolicy.PEOPLE_TYPE_CONTACTS:
-
return Policy.PRIORITY_SENDERS_CONTACTS;
case ZenPolicy.PEOPLE_TYPE_STARRED:
- default:
return Policy.PRIORITY_SENDERS_STARRED;
+ default:
+ return defaultPolicySender;
}
}
diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java
index e3de307..ace4bf4 100644
--- a/core/java/android/util/StatsLog.java
+++ b/core/java/android/util/StatsLog.java
@@ -16,6 +16,7 @@
package android.util;
+import android.annotation.NonNull;
import android.os.IStatsManager;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -113,4 +114,18 @@
sService = IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
return sService;
}
+
+ /**
+ * Add a log to the stats log.
+ *
+ * @param id The id of the atom
+ * @param params The parameters of the atom's message.
+ */
+ public static void write(int id, @NonNull Object... params) {
+ switch (id) {
+ case PERMISSION_GRANT_REQUEST_RESULT_REPORTED:
+ write(id, (long) params[0], (int) params[1], (String) params[2], (String) params[3],
+ (boolean) params[4], (int) params[5]);
+ }
+ }
}
diff --git a/core/java/android/util/StatsLogAtoms.java b/core/java/android/util/StatsLogAtoms.java
new file mode 100644
index 0000000..bbede53
--- /dev/null
+++ b/core/java/android/util/StatsLogAtoms.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+
+import java.lang.annotation.Retention;
+
+/**
+ * Exposed stats logs atom ids.
+ *
+ * @hide
+ */
+@SystemApi
+public class StatsLogAtoms {
+ private StatsLogAtoms() {
+ }
+
+ /**
+ * Information about a permission grant request
+ *
+ * Usage: {@code StatsLog.write(PERMISSION_GRANT_REQUEST_RESULT_REPORTED, long request_id,
+ * int requesting_uid, String requesting_package_name, String permission_name,
+ * boolean is_implicit, @PermissionGrantRequestResultReported_Result int result)}
+ */
+ public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED =
+ StatsLogInternal.PERMISSION_GRANT_REQUEST_RESULT_REPORTED;
+
+ @Retention(SOURCE)
+ @IntDef(prefix = "PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__",
+ value = {PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_FIXED,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE,
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_DENIED})
+ public @interface PermissionGrantRequestResultReported_Result {}
+
+ /**
+ * Possible value of {@link PermissionGrantRequestResultReported_Result}:
+ * permission request was ignored
+ */
+ public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED =
+ StatsLogInternal.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED;
+
+ /**
+ * Possible value of {@link PermissionGrantRequestResultReported_Result}:
+ * permission request was ignored because it was user fixed
+ */
+ public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_FIXED =
+ StatsLogInternal.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_USER_FIXED;
+
+ /**
+ * Possible value of {@link PermissionGrantRequestResultReported_Result}:
+ * permission request was ignored because it was policy fixed
+ */
+ public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED =
+ StatsLogInternal.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__IGNORED_POLICY_FIXED;
+
+ /**
+ * Possible value of {@link PermissionGrantRequestResultReported_Result}:
+ * permission was granted by user action
+ */
+ public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED =
+ StatsLogInternal.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED;
+
+ /**
+ * Possible value of {@link PermissionGrantRequestResultReported_Result}:
+ * permission was automatically granted
+ */
+ public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED =
+ StatsLogInternal.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_GRANTED;
+
+ /**
+ * Possible value of {@link PermissionGrantRequestResultReported_Result}:
+ * permission was denied by user action
+ */
+ public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED =
+ StatsLogInternal.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED;
+
+ /**
+ * Possible value of {@link PermissionGrantRequestResultReported_Result}:
+ * permission was denied with prejudice by the user
+ */
+ public static final int
+ PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE =
+ StatsLogInternal
+ .PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE;
+
+ /**
+ * Possible value of {@link PermissionGrantRequestResultReported_Result}:
+ * permission was automatically denied
+ */
+ public static final int PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_DENIED =
+ StatsLogInternal.PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__AUTO_DENIED;
+}
diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java
index 99106be..7f1ee30 100644
--- a/core/java/android/util/TypedValue.java
+++ b/core/java/android/util/TypedValue.java
@@ -217,10 +217,10 @@
public int density;
/**
- * If the Value came from a style resource, this holds the corresponding style resource id
- * against which the attribute was resolved.
+ * If the Value came from a style resource or a layout resource (set in an XML layout), this
+ * holds the corresponding style or layout resource id against which the attribute was resolved.
*/
- public int sourceStyleResourceId;
+ public int sourceResourceId;
/* ------------------------------------------------------------ */
diff --git a/core/jni/android_util_XmlBlock.cpp b/core/jni/android_util_XmlBlock.cpp
index ad6bad2..1dc6834 100644
--- a/core/jni/android_util_XmlBlock.cpp
+++ b/core/jni/android_util_XmlBlock.cpp
@@ -72,7 +72,7 @@
}
static jlong android_content_XmlBlock_nativeCreateParseState(JNIEnv* env, jobject clazz,
- jlong token)
+ jlong token, jint res_id)
{
ResXMLTree* osb = reinterpret_cast<ResXMLTree*>(token);
if (osb == NULL) {
@@ -81,6 +81,7 @@
}
ResXMLParser* st = new ResXMLParser(*osb);
+ st->setSourceResourceId(res_id);
if (st == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
return 0;
@@ -335,6 +336,17 @@
? value.data : 0;
}
+static jint android_content_XmlBlock_nativeGetSourceResId(JNIEnv* env, jobject clazz,
+ jlong token)
+{
+ ResXMLParser* st = reinterpret_cast<ResXMLParser*>(token);
+ if (st == NULL) {
+ return 0;
+ } else {
+ return st->getSourceResourceId();
+ }
+}
+
static void android_content_XmlBlock_nativeDestroyParseState(JNIEnv* env, jobject clazz,
jlong token)
{
@@ -370,7 +382,7 @@
(void*) android_content_XmlBlock_nativeCreate },
{ "nativeGetStringBlock", "(J)J",
(void*) android_content_XmlBlock_nativeGetStringBlock },
- { "nativeCreateParseState", "(J)J",
+ { "nativeCreateParseState", "(JI)J",
(void*) android_content_XmlBlock_nativeCreateParseState },
{ "nativeDestroyParseState", "(J)V",
(void*) android_content_XmlBlock_nativeDestroyParseState },
@@ -411,6 +423,8 @@
(void*) android_content_XmlBlock_nativeGetClassAttribute },
{ "nativeGetStyleAttribute", "(J)I",
(void*) android_content_XmlBlock_nativeGetStyleAttribute },
+ { "nativeGetSourceResId", "(J)I",
+ (void*) android_content_XmlBlock_nativeGetSourceResId},
};
int register_android_content_XmlBlock(JNIEnv* env)
diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp
index 18d74ef..cc177af 100644
--- a/libs/androidfw/AttributeResolution.cpp
+++ b/libs/androidfw/AttributeResolution.cpp
@@ -286,7 +286,7 @@
value.dataType = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
config.density = 0;
- uint32_t source_style_resid = 0;
+ uint32_t value_source_resid = 0;
// Try to find a value for this attribute... we prioritize values
// coming from, first XML attributes, then XML style, then default
@@ -300,6 +300,7 @@
if (kDebugStyles) {
ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
}
+ value_source_resid = xml_parser->getSourceResourceId();
}
if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
@@ -310,7 +311,7 @@
cookie = entry->cookie;
type_set_flags = style_flags;
value = entry->value;
- source_style_resid = entry->style;
+ value_source_resid = entry->style;
if (kDebugStyles) {
ALOGI("-> From style: type=0x%x, data=0x%08x, style=0x%08x", value.dataType, value.data,
entry->style);
@@ -330,7 +331,7 @@
ALOGI("-> From def style: type=0x%x, data=0x%08x, style=0x%08x", value.dataType, value.data,
entry->style);
}
- source_style_resid = entry->style;
+ value_source_resid = entry->style;
}
}
@@ -349,6 +350,7 @@
} else if (value.data != Res_value::DATA_NULL_EMPTY) {
// If we still don't have a value for this attribute, try to find it in the theme!
ApkAssetsCookie new_cookie = theme->GetAttribute(cur_ident, &value, &type_set_flags);
+ // TODO: set value_source_resid for the style in the theme that was used.
if (new_cookie != kInvalidCookie) {
if (kDebugStyles) {
ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
@@ -386,7 +388,7 @@
out_values[STYLE_RESOURCE_ID] = resid;
out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
out_values[STYLE_DENSITY] = config.density;
- out_values[SYTLE_SOURCE_STYLE] = source_style_resid;
+ out_values[SYTLE_SOURCE_RESOURCE_ID] = value_source_resid;
if (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY) {
indices_idx++;
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 63b2527..11e4cb8 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -1594,6 +1594,16 @@
mCurExt = pos.curExt;
}
+void ResXMLParser::setSourceResourceId(const uint32_t resId)
+{
+ mSourceResourceId = resId;
+}
+
+uint32_t ResXMLParser::getSourceResourceId() const
+{
+ return mSourceResourceId;
+}
+
// --------------------------------------------------------------------
static volatile int32_t gCount = 0;
diff --git a/libs/androidfw/include/androidfw/AttributeResolution.h b/libs/androidfw/include/androidfw/AttributeResolution.h
index c88004c..0cc1d3c 100644
--- a/libs/androidfw/include/androidfw/AttributeResolution.h
+++ b/libs/androidfw/include/androidfw/AttributeResolution.h
@@ -33,7 +33,7 @@
STYLE_RESOURCE_ID = 3,
STYLE_CHANGING_CONFIGURATIONS = 4,
STYLE_DENSITY = 5,
- SYTLE_SOURCE_STYLE = 6
+ SYTLE_SOURCE_RESOURCE_ID = 6
};
// These are all variations of the same method. They each perform the exact same operation,
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 1655e89..742813e 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -782,6 +782,9 @@
void getPosition(ResXMLPosition* pos) const;
void setPosition(const ResXMLPosition& pos);
+ void setSourceResourceId(const uint32_t resId);
+ uint32_t getSourceResourceId() const;
+
private:
friend class ResXMLTree;
@@ -791,6 +794,7 @@
event_code_t mEventCode;
const ResXMLTree_node* mCurNode;
const void* mCurExt;
+ uint32_t mSourceResourceId;
};
class DynamicRefTable;
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 297a418..7c42cc2 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -393,15 +393,6 @@
"persist.sys.hdmi.property_sytem_audio_mode_audio_port";
/**
- * Property to indicate if a CEC audio device should forward volume keys when system audio mode
- * is off.
- *
- * <p>Default is false.
- */
- static final String PROPERTY_CEC_AUDIO_DEVICE_FORWARD_VOLUME_KEYS_SYSTEM_AUDIO_MODE_OFF =
- "persist.sys.hdmi.property_cec_audio_device_forward_volume_keys_system_audio_mode_off";
-
- /**
* Property to strip local audio of amplifier and use local speaker
* when TV does not support system audio mode.
*
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index f3a1e46..c5eccdf 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1392,11 +1392,15 @@
}
@Override
+ @Nullable
public HdmiDeviceInfo getActiveSource() {
enforceAccessPermission();
HdmiCecLocalDeviceTv tv = tv();
if (tv == null) {
- Slog.w(TAG, "Local tv device not available");
+ if (isTvDevice()) {
+ Slog.e(TAG, "Local tv device not available.");
+ return null;
+ }
if (isPlaybackDevice()) {
// if playback device itself is the active source,
// return its own device info.
@@ -1457,7 +1461,10 @@
HdmiControlService.this, deviceId, callback));
return;
}
- Slog.w(TAG, "Local tv device not available");
+ if (isTvDevice()) {
+ Slog.e(TAG, "Local tv device not available");
+ return;
+ }
invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE);
return;
}
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index bc68dde..5030e34 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -376,7 +376,7 @@
version = mVersion;
packagesHash = mPackagesHash;
- roles = getRoleHolders();
+ roles = snapshotRolesLocked();
}
AtomicFile atomicFile = new AtomicFile(getFile(mUserId), "roles-" + mUserId);
@@ -541,7 +541,7 @@
version = mVersion;
packagesHash = mPackagesHash;
- roles = getRoleHolders();
+ roles = snapshotRolesLocked();
}
long fieldToken = dumpOutputStream.start(fieldName, fieldId);
@@ -578,18 +578,23 @@
@NonNull
public ArrayMap<String, ArraySet<String>> getRoleHolders() {
synchronized (mLock) {
- ArrayMap<String, ArraySet<String>> roles = new ArrayMap<>();
- for (int i = 0, size = CollectionUtils.size(mRoles); i < size; ++i) {
- String roleName = mRoles.keyAt(i);
- ArraySet<String> roleHolders = mRoles.valueAt(i);
-
- roleHolders = new ArraySet<>(roleHolders);
- roles.put(roleName, roleHolders);
- }
- return roles;
+ return snapshotRolesLocked();
}
}
+ @GuardedBy("mLock")
+ private ArrayMap<String, ArraySet<String>> snapshotRolesLocked() {
+ ArrayMap<String, ArraySet<String>> roles = new ArrayMap<>();
+ for (int i = 0, size = CollectionUtils.size(mRoles); i < size; ++i) {
+ String roleName = mRoles.keyAt(i);
+ ArraySet<String> roleHolders = mRoles.valueAt(i);
+
+ roleHolders = new ArraySet<>(roleHolders);
+ roles.put(roleName, roleHolders);
+ }
+ return roles;
+ }
+
/**
* Destroy this user state and delete the corresponding file. Any pending writes to the file
* will be cancelled, and any future interaction with this state will throw an exception.
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
old mode 100644
new mode 100755
index c1607e9..f08e585
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -24,7 +24,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.PackageManager;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiHotplugEvent;
@@ -46,7 +45,6 @@
import android.media.tv.TvInputHardwareInfo;
import android.media.tv.TvInputInfo;
import android.media.tv.TvStreamConfig;
-import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -56,7 +54,6 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import android.view.KeyEvent;
import android.view.Surface;
import com.android.internal.util.DumpUtils;
@@ -943,7 +940,7 @@
sinkChannelMask = sinkConfig.channelMask();
}
if (sinkFormat == AudioFormat.ENCODING_DEFAULT) {
- sinkChannelMask = sinkConfig.format();
+ sinkFormat = sinkConfig.format();
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index 68d3e4c..9c7e028 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -67,7 +67,7 @@
@Test
public void testZenPolicyNothingSetToNotificationPolicy() {
- ZenModeConfig config = getMutedAllConfig();
+ ZenModeConfig config = getCustomConfig();
ZenPolicy zenPolicy = new ZenPolicy.Builder().build();
assertEquals(config.toNotificationPolicy(), config.toNotificationPolicy(zenPolicy));
}
@@ -219,6 +219,25 @@
return config;
}
+ private ZenModeConfig getCustomConfig() {
+ ZenModeConfig config = new ZenModeConfig();
+ // Some sounds allowed
+ config.allowAlarms = true;
+ config.allowMedia = false;
+ config.allowSystem = false;
+ config.allowCalls = true;
+ config.allowRepeatCallers = true;
+ config.allowMessages = false;
+ config.allowReminders = false;
+ config.allowEvents = false;
+ config.areChannelsBypassingDnd = false;
+ config.allowCallsFrom = ZenModeConfig.SOURCE_ANYONE;
+ config.allowMessagesFrom = ZenModeConfig.SOURCE_ANYONE;
+
+ config.suppressedVisualEffects = 0;
+ return config;
+ }
+
private ZenModeConfig getMutedAllConfig() {
ZenModeConfig config = new ZenModeConfig();
// No sounds allowed
diff --git a/startop/view_compiler/dex_builder.cc b/startop/view_compiler/dex_builder.cc
index a78f7d5..4c1a0dc7 100644
--- a/startop/view_compiler/dex_builder.cc
+++ b/startop/view_compiler/dex_builder.cc
@@ -21,8 +21,6 @@
#include <fstream>
#include <memory>
-#define DCHECK_NOT_NULL(p) DCHECK((p) != nullptr)
-
namespace startop {
namespace dex {
@@ -32,6 +30,8 @@
using ::dex::kAccPublic;
using Op = Instruction::Op;
+using Opcode = ::art::Instruction::Code;
+
const TypeDescriptor TypeDescriptor::Int() { return TypeDescriptor{"I"}; };
const TypeDescriptor TypeDescriptor::Void() { return TypeDescriptor{"V"}; };
@@ -42,6 +42,23 @@
// Strings lengths can be 32 bits long, but encoded as LEB128 this can take up to five bytes.
constexpr size_t kMaxEncodedStringLength{5};
+// Converts invoke-* to invoke-*/range
+constexpr Opcode InvokeToInvokeRange(Opcode opcode) {
+ switch (opcode) {
+ case ::art::Instruction::INVOKE_VIRTUAL:
+ return ::art::Instruction::INVOKE_VIRTUAL_RANGE;
+ case ::art::Instruction::INVOKE_DIRECT:
+ return ::art::Instruction::INVOKE_DIRECT_RANGE;
+ case ::art::Instruction::INVOKE_STATIC:
+ return ::art::Instruction::INVOKE_STATIC_RANGE;
+ case ::art::Instruction::INVOKE_INTERFACE:
+ return ::art::Instruction::INVOKE_INTERFACE_RANGE;
+ default:
+ LOG(FATAL) << opcode << " is not a recognized invoke opcode.";
+ UNREACHABLE();
+ }
+}
+
} // namespace
std::ostream& operator<<(std::ostream& out, const Instruction::Op& opcode) {
@@ -55,6 +72,9 @@
case Instruction::Op::kMove:
out << "kMove";
return out;
+ case Instruction::Op::kMoveObject:
+ out << "kMoveObject";
+ return out;
case Instruction::Op::kInvokeVirtual:
out << "kInvokeVirtual";
return out;
@@ -233,6 +253,11 @@
return shorty;
}
+const TypeDescriptor& Prototype::ArgType(size_t index) const {
+ CHECK_LT(index, param_types_.size());
+ return param_types_[index];
+}
+
ClassBuilder::ClassBuilder(DexBuilder* parent, const std::string& name, ir::Class* class_def)
: parent_(parent), type_descriptor_{TypeDescriptor::FromClassname(name)}, class_(class_def) {}
@@ -257,10 +282,10 @@
method->access_flags = kAccPublic | ::dex::kAccStatic;
auto* code = dex_->Alloc<ir::Code>();
- DCHECK_NOT_NULL(decl_->prototype);
+ CHECK(decl_->prototype != nullptr);
size_t const num_args =
decl_->prototype->param_types != nullptr ? decl_->prototype->param_types->types.size() : 0;
- code->registers = num_registers_ + num_args;
+ code->registers = num_registers_ + num_args + kMaxScratchRegisters;
code->ins_count = num_args;
EncodeInstructions();
code->instructions = slicer::ArrayView<const ::dex::u2>(buffer_.data(), buffer_.size());
@@ -292,7 +317,7 @@
}
void MethodBuilder::BuildConst4(Value target, int value) {
- DCHECK_LT(value, 16);
+ CHECK_LT(value, 16);
AddInstruction(Instruction::OpWithArgs(Op::kMove, target, Value::Immediate(value)));
}
@@ -315,6 +340,7 @@
case Instruction::Op::kReturnObject:
return EncodeReturn(instruction, ::art::Instruction::RETURN_OBJECT);
case Instruction::Op::kMove:
+ case Instruction::Op::kMoveObject:
return EncodeMove(instruction);
case Instruction::Op::kInvokeVirtual:
return EncodeInvoke(instruction, art::Instruction::INVOKE_VIRTUAL);
@@ -338,33 +364,43 @@
}
void MethodBuilder::EncodeReturn(const Instruction& instruction, ::art::Instruction::Code opcode) {
- DCHECK(!instruction.dest().has_value());
+ CHECK(!instruction.dest().has_value());
if (instruction.args().size() == 0) {
Encode10x(art::Instruction::RETURN_VOID);
} else {
- DCHECK_EQ(1, instruction.args().size());
+ CHECK_EQ(1, instruction.args().size());
size_t source = RegisterValue(instruction.args()[0]);
Encode11x(opcode, source);
}
}
void MethodBuilder::EncodeMove(const Instruction& instruction) {
- DCHECK_EQ(Instruction::Op::kMove, instruction.opcode());
- DCHECK(instruction.dest().has_value());
- DCHECK(instruction.dest()->is_register() || instruction.dest()->is_parameter());
- DCHECK_EQ(1, instruction.args().size());
+ CHECK(Instruction::Op::kMove == instruction.opcode() ||
+ Instruction::Op::kMoveObject == instruction.opcode());
+ CHECK(instruction.dest().has_value());
+ CHECK(instruction.dest()->is_variable());
+ CHECK_EQ(1, instruction.args().size());
const Value& source = instruction.args()[0];
if (source.is_immediate()) {
// TODO: support more registers
- DCHECK_LT(RegisterValue(*instruction.dest()), 16);
+ CHECK_LT(RegisterValue(*instruction.dest()), 16);
Encode11n(art::Instruction::CONST_4, RegisterValue(*instruction.dest()), source.value());
} else if (source.is_string()) {
constexpr size_t kMaxRegisters = 256;
- DCHECK_LT(RegisterValue(*instruction.dest()), kMaxRegisters);
- DCHECK_LT(source.value(), 65536); // make sure we don't need a jumbo string
+ CHECK_LT(RegisterValue(*instruction.dest()), kMaxRegisters);
+ CHECK_LT(source.value(), 65536); // make sure we don't need a jumbo string
Encode21c(::art::Instruction::CONST_STRING, RegisterValue(*instruction.dest()), source.value());
+ } else if (source.is_variable()) {
+ // For the moment, we only use this when we need to reshuffle registers for
+ // an invoke instruction, meaning we are too big for the 4-bit version.
+ // We'll err on the side of caution and always generate the 16-bit form of
+ // the instruction.
+ Opcode opcode = instruction.opcode() == Instruction::Op::kMove
+ ? ::art::Instruction::MOVE_16
+ : ::art::Instruction::MOVE_OBJECT_16;
+ Encode32x(opcode, RegisterValue(*instruction.dest()), RegisterValue(source));
} else {
UNIMPLEMENTED(FATAL);
}
@@ -373,22 +409,61 @@
void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::art::Instruction::Code opcode) {
constexpr size_t kMaxArgs = 5;
+ // Currently, we only support up to 5 arguments.
CHECK_LE(instruction.args().size(), kMaxArgs);
uint8_t arguments[kMaxArgs]{};
+ bool has_long_args = false;
for (size_t i = 0; i < instruction.args().size(); ++i) {
CHECK(instruction.args()[i].is_variable());
arguments[i] = RegisterValue(instruction.args()[i]);
+ if (!IsShortRegister(arguments[i])) {
+ has_long_args = true;
+ }
}
- Encode35c(opcode,
- instruction.args().size(),
- instruction.method_id(),
- arguments[0],
- arguments[1],
- arguments[2],
- arguments[3],
- arguments[4]);
+ if (has_long_args) {
+ // Some of the registers don't fit in the four bit short form of the invoke
+ // instruction, so we need to do an invoke/range. To do this, we need to
+ // first move all the arguments into contiguous temporary registers.
+ std::array<Value, kMaxArgs> scratch{GetScratchRegisters<kMaxArgs>()};
+
+ const auto& prototype = dex_->GetPrototypeByMethodId(instruction.method_id());
+ CHECK(prototype.has_value());
+
+ for (size_t i = 0; i < instruction.args().size(); ++i) {
+ Instruction::Op move_op;
+ if (opcode == ::art::Instruction::INVOKE_VIRTUAL ||
+ opcode == ::art::Instruction::INVOKE_DIRECT) {
+ // In this case, there is an implicit `this` argument, which is always an object.
+ if (i == 0) {
+ move_op = Instruction::Op::kMoveObject;
+ } else {
+ move_op = prototype->ArgType(i - 1).is_object() ? Instruction::Op::kMoveObject
+ : Instruction::Op::kMove;
+ }
+ } else {
+ move_op = prototype->ArgType(i).is_object() ? Instruction::Op::kMoveObject
+ : Instruction::Op::kMove;
+ }
+
+ EncodeMove(Instruction::OpWithArgs(move_op, scratch[i], instruction.args()[i]));
+ }
+
+ Encode3rc(InvokeToInvokeRange(opcode),
+ instruction.args().size(),
+ instruction.method_id(),
+ RegisterValue(scratch[0]));
+ } else {
+ Encode35c(opcode,
+ instruction.args().size(),
+ instruction.method_id(),
+ arguments[0],
+ arguments[1],
+ arguments[2],
+ arguments[3],
+ arguments[4]);
+ }
// If there is a return value, add a move-result instruction
if (instruction.dest().has_value()) {
@@ -416,26 +491,26 @@
}
void MethodBuilder::EncodeNew(const Instruction& instruction) {
- DCHECK_EQ(Instruction::Op::kNew, instruction.opcode());
- DCHECK(instruction.dest().has_value());
- DCHECK(instruction.dest()->is_variable());
- DCHECK_EQ(1, instruction.args().size());
+ CHECK_EQ(Instruction::Op::kNew, instruction.opcode());
+ CHECK(instruction.dest().has_value());
+ CHECK(instruction.dest()->is_variable());
+ CHECK_EQ(1, instruction.args().size());
const Value& type = instruction.args()[0];
- DCHECK_LT(RegisterValue(*instruction.dest()), 256);
- DCHECK(type.is_type());
+ CHECK_LT(RegisterValue(*instruction.dest()), 256);
+ CHECK(type.is_type());
Encode21c(::art::Instruction::NEW_INSTANCE, RegisterValue(*instruction.dest()), type.value());
}
void MethodBuilder::EncodeCast(const Instruction& instruction) {
- DCHECK_EQ(Instruction::Op::kCheckCast, instruction.opcode());
- DCHECK(instruction.dest().has_value());
- DCHECK(instruction.dest()->is_variable());
- DCHECK_EQ(1, instruction.args().size());
+ CHECK_EQ(Instruction::Op::kCheckCast, instruction.opcode());
+ CHECK(instruction.dest().has_value());
+ CHECK(instruction.dest()->is_variable());
+ CHECK_EQ(1, instruction.args().size());
const Value& type = instruction.args()[0];
- DCHECK_LT(RegisterValue(*instruction.dest()), 256);
- DCHECK(type.is_type());
+ CHECK_LT(RegisterValue(*instruction.dest()), 256);
+ CHECK(type.is_type());
Encode21c(::art::Instruction::CHECK_CAST, RegisterValue(*instruction.dest()), type.value());
}
@@ -443,9 +518,9 @@
if (value.is_register()) {
return value.value();
} else if (value.is_parameter()) {
- return value.value() + num_registers_;
+ return value.value() + num_registers_ + kMaxScratchRegisters;
}
- DCHECK(false && "Must be either a parameter or a register");
+ CHECK(false && "Must be either a parameter or a register");
return 0;
}
@@ -498,7 +573,7 @@
// update the index -> ir node map (see tools/dexter/slicer/dex_ir_builder.cc)
auto new_index = dex_file_->methods_indexes.AllocateIndex();
auto& ir_node = dex_file_->methods_map[new_index];
- SLICER_CHECK(ir_node == nullptr);
+ CHECK(ir_node == nullptr);
ir_node = decl;
decl->orig_index = decl->index = new_index;
@@ -508,6 +583,15 @@
return entry;
}
+std::optional<const Prototype> DexBuilder::GetPrototypeByMethodId(size_t method_id) const {
+ for (const auto& entry : method_id_map_) {
+ if (entry.second.id == method_id) {
+ return entry.first.prototype;
+ }
+ }
+ return {};
+}
+
ir::Proto* DexBuilder::GetOrEncodeProto(Prototype prototype) {
ir::Proto*& ir_proto = proto_map_[prototype];
if (ir_proto == nullptr) {
diff --git a/startop/view_compiler/dex_builder.h b/startop/view_compiler/dex_builder.h
index 757d863..541d800 100644
--- a/startop/view_compiler/dex_builder.h
+++ b/startop/view_compiler/dex_builder.h
@@ -16,6 +16,7 @@
#ifndef DEX_BUILDER_H_
#define DEX_BUILDER_H_
+#include <array>
#include <forward_list>
#include <map>
#include <optional>
@@ -70,6 +71,8 @@
// Return the shorty descriptor, such as I or L
std::string short_descriptor() const { return descriptor().substr(0, 1); }
+ bool is_object() const { return short_descriptor() == "L"; }
+
bool operator<(const TypeDescriptor& rhs) const { return descriptor_ < rhs.descriptor_; }
private:
@@ -92,6 +95,8 @@
// Get the shorty descriptor, such as VII for (Int, Int) -> Void
std::string Shorty() const;
+ const TypeDescriptor& ArgType(size_t index) const;
+
bool operator<(const Prototype& rhs) const {
return std::make_tuple(return_type_, param_types_) <
std::make_tuple(rhs.return_type_, rhs.param_types_);
@@ -124,11 +129,13 @@
size_t value() const { return value_; }
- private:
- enum class Kind { kLocalRegister, kParameter, kImmediate, kString, kLabel, kType };
+ constexpr Value() : value_{0}, kind_{Kind::kInvalid} {}
- const size_t value_;
- const Kind kind_;
+ private:
+ enum class Kind { kInvalid, kLocalRegister, kParameter, kImmediate, kString, kLabel, kType };
+
+ size_t value_;
+ Kind kind_;
constexpr Value(size_t value, Kind kind) : value_{value}, kind_{kind} {}
};
@@ -151,6 +158,7 @@
kInvokeStatic,
kInvokeVirtual,
kMove,
+ kMoveObject,
kNew,
kReturn,
kReturnObject,
@@ -172,7 +180,7 @@
// A cast instruction. Basically, `(type)val`
static inline Instruction Cast(Value val, Value type) {
- DCHECK(type.is_type());
+ CHECK(type.is_type());
return OpWithArgs(Op::kCheckCast, val, type);
}
@@ -343,21 +351,48 @@
buffer_.push_back(b);
}
+ inline void Encode32x(art::Instruction::Code opcode, uint16_t a, uint16_t b) {
+ buffer_.push_back(opcode);
+ buffer_.push_back(a);
+ buffer_.push_back(b);
+ }
+
inline void Encode35c(art::Instruction::Code opcode, size_t a, uint16_t b, uint8_t c, uint8_t d,
uint8_t e, uint8_t f, uint8_t g) {
// a|g|op|bbbb|f|e|d|c
CHECK_LE(a, 5);
- CHECK_LT(c, 16);
- CHECK_LT(d, 16);
- CHECK_LT(e, 16);
- CHECK_LT(f, 16);
- CHECK_LT(g, 16);
+ CHECK(IsShortRegister(c));
+ CHECK(IsShortRegister(d));
+ CHECK(IsShortRegister(e));
+ CHECK(IsShortRegister(f));
+ CHECK(IsShortRegister(g));
buffer_.push_back((a << 12) | (g << 8) | opcode);
buffer_.push_back(b);
buffer_.push_back((f << 12) | (e << 8) | (d << 4) | c);
}
+ inline void Encode3rc(art::Instruction::Code opcode, size_t a, uint16_t b, uint16_t c) {
+ CHECK_LE(a, 255);
+ buffer_.push_back((a << 8) | opcode);
+ buffer_.push_back(b);
+ buffer_.push_back(c);
+ }
+
+ static constexpr bool IsShortRegister(size_t register_value) { return register_value < 16; }
+
+ // Returns an array of num_regs scratch registers. These are guaranteed to be
+ // contiguous, so they are suitable for the invoke-*/range instructions.
+ template <int num_regs>
+ std::array<Value, num_regs> GetScratchRegisters() const {
+ static_assert(num_regs <= kMaxScratchRegisters);
+ std::array<Value, num_regs> regs;
+ for (size_t i = 0; i < num_regs; ++i) {
+ regs[i] = std::move(Value::Local(num_registers_ + i));
+ }
+ return regs;
+ }
+
// Converts a register or parameter to its DEX register number.
size_t RegisterValue(const Value& value) const;
@@ -379,6 +414,10 @@
// A buffer to hold instructions that have been encoded.
std::vector<::dex::u2> buffer_;
+ // We create some scratch registers for when we have to shuffle registers
+ // around to make legal DEX code.
+ static constexpr size_t kMaxScratchRegisters = 5;
+
// How many registers we've allocated
size_t num_registers_{0};
@@ -447,6 +486,8 @@
const MethodDeclData& GetOrDeclareMethod(TypeDescriptor type, const std::string& name,
Prototype prototype);
+ std::optional<const Prototype> GetPrototypeByMethodId(size_t method_id) const;
+
private:
// Looks up the ir::Proto* corresponding to this given prototype, or creates one if it does not
// exist.
diff --git a/startop/view_compiler/dex_builder_test.cc b/startop/view_compiler/dex_builder_test.cc
index 61c86b4..90c256f 100644
--- a/startop/view_compiler/dex_builder_test.cc
+++ b/startop/view_compiler/dex_builder_test.cc
@@ -140,3 +140,41 @@
EXPECT_TRUE(EncodeAndVerify(&dex_file));
}
+
+// Write out and verify a DEX file that corresponds to:
+//
+// package dextest;
+// public class DexTest {
+// public static int foo(String s) { return s.length(); }
+// }
+TEST(DexBuilderTest, VerifyDexCallManyRegisters) {
+ DexBuilder dex_file;
+
+ auto cbuilder{dex_file.MakeClass("dextest.DexTest")};
+
+ MethodBuilder method{cbuilder.CreateMethod(
+ "foo", Prototype{TypeDescriptor::Int()})};
+
+ Value result = method.MakeRegister();
+
+ // Make a bunch of registers
+ for (size_t i = 0; i < 25; ++i) {
+ method.MakeRegister();
+ }
+
+ // Now load a string literal into a register
+ Value string_val = method.MakeRegister();
+ method.BuildConstString(string_val, "foo");
+
+ MethodDeclData string_length =
+ dex_file.GetOrDeclareMethod(TypeDescriptor::FromClassname("java.lang.String"),
+ "length",
+ Prototype{TypeDescriptor::Int()});
+
+ method.AddInstruction(Instruction::InvokeVirtual(string_length.id, result, string_val));
+ method.BuildReturn(result);
+
+ method.Encode();
+
+ EXPECT_TRUE(EncodeAndVerify(&dex_file));
+}
diff --git a/startop/view_compiler/dex_builder_test/Android.bp b/startop/view_compiler/dex_builder_test/Android.bp
index d4f38ed..ac60e96 100644
--- a/startop/view_compiler/dex_builder_test/Android.bp
+++ b/startop/view_compiler/dex_builder_test/Android.bp
@@ -15,7 +15,7 @@
//
genrule {
- name: "generate_compiled_layout",
+ name: "generate_compiled_layout1",
tools: [":viewcompiler"],
cmd: "$(location :viewcompiler) $(in) --dex --out $(out) --package android.startop.test",
srcs: ["res/layout/layout1.xml"],
@@ -24,6 +24,16 @@
],
}
+genrule {
+ name: "generate_compiled_layout2",
+ tools: [":viewcompiler"],
+ cmd: "$(location :viewcompiler) $(in) --dex --out $(out) --package android.startop.test",
+ srcs: ["res/layout/layout2.xml"],
+ out: [
+ "layout2.dex",
+ ],
+}
+
android_test {
name: "dex-builder-test",
srcs: [
@@ -31,7 +41,7 @@
"src/android/startop/test/LayoutCompilerTest.java",
],
sdk_version: "current",
- data: [":generate_dex_testcases", ":generate_compiled_layout"],
+ data: [":generate_dex_testcases", ":generate_compiled_layout1", ":generate_compiled_layout2"],
static_libs: [
"android-support-test",
"guava",
diff --git a/startop/view_compiler/dex_builder_test/AndroidTest.xml b/startop/view_compiler/dex_builder_test/AndroidTest.xml
index 68d8fdc..92e2a71 100644
--- a/startop/view_compiler/dex_builder_test/AndroidTest.xml
+++ b/startop/view_compiler/dex_builder_test/AndroidTest.xml
@@ -26,6 +26,7 @@
<option name="push" value="trivial.dex->/data/local/tmp/dex-builder-test/trivial.dex" />
<option name="push" value="simple.dex->/data/local/tmp/dex-builder-test/simple.dex" />
<option name="push" value="layout1.dex->/data/local/tmp/dex-builder-test/layout1.dex" />
+ <option name="push" value="layout2.dex->/data/local/tmp/dex-builder-test/layout2.dex" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
diff --git a/startop/view_compiler/dex_builder_test/res/layout/layout2.xml b/startop/view_compiler/dex_builder_test/res/layout/layout2.xml
new file mode 100644
index 0000000..b092e1c
--- /dev/null
+++ b/startop/view_compiler/dex_builder_test/res/layout/layout2.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TableRow
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Button" />
+
+ <TableRow
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Button" />
+ <TableRow
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Button" />
+
+ <TableRow
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Button" />
+ </TableRow>
+
+ </TableRow>
+ </TableRow>
+ </TableRow>
+</LinearLayout>
diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java
index ce3ce83..a3b1b6c 100644
--- a/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java
+++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/LayoutCompilerTest.java
@@ -36,11 +36,20 @@
}
@Test
- public void loadAndInflaterLayout1() throws Exception {
+ public void loadAndInflateLayout1() throws Exception {
ClassLoader dex_file = loadDexFile("layout1.dex");
Class compiled_view = dex_file.loadClass("android.startop.test.CompiledView");
Method layout1 = compiled_view.getMethod("layout1", Context.class, int.class);
Context context = InstrumentationRegistry.getTargetContext();
layout1.invoke(null, context, R.layout.layout1);
}
+
+ @Test
+ public void loadAndInflateLayout2() throws Exception {
+ ClassLoader dex_file = loadDexFile("layout2.dex");
+ Class compiled_view = dex_file.loadClass("android.startop.test.CompiledView");
+ Method layout1 = compiled_view.getMethod("layout2", Context.class, int.class);
+ Context context = InstrumentationRegistry.getTargetContext();
+ layout1.invoke(null, context, R.layout.layout1);
+ }
}
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 12a5344..0e17a33 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1404,8 +1404,14 @@
*
* @return {@code true} if there is a call which will be rejected or terminated, {@code false}
* otherwise.
+ * @deprecated Companion apps for wearable devices should use the {@link InCallService} API
+ * instead. Apps performing call screening should use the {@link CallScreeningService} API
+ * instead.
*/
+
+
@RequiresPermission(Manifest.permission.ANSWER_PHONE_CALLS)
+ @Deprecated
public boolean endCall() {
try {
if (isServiceConnected()) {
@@ -1426,11 +1432,15 @@
*
* Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or
* {@link android.Manifest.permission#ANSWER_PHONE_CALLS}
+ *
+ * @deprecated Companion apps for wearable devices should use the {@link InCallService} API
+ * instead.
*/
//TODO: L-release - need to convert all invocation of ITelecmmService#answerRingingCall to use
// this method (clockwork & gearhead).
@RequiresPermission(anyOf =
{Manifest.permission.ANSWER_PHONE_CALLS, Manifest.permission.MODIFY_PHONE_STATE})
+ @Deprecated
public void acceptRingingCall() {
try {
if (isServiceConnected()) {
@@ -1449,9 +1459,12 @@
* {@link android.Manifest.permission#ANSWER_PHONE_CALLS}
*
* @param videoState The desired video state to answer the call with.
+ * @deprecated Companion apps for wearable devices should use the {@link InCallService} API
+ * instead.
*/
@RequiresPermission(anyOf =
{Manifest.permission.ANSWER_PHONE_CALLS, Manifest.permission.MODIFY_PHONE_STATE})
+ @Deprecated
public void acceptRingingCall(int videoState) {
try {
if (isServiceConnected()) {