diff options
103 files changed, 1065 insertions, 5737 deletions
diff --git a/Android.bp b/Android.bp index d75a311a36ef..fb14f86bdae4 100644 --- a/Android.bp +++ b/Android.bp @@ -271,7 +271,6 @@ filegroup { // etc. ":framework-javastream-protos", - ":framework-statslog-gen", // StatsLogInternal.java ":statslog-framework-java-gen", // FrameworkStatsLog.java // telephony annotations @@ -282,7 +281,6 @@ filegroup { filegroup { name: "framework-updatable-sources", srcs: [ - ":framework-appsearch-sources", ":framework-sdkextensions-sources", ":framework-statsd-sources", ":framework-tethering-srcs", @@ -468,7 +466,6 @@ java_library { defaults: ["framework-defaults"], srcs: [":framework-non-updatable-sources"], libs: [ - "framework-appsearch-stubs", "framework-sdkextensions-stubs-systemapi", "framework-statsd-stubs-module_libs_api", "framework-permission-stubs-systemapi", @@ -494,7 +491,6 @@ java_library { visibility: [ "//frameworks/base", // TODO(b/147128803) remove the below lines - "//frameworks/base/apex/appsearch/framework", "//frameworks/base/apex/blobstore/framework", "//frameworks/base/apex/jobscheduler/framework", "//frameworks/base/packages/Tethering/tests/unit", @@ -516,7 +512,6 @@ java_library { installable: false, // this lib is a build-only library static_libs: [ "framework-minus-apex", - "framework-appsearch", // TODO(b/146218515): should be framework-appsearch-stubs "framework-media-stubs-systemapi", "framework-mediaprovider-stubs-systemapi", "framework-permission-stubs-systemapi", @@ -541,7 +536,6 @@ java_library { "exoplayer2-extractor", "android.hardware.wifi-V1.0-java-constants", ], - libs: ["icing-java-proto-lite"], apex_available: ["//apex_available:platform"], visibility: [ // DO NOT ADD ANY MORE ENTRIES TO THIS LIST @@ -562,7 +556,6 @@ java_library { libs: [ "app-compat-annotations", "ext", - "icing-java-proto-lite", "unsupportedappusage", ], @@ -617,13 +610,6 @@ java_library { } genrule { - name: "framework-statslog-gen", - tools: ["stats-log-api-gen"], - cmd: "$(location stats-log-api-gen) --java $(out) --worksource", - out: ["android/util/StatsLogInternal.java"], -} - -genrule { name: "statslog-framework-java-gen", tools: ["stats-log-api-gen"], cmd: "$(location stats-log-api-gen) --java $(out) --module framework" + diff --git a/apex/appsearch/Android.bp b/apex/appsearch/Android.bp deleted file mode 100644 index b014fdcb3df3..000000000000 --- a/apex/appsearch/Android.bp +++ /dev/null @@ -1,37 +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. - -apex { - name: "com.android.appsearch", - manifest: "apex_manifest.json", - java_libs: [ - "framework-appsearch", - "service-appsearch", - ], - key: "com.android.appsearch.key", - certificate: ":com.android.appsearch.certificate", -} - -apex_key { - name: "com.android.appsearch.key", - public_key: "com.android.appsearch.avbpubkey", - private_key: "com.android.appsearch.pem", -} - -android_app_certificate { - name: "com.android.appsearch.certificate", - // This will use com.android.appsearch.x509.pem (the cert) and - // com.android.appsearch.pk8 (the private key) - certificate: "com.android.appsearch", -} diff --git a/apex/appsearch/apex_manifest.json b/apex/appsearch/apex_manifest.json deleted file mode 100644 index 39a2d38fa642..000000000000 --- a/apex/appsearch/apex_manifest.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "com.android.appsearch", - "version": 300000000 -} diff --git a/apex/appsearch/com.android.appsearch.avbpubkey b/apex/appsearch/com.android.appsearch.avbpubkey Binary files differdeleted file mode 100644 index 4e5acae9c1e4..000000000000 --- a/apex/appsearch/com.android.appsearch.avbpubkey +++ /dev/null diff --git a/apex/appsearch/com.android.appsearch.pem b/apex/appsearch/com.android.appsearch.pem deleted file mode 100644 index 4ed5945acc86..000000000000 --- a/apex/appsearch/com.android.appsearch.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIJKQIBAAKCAgEAro9f/jvoIsj6ywuRmuUQS8UtprhohJitrovDMfm/T2R/WQvy -AvUxgetyF4XvBPCDRqCsGxXCJMQOn1furrAeTmWbGHPhA0PI1Ys/qtfNMbh9THyn -70I2c4X70CUQ+8/Y8BJ8CAB4iER/s9QtD28QLvM2BBUzRoKUSBGUYNMlYobjgRdK -57V7yg48LkvUIg1fzIW3M5gCgOXa0u1xOadKX3m7tzCboHcXp5anfWX5PH1+okRu -jzdI8OjtUq23qhoRw5Skz0Vbf4a+8t3kT3slF/Q7O8LoRPwpZsvIcvTyCGAqlra7 -2L2LN4H1p+u2ko3r/QmRbJn2eXW07elkyrggXMyn2rTxibQgk53wYfSavMyNd/E7 -+de/uJ60l2aPa+5KUaR8eYwchXEELdqQ+zRgSZ2711xCaY4glEj7DT6VlEEdr26x -akX0ra7e2sVGv1um/dvSyVO5aFKKjVvo4LqhWKWO8yvDMxmDDTNatvWhY2Bhd3RA -0hilYpWQFb9Tv5f4E0tZmfvlddgux7sw++Y/RIimBFoSyf5AezAUIFYYoYvEzytB -muq1/ecNHr+Z2tZMxN88sJVhzRzD9tKUyXhvxOV2Lg9TIeVTWGwQqgSnHWtIe+1p -cw8inPfYEhP4Q+3W/RlPvNdu75x8Nj2aG7bxZnhoQDRDw5ddgma27I+a8esCAwEA -AQKCAgBsNh9I6HRAVBz8kCBkSEnw3rwtFTZdtJQ+lw+bRHpvShqT5g7R/JQDOSTS -JkoE4uBOgT4P0E45Inz6FLW2/yDacqxR3UwJDRVMI/WFACCJCRhLuR8V+BLvTIjN -AJ1lrPSL5rmS8E/IEcakgQyp+6ypnkXHBCl0NXCcuKEl4N7VFE+mb/0UZPHnUSnH -fWR085uGmwH17u7mXxdnGKDPH8DALSPMLUrcj9dPIdqUpwl5kUZWa1uqVphWF98/ -GMe5oE2Q0+3TO+i7xplKz3lAOFPHZLTvmCUK1tMHkZ6ifOwpewwLwB30/5N1BpB1 -126nrWk0xKCtFUixBOHzdnLwJHKSbi7chQU5q39oAJoTfxdmAJlaG0zQHUQZ44MQ -gemzSA7uJbtoAOAZVF1K14xbIpnfidqTB7N3RCmiJE+/Hpkq6PxgPfu5rqocPbPC -t0FgJ4NXNmKOAuJllSlrrHATcUOhF4g5pX7tvOc8X4y7bvfwOmtw5ez3INKMF0q6 -/y0vVCi6N1Z7CTa9eY8feZ1PImk/Fkq4NInSPyx7ZE3pLYmsvuJjliFrWo9TRVae -Dt5vvBKBOpAfhDiHkeXbX7Raj2B6c6adF4no/3SAVlAjIq1iBVjfQWyHAGUoEW1O -u3LdHTIb6gSTLJ4AfryEKrOE+1VMlYt92GwX692KKXMaJjytSQKCAQEA3pYbl8HD -Y++UyEN5VzWAQedT3//GDwpDfgdERe2E4smYrkVNJ2WAG2SqY1A35DIl8be3eHvl -soaL38j48ailfDYY9tI+IlapNh+VOLej+HiOytaPlLhcv2FpSC2qZT4EiU6IBXLo -+l6FrmD/VQXTjvoktzsDB/n1t4Dfa3Ogf+lLf1Jxr94YpEnDh18V5ofj78SplVLm -NrzsHxAafE4Ni2a7dyWjcDYIuL7FTShT+0K4W45tRr+CGxThxu7LEe7zw4Z1IagU -jJNtXjvDD/Zw4UTqI6RwWGZsu6UjPS6LHhOqnWqflWmFRIfMbDkuWvnGZTM9DkVg -kk1+BNi1PECZXwKCAQEAyMOjbVo6XV3lFN0X8TpHyg/z9ar00/SE7WEJHqPSuzYT -rSfU4vDDlaPAwkYvGi9ZKi9VM+R3CyBNxnK9Yq6NurHhhrYcAwdS/hGLT1K2o0Y8 -Pgv7gZCFb+SIwLBhlUG9otGULcBzLneqgVUqyMG6IoCjuC2LRyB71Xc2UMyg6n/f -XpV2RTMb8f+26cgm6nj0SDAfgpr8HV6uNV80c6l1A8gq86nUWwiVAEUdmExSDe7J -shsfWAj8RSErqDXf1BtEdPLJUSIPX5VXkzAXOXIkengwVno0vv0dBN8uraS8iQSG -0JsJLLcw9b5kvnh6FEbE7POsIqKyCZV9VADwO6YW9QKCAQBYQsdwNqoGv6KMgozj -8tgHyfWtVduwbQ50M+dznwpZbzz2pY5Bd/MDabhSpyVyfBwlrAa5ZM+hKc7fDu7/ -zDLKfR0LCjUPIrP4PS/LjK4dQZjFf6zxeOV2EedQcqMlgCEGXTh8iKMvXDm/+sBk -c2n/QNs8OM8r44b2m8h78B6NefGw6/0ekn/M7V72F9M0VWAh3Cauim+09tbePmFy -NvUR+MuPJEKZpSNyNltADCS49izqSSC1tAygNniMjHXDh6/rMS7TCLYVRARTIHlp -o/wAp3X8aiEOPJcTFRlTElihtYSq5POgqHXqxbpek5H5CyALUvT76rCvcsDspQ3A -dZEbAoIBAQCoLEmP5o8Rev/UdEgECB/uwWJIngYsLp3TAv/SrMRvkiL1X3JTD/+m -L9/eXVBDjPoR/khPCcg2h77ex2qhaTrL8wnKAG6CkvYQYb3impTnPIRmLT9nDxrX -2gY78wQrNUCXTRvlH1rcx90KLb+DH9S95ig+tdf/otRYwl27XU5GYQtJfcXuvZth -IiWku8btjpiCh909WHpsV81yY+faI08j9d8U8WQzRYMbEMpzsyrhBO/rxBCDfDNl -7R1W8JooYRb9KAs/bVqXZNBROW2a72RjOp6zMfdRLVHLrPC7AE32MNaFk/khfesD -T5OwgdcxeP6oxo2hDcw5fwHXBlo2fTCpAoIBAQChgjv5AfQ50spqvHy6MNem4tV0 -L0IsxmNLsi8X2a6s4kStwUzOxDA8c/e54XabxQNZ0ERU1q+bgbG7PWC4twDMPR8i -2DO6rgqSK4MjGOTgAoeDuy3mElFQmCLRs04Wf4jh8kPi217WFlYBynh2HmBKbh42 -JmIrLetbKEK13FXRvMkgZcX4OIDrT5TOvev4VZArU8PTRlWv3sqsKAVXjX0clGHf -I0/2kSsr2qq1UY7JrYWZsZ9uqz2ZH0pF19a6O/Cq4uqTYoL+sYzFTSeFmChRjV1g -ancTvTn9lcBqECDMgq5DE/p96Oxg/t8elalR6WDUlysafphVz3nTuyMTh7ka ------END RSA PRIVATE KEY----- diff --git a/apex/appsearch/com.android.appsearch.pk8 b/apex/appsearch/com.android.appsearch.pk8 Binary files differdeleted file mode 100644 index 77e98b20877b..000000000000 --- a/apex/appsearch/com.android.appsearch.pk8 +++ /dev/null diff --git a/apex/appsearch/com.android.appsearch.x509.pem b/apex/appsearch/com.android.appsearch.x509.pem deleted file mode 100644 index e37c4b9fcead..000000000000 --- a/apex/appsearch/com.android.appsearch.x509.pem +++ /dev/null @@ -1,35 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIGETCCA/mgAwIBAgIUGl+MIvpEi0+TWzj0ieh6WtjXmP8wDQYJKoZIhvcNAQEL -BQAwgZYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH -DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy -b2lkMRIwEAYDVQQDDAlhcHBzZWFyY2gxIjAgBgkqhkiG9w0BCQEWE2FuZHJvaWRA -YW5kcm9pZC5jb20wIBcNMTkxMTIwMjMxNTM1WhgPNDc1NzEwMTYyMzE1MzVaMIGW -MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91 -bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDES -MBAGA1UEAwwJYXBwc2VhcmNoMSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJv -aWQuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsyPlp3q3P9Xg -W1WhIwQiF9em9oqaGQ/3dbIxickAy591qcRbpHb4lDTZusRECfqlV215mV+lv5x4 -EhOnId3uPKBAJ/YDtL7zUW6TWL7to7zEnUqSIKTcoQzNF2EiCeGuRhrtgYvAD3HQ -dwr4xrbSADbDArF04A49voLpsmq1fyNgl86VISiMRqoSLJnA6eghlduuOt+nf252 -6WgxDs/JrO/eK70q0+RwmWzVJ/tVr+36a65N4EHhfL4t2hdV0k0XFob7hBn7XWzC -QrSR3jCvE3yAfAr3tq5c19/WWBA7V45nEHzXyAvBUHWubYvDi+vm/yzqU2rQwScC -bzp4zK4CnhBHqb4gHoy0+kfFIwJ1A3GT2pl3ba/NsIYgliMtPQfkDV5PE5RTNcwH -21ewH7vm2+spQv5Z/2TEV2lEHlp2vuAliyn2AT4u1ginr6vtBRFLmpPeziFcfB0y -7h04GctZpX8odz+XI7aMDe47RNu9XyJX0vulntxmlDF76k8Z9DIXg02hY+yc/i7+ -2ztnj1eXL51p+HyhK5VbvJWbKkVaMQijlbuIMYNzMA6L0WHWRc2Cux9UDODMGoiC -w09JpqudCS/95I/F1xaWJ/Kh3vKeQshHAz0hrL7v7wpjmfeXf6NGsWJGy+giCwZj -ABtn9nFQoesgi7M1LeazD5Q/4v4AMaUCAwEAAaNTMFEwHQYDVR0OBBYEFJpHCy2Y -3qaL6cLpE9fe53L61KEEMB8GA1UdIwQYMBaAFJpHCy2Y3qaL6cLpE9fe53L61KEE -MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAGDYAcOhbOYcDB2K -WDZka+FCORFFvz4nLQGE7Z9TAn1g7XusM2KbXlb2drIN6CWOFlnKQrUsNsAHrc+s -tl+A1vC3/NfYKKBVuizPx/kHUgz3k/UIJzbzEu/uCJd86idcJoUTqC/qEJAeeQqM -XpsNP1Yg7oyzZT8sFlUAKeDeXJ7fIDXR6nduUQ6uJXkee/5JF3VedHdgHAUsC19/ -KHhyVU3MLDUNBdAmM79+DsdVYi2Pw31jojMu95Zz1MYTRBcgQAiEw5nncr38k6ac -Gy+JffgJR68FzI4QLBSxnDRFD2zXJ09lpP6Sjb1FVcDzk7Bi/EQDLBkrkbeLsk5F -a0xz9VoJ3kM7Cc4R9MXN4ZWuePjdJwgasnHmllsXn45R9odgJgmfzuUwtgNw/XKQ -QcQl7Q9QUrBCqIoHijxscUZCBSmIHVNBBDckRAmSXHeWMRlO3uBR4IA/Jfrt//4f -uc7CNUp+LQ6EzBXJOVFrXRtau6Oj+jM1+fzxKo1uV2+T+GdVEE5jeF/6nB3qna6h -2NmyLqbqeqp2QxgzBWSGy8Ugs6zg4wItJBqOoRLKKFxTJu5OAzJ4fUA+g7WFXNhR -kG56SJ863LZoORKHWE72oXYeIW98Tq0qKLH3NzH5L4tfX8DeBTq+APezHetH1ljA -D0avPy62g0i643bbpwZgezBgRIKL ------END CERTIFICATE----- diff --git a/apex/appsearch/framework/Android.bp b/apex/appsearch/framework/Android.bp deleted file mode 100644 index 24309d7c4e0d..000000000000 --- a/apex/appsearch/framework/Android.bp +++ /dev/null @@ -1,83 +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. - -filegroup { - name: "framework-appsearch-sources", - srcs: [ - "java/**/*.java", - "java/**/*.aidl", - ], - path: "java", -} - -java_library { - name: "framework-appsearch", - installable: true, - sdk_version: "core_platform", // TODO(b/146218515) should be core_current - srcs: [":framework-appsearch-sources"], - hostdex: true, // for hiddenapi check - libs: [ - "framework-minus-apex", // TODO(b/146218515) should be framework-system-stubs - ], - static_libs: ["icing-java-proto-lite"], - visibility: [ - // TODO(b/146218515) remove this when framework is built with the stub of appsearch - "//frameworks/base", - "//frameworks/base/apex/appsearch:__subpackages__", - ], - permitted_packages: ["android.app.appsearch"], - apex_available: ["com.android.appsearch"], -} - -metalava_appsearch_docs_args = - "--hide-package com.android.server " + - "--error UnhiddenSystemApi " + - "--hide RequiresPermission " + - "--hide MissingPermission " + - "--hide BroadcastBehavior " + - "--hide HiddenSuperclass " + - "--hide DeprecationMismatch " + - "--hide UnavailableSymbol " + - "--hide SdkConstant " + - "--hide HiddenTypeParameter " + - "--hide Todo --hide Typo " + - "--hide HiddenTypedefConstant " + - "--show-annotation android.annotation.SystemApi " - -droidstubs { - name: "framework-appsearch-stubs-srcs", - srcs: [ - ":framework-annotations", - ":framework-appsearch-sources", - ], - aidl: { - include_dirs: ["frameworks/base/core/java"], - }, - args: metalava_appsearch_docs_args, - sdk_version: "core_current", - libs: ["android_system_stubs_current"], -} - -java_library { - name: "framework-appsearch-stubs", - srcs: [":framework-appsearch-stubs-srcs"], - aidl: { - export_include_dirs: [ - "java", - ], - }, - sdk_version: "core_current", - libs: ["android_system_stubs_current"], - installable: false, -} diff --git a/apex/appsearch/framework/java/android/app/TEST_MAPPING b/apex/appsearch/framework/java/android/app/TEST_MAPPING deleted file mode 100644 index 12188f83a29f..000000000000 --- a/apex/appsearch/framework/java/android/app/TEST_MAPPING +++ /dev/null @@ -1,7 +0,0 @@ -{ - "imports": [ - { - "path": "frameworks/base/apex/appsearch/service/java/com/android/server/appsearch" - } - ] -} diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java deleted file mode 100644 index 773db9346625..000000000000 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.appsearch; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.ArrayMap; - -import java.util.Collections; -import java.util.Map; - -/** - * Provides access to multiple results from a batch operation accepting multiple inputs. - * - * @param <KeyType> The type of the keys for {@link #getResults} and {@link #getFailures}. - * @param <ValueType> The type of result objects associated with the keys. - * @hide - */ -public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable { - @NonNull private final Map<KeyType, ValueType> mResults; - @NonNull private final Map<KeyType, Throwable> mFailures; - - private AppSearchBatchResult( - @NonNull Map<KeyType, ValueType> results, @NonNull Map<KeyType, Throwable> failures) { - mResults = results; - mFailures = failures; - } - - private AppSearchBatchResult(@NonNull Parcel in) { - mResults = Collections.unmodifiableMap(in.readHashMap(/*loader=*/ null)); - mFailures = Collections.unmodifiableMap(in.readHashMap(/*loader=*/ null)); - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeMap(mResults); - dest.writeMap(mFailures); - } - - /** Returns {@code true} if this {@link AppSearchBatchResult} has no failures. */ - public boolean isSuccess() { - return mFailures.isEmpty(); - } - - /** - * Returns a {@link Map} of all successful keys mapped to the results they produced. - * - * <p>The values of the {@link Map} may be {@code null}. - */ - @NonNull - public Map<KeyType, ValueType> getResults() { - return mResults; - } - - /** - * Returns a {@link Map} of all failed keys mapped to a {@link Throwable} representing the cause - * of failure. - * - * <p>The values of the {@link Map} may be {@code null}. - */ - @NonNull - public Map<KeyType, Throwable> getFailures() { - return mFailures; - } - - @Override - public int describeContents() { - return 0; - } - - public static final Creator<AppSearchBatchResult> CREATOR = - new Creator<AppSearchBatchResult>() { - @NonNull - @Override - public AppSearchBatchResult createFromParcel(@NonNull Parcel in) { - return new AppSearchBatchResult(in); - } - - @NonNull - @Override - public AppSearchBatchResult[] newArray(int size) { - return new AppSearchBatchResult[size]; - } - }; - - /** - * Creates a new {@link Builder} for this {@link AppSearchBatchResult}. - * @hide - */ - @NonNull - public static <KeyType, ValueType> Builder<KeyType, ValueType> newBuilder() { - return new Builder<>(); - } - - /** - * Builder for {@link AppSearchBatchResult} objects. - * - * @param <KeyType> The type of keys. - * @param <ValueType> The type of result objects associated with the keys. - * @hide - */ - public static final class Builder<KeyType, ValueType> { - @NonNull private final Map<KeyType, ValueType> mResults = new ArrayMap<>(); - @NonNull private final Map<KeyType, Throwable> mFailures = new ArrayMap<>(); - - private Builder() {} - - /** - * Registers that the {@code key} was processed successfully and associates it with - * {@code value}. Any previous mapping for a key, whether success or failure, is deleted. - */ - public Builder setSuccess(@NonNull KeyType key, @Nullable ValueType value) { - mResults.put(key, value); - mFailures.remove(key); - return this; - } - - /** - * Registers that the {@code key} failed and associates it with {@code throwable}. Any - * previous mapping for a key, whether success or failure, is deleted. - */ - public Builder setFailure(@NonNull KeyType key, @Nullable Throwable throwable) { - mFailures.put(key, throwable); - mResults.remove(key); - return this; - } - - /** Builds an {@link AppSearchBatchResult} from the contents of this {@link Builder}. */ - @NonNull - public AppSearchBatchResult<KeyType, ValueType> build() { - return new AppSearchBatchResult<>(mResults, mFailures); - } - } -} diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchDocument.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchDocument.java deleted file mode 100644 index ff0f0dda55b9..000000000000 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchDocument.java +++ /dev/null @@ -1,724 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.appsearch; - -import android.annotation.CurrentTimeMillisLong; -import android.annotation.DurationMillisLong; -import android.annotation.IntRange; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.util.ArrayMap; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.ArrayUtils; -import com.android.internal.util.Preconditions; - -import com.google.android.icing.proto.DocumentProto; -import com.google.android.icing.proto.PropertyProto; -import com.google.android.icing.protobuf.ByteString; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -/** - * Represents a document unit. - * - * <p>Documents are constructed via {@link AppSearchDocument.Builder}. - * @hide - */ -public class AppSearchDocument { - private static final String TAG = "AppSearchDocument"; - - /** - * The maximum number of elements in a repeatable field. Will reject the request if exceed - * this limit. - */ - private static final int MAX_REPEATED_PROPERTY_LENGTH = 100; - - /** - * The maximum {@link String#length} of a {@link String} field. Will reject the request if - * {@link String}s longer than this. - */ - private static final int MAX_STRING_LENGTH = 20_000; - - /** - * Contains {@link AppSearchDocument} basic information (uri, schemaType etc) and properties - * ordered by keys. - */ - @NonNull - private final DocumentProto mProto; - - /** Contains all properties in {@link #mProto} to support getting properties via keys. */ - @NonNull - private final Map<String, Object> mProperties; - - /** - * Create a new {@link AppSearchDocument}. - * @param proto Contains {@link AppSearchDocument} basic information (uri, schemaType etc) and - * properties ordered by keys. - * @param propertiesMap Contains all properties in {@link #mProto} to support get properties - * via keys. - */ - private AppSearchDocument(@NonNull DocumentProto proto, - @NonNull Map<String, Object> propertiesMap) { - mProto = proto; - mProperties = propertiesMap; - } - - /** - * Create a new {@link AppSearchDocument} from an existing instance. - * - * <p>This method should be only used by constructor of a subclass. - */ - protected AppSearchDocument(@NonNull AppSearchDocument document) { - this(document.mProto, document.mProperties); - } - - /** @hide */ - AppSearchDocument(@NonNull DocumentProto documentProto) { - this(documentProto, new ArrayMap<>()); - for (int i = 0; i < documentProto.getPropertiesCount(); i++) { - PropertyProto property = documentProto.getProperties(i); - String name = property.getName(); - if (property.getStringValuesCount() > 0) { - String[] values = new String[property.getStringValuesCount()]; - for (int j = 0; j < values.length; j++) { - values[j] = property.getStringValues(j); - } - mProperties.put(name, values); - } else if (property.getInt64ValuesCount() > 0) { - long[] values = new long[property.getInt64ValuesCount()]; - for (int j = 0; j < values.length; j++) { - values[j] = property.getInt64Values(j); - } - mProperties.put(property.getName(), values); - } else if (property.getDoubleValuesCount() > 0) { - double[] values = new double[property.getDoubleValuesCount()]; - for (int j = 0; j < values.length; j++) { - values[j] = property.getDoubleValues(j); - } - mProperties.put(property.getName(), values); - } else if (property.getBooleanValuesCount() > 0) { - boolean[] values = new boolean[property.getBooleanValuesCount()]; - for (int j = 0; j < values.length; j++) { - values[j] = property.getBooleanValues(j); - } - mProperties.put(property.getName(), values); - } else if (property.getBytesValuesCount() > 0) { - byte[][] values = new byte[property.getBytesValuesCount()][]; - for (int j = 0; j < values.length; j++) { - values[j] = property.getBytesValues(j).toByteArray(); - } - mProperties.put(name, values); - } else if (property.getDocumentValuesCount() > 0) { - AppSearchDocument[] values = - new AppSearchDocument[property.getDocumentValuesCount()]; - for (int j = 0; j < values.length; j++) { - values[j] = new AppSearchDocument(property.getDocumentValues(j)); - } - mProperties.put(name, values); - } else { - throw new IllegalStateException("Unknown type of value: " + name); - } - } - } - - /** - * Get the {@link DocumentProto} of the {@link AppSearchDocument}. - * - * <p>The {@link DocumentProto} contains {@link AppSearchDocument}'s basic information and all - * properties ordered by keys. - * @hide - */ - @NonNull - @VisibleForTesting - public DocumentProto getProto() { - return mProto; - } - - /** - * Get the uri of the {@link AppSearchDocument}. - * - * @hide - */ - @NonNull - public String getUri() { - return mProto.getUri(); - } - - /** - * Get the schema type of the {@link AppSearchDocument}. - * @hide - */ - @NonNull - public String getSchemaType() { - return mProto.getSchema(); - } - - /** - * Get the creation timestamp in milliseconds of the {@link AppSearchDocument}. Value will be in - * the {@link System#currentTimeMillis()} time base. - * - * @hide - */ - @CurrentTimeMillisLong - public long getCreationTimestampMillis() { - return mProto.getCreationTimestampMs(); - } - - /** - * Returns the TTL (Time To Live) of the {@link AppSearchDocument}, in milliseconds. - * - * <p>The default value is 0, which means the document is permanent and won't be auto-deleted - * until the app is uninstalled. - * - * @hide - */ - @DurationMillisLong - public long getTtlMillis() { - return mProto.getTtlMs(); - } - - /** - * Returns the score of the {@link AppSearchDocument}. - * - * <p>The score is a query-independent measure of the document's quality, relative to other - * {@link AppSearchDocument}s of the same type. - * - * <p>The default value is 0. - * - * @hide - */ - public int getScore() { - return mProto.getScore(); - } - - /** - * Retrieve a {@link String} value by key. - * - * @param key The key to look for. - * @return The first {@link String} associated with the given key or {@code null} if there - * is no such key or the value is of a different type. - * @hide - */ - @Nullable - public String getPropertyString(@NonNull String key) { - String[] propertyArray = getPropertyStringArray(key); - if (ArrayUtils.isEmpty(propertyArray)) { - return null; - } - warnIfSinglePropertyTooLong("String", key, propertyArray.length); - return propertyArray[0]; - } - - /** - * Retrieve a {@link Long} value by key. - * - * @param key The key to look for. - * @return The first {@link Long} associated with the given key or {@code null} if there - * is no such key or the value is of a different type. - * @hide - */ - @Nullable - public Long getPropertyLong(@NonNull String key) { - long[] propertyArray = getPropertyLongArray(key); - if (ArrayUtils.isEmpty(propertyArray)) { - return null; - } - warnIfSinglePropertyTooLong("Long", key, propertyArray.length); - return propertyArray[0]; - } - - /** - * Retrieve a {@link Double} value by key. - * - * @param key The key to look for. - * @return The first {@link Double} associated with the given key or {@code null} if there - * is no such key or the value is of a different type. - * @hide - */ - @Nullable - public Double getPropertyDouble(@NonNull String key) { - double[] propertyArray = getPropertyDoubleArray(key); - // TODO(tytytyww): Add support double array to ArraysUtils.isEmpty(). - if (propertyArray == null || propertyArray.length == 0) { - return null; - } - warnIfSinglePropertyTooLong("Double", key, propertyArray.length); - return propertyArray[0]; - } - - /** - * Retrieve a {@link Boolean} value by key. - * - * @param key The key to look for. - * @return The first {@link Boolean} associated with the given key or {@code null} if there - * is no such key or the value is of a different type. - * @hide - */ - @Nullable - public Boolean getPropertyBoolean(@NonNull String key) { - boolean[] propertyArray = getPropertyBooleanArray(key); - if (ArrayUtils.isEmpty(propertyArray)) { - return null; - } - warnIfSinglePropertyTooLong("Boolean", key, propertyArray.length); - return propertyArray[0]; - } - - /** - * Retrieve a {@code byte[]} value by key. - * - * @param key The key to look for. - * @return The first {@code byte[]} associated with the given key or {@code null} if there - * is no such key or the value is of a different type. - */ - @Nullable - public byte[] getPropertyBytes(@NonNull String key) { - byte[][] propertyArray = getPropertyBytesArray(key); - if (ArrayUtils.isEmpty(propertyArray)) { - return null; - } - warnIfSinglePropertyTooLong("ByteArray", key, propertyArray.length); - return propertyArray[0]; - } - - /** - * Retrieve a {@link AppSearchDocument} value by key. - * - * @param key The key to look for. - * @return The first {@link AppSearchDocument} associated with the given key or {@code null} if - * there is no such key or the value is of a different type. - */ - @Nullable - public AppSearchDocument getPropertyDocument(@NonNull String key) { - AppSearchDocument[] propertyArray = getPropertyDocumentArray(key); - if (ArrayUtils.isEmpty(propertyArray)) { - return null; - } - warnIfSinglePropertyTooLong("Document", key, propertyArray.length); - return propertyArray[0]; - } - - /** Prints a warning to logcat if the given propertyLength is greater than 1. */ - private static void warnIfSinglePropertyTooLong( - @NonNull String propertyType, @NonNull String key, int propertyLength) { - if (propertyLength > 1) { - Log.w(TAG, "The value for \"" + key + "\" contains " + propertyLength - + " elements. Only the first one will be returned from " - + "getProperty" + propertyType + "(). Try getProperty" + propertyType - + "Array()."); - } - } - - /** - * Retrieve a repeated {@code String} property by key. - * - * @param key The key to look for. - * @return The {@code String[]} associated with the given key, or {@code null} if no value - * is set or the value is of a different type. - * @hide - */ - @Nullable - public String[] getPropertyStringArray(@NonNull String key) { - return getAndCastPropertyArray(key, String[].class); - } - - /** - * Retrieve a repeated {@code long} property by key. - * - * @param key The key to look for. - * @return The {@code long[]} associated with the given key, or {@code null} if no value is - * set or the value is of a different type. - * @hide - */ - @Nullable - public long[] getPropertyLongArray(@NonNull String key) { - return getAndCastPropertyArray(key, long[].class); - } - - /** - * Retrieve a repeated {@code double} property by key. - * - * @param key The key to look for. - * @return The {@code double[]} associated with the given key, or {@code null} if no value - * is set or the value is of a different type. - * @hide - */ - @Nullable - public double[] getPropertyDoubleArray(@NonNull String key) { - return getAndCastPropertyArray(key, double[].class); - } - - /** - * Retrieve a repeated {@code boolean} property by key. - * - * @param key The key to look for. - * @return The {@code boolean[]} associated with the given key, or {@code null} if no value - * is set or the value is of a different type. - * @hide - */ - @Nullable - public boolean[] getPropertyBooleanArray(@NonNull String key) { - return getAndCastPropertyArray(key, boolean[].class); - } - - /** - * Retrieve a {@code byte[][]} property by key. - * - * @param key The key to look for. - * @return The {@code byte[][]} associated with the given key, or {@code null} if no value - * is set or the value is of a different type. - */ - @Nullable - public byte[][] getPropertyBytesArray(@NonNull String key) { - return getAndCastPropertyArray(key, byte[][].class); - } - - /** - * Retrieve a repeated {@link AppSearchDocument} property by key. - * - * @param key The key to look for. - * @return The {@link AppSearchDocument[]} associated with the given key, or {@code null} if no - * value is set or the value is of a different type. - */ - @Nullable - public AppSearchDocument[] getPropertyDocumentArray(@NonNull String key) { - return getAndCastPropertyArray(key, AppSearchDocument[].class); - } - - /** - * Gets a repeated property of the given key, and casts it to the given class type, which - * must be an array class type. - */ - @Nullable - private <T> T getAndCastPropertyArray(@NonNull String key, @NonNull Class<T> tClass) { - Object value = mProperties.get(key); - if (value == null) { - return null; - } - try { - return tClass.cast(value); - } catch (ClassCastException e) { - Log.w(TAG, "Error casting to requested type for key \"" + key + "\"", e); - return null; - } - } - - @Override - public boolean equals(@Nullable Object other) { - // Check only proto's equality is sufficient here since all properties in - // mProperties are ordered by keys and stored in proto. - if (this == other) { - return true; - } - if (!(other instanceof AppSearchDocument)) { - return false; - } - AppSearchDocument otherDocument = (AppSearchDocument) other; - return this.mProto.equals(otherDocument.mProto); - } - - @Override - public int hashCode() { - // Hash only proto is sufficient here since all properties in mProperties are ordered by - // keys and stored in proto. - return mProto.hashCode(); - } - - @Override - public String toString() { - return mProto.toString(); - } - - /** - * The builder class for {@link AppSearchDocument}. - * - * @param <BuilderType> Type of subclass who extend this. - * @hide - */ - public static class Builder<BuilderType extends Builder> { - - private final Map<String, Object> mProperties = new ArrayMap<>(); - private final DocumentProto.Builder mProtoBuilder = DocumentProto.newBuilder(); - private final BuilderType mBuilderTypeInstance; - - /** - * Create a new {@link AppSearchDocument.Builder}. - * - * @param uri The uri of {@link AppSearchDocument}. - * @param schemaType The schema type of the {@link AppSearchDocument}. The passed-in - * {@code schemaType} must be defined using {@link AppSearchManager#setSchema} prior - * to inserting a document of this {@code schemaType} into the AppSearch index using - * {@link AppSearchManager#putDocuments(List)}. Otherwise, the document will be - * rejected by {@link AppSearchManager#putDocuments(List)}. - * @hide - */ - public Builder(@NonNull String uri, @NonNull String schemaType) { - mBuilderTypeInstance = (BuilderType) this; - mProtoBuilder.setUri(uri).setSchema(schemaType); - // Set current timestamp for creation timestamp by default. - setCreationTimestampMillis(System.currentTimeMillis()); - } - - /** - * Sets the score of the {@link AppSearchDocument}. - * - * <p>The score is a query-independent measure of the document's quality, relative to - * other {@link AppSearchDocument}s of the same type. - * - * @throws IllegalArgumentException If the provided value is negative. - * @hide - */ - @NonNull - public BuilderType setScore(@IntRange(from = 0, to = Integer.MAX_VALUE) int score) { - if (score < 0) { - throw new IllegalArgumentException("Document score cannot be negative."); - } - mProtoBuilder.setScore(score); - return mBuilderTypeInstance; - } - - /** - * Set the creation timestamp in milliseconds of the {@link AppSearchDocument}. Should be - * set using a value obtained from the {@link System#currentTimeMillis()} time base. - * - * @hide - */ - @NonNull - public BuilderType setCreationTimestampMillis( - @CurrentTimeMillisLong long creationTimestampMillis) { - mProtoBuilder.setCreationTimestampMs(creationTimestampMillis); - return mBuilderTypeInstance; - } - - /** - * Set the TTL (Time To Live) of the {@link AppSearchDocument}, in milliseconds. - * - * <p>After this many milliseconds since the {@link #setCreationTimestampMillis(long)} - * creation timestamp}, the document is deleted. - * - * @param ttlMillis A non-negative duration in milliseconds. - * @throws IllegalArgumentException If the provided value is negative. - */ - @NonNull - public BuilderType setTtlMillis(@DurationMillisLong long ttlMillis) { - Preconditions.checkArgumentNonNegative( - ttlMillis, "Document ttlMillis cannot be negative."); - mProtoBuilder.setTtlMs(ttlMillis); - return mBuilderTypeInstance; - } - - /** - * Sets one or multiple {@code String} values for a property, replacing its previous - * values. - * - * @param key The key associated with the {@code values}. - * @param values The {@code String} values of the property. - * @hide - */ - @NonNull - public BuilderType setProperty(@NonNull String key, @NonNull String... values) { - putInPropertyMap(key, values); - return mBuilderTypeInstance; - } - - /** - * Sets one or multiple {@code boolean} values for a property, replacing its previous - * values. - * - * @param key The key associated with the {@code values}. - * @param values The {@code boolean} values of the property. - */ - @NonNull - public BuilderType setProperty(@NonNull String key, @NonNull boolean... values) { - putInPropertyMap(key, values); - return mBuilderTypeInstance; - } - - /** - * Sets one or multiple {@code long} values for a property, replacing its previous - * values. - * - * @param key The key associated with the {@code values}. - * @param values The {@code long} values of the property. - */ - @NonNull - public BuilderType setProperty(@NonNull String key, @NonNull long... values) { - putInPropertyMap(key, values); - return mBuilderTypeInstance; - } - - /** - * Sets one or multiple {@code double} values for a property, replacing its previous - * values. - * - * @param key The key associated with the {@code values}. - * @param values The {@code double} values of the property. - */ - @NonNull - public BuilderType setProperty(@NonNull String key, @NonNull double... values) { - putInPropertyMap(key, values); - return mBuilderTypeInstance; - } - - /** - * Sets one or multiple {@code byte[]} for a property, replacing its previous values. - * - * @param key The key associated with the {@code values}. - * @param values The {@code byte[]} of the property. - */ - @NonNull - public BuilderType setProperty(@NonNull String key, @NonNull byte[]... values) { - putInPropertyMap(key, values); - return mBuilderTypeInstance; - } - - /** - * Sets one or multiple {@link AppSearchDocument} values for a property, replacing its - * previous values. - * - * @param key The key associated with the {@code values}. - * @param values The {@link AppSearchDocument} values of the property. - */ - @NonNull - public BuilderType setProperty(@NonNull String key, @NonNull AppSearchDocument... values) { - putInPropertyMap(key, values); - return mBuilderTypeInstance; - } - - private void putInPropertyMap(@NonNull String key, @NonNull String[] values) - throws IllegalArgumentException { - Objects.requireNonNull(key); - Objects.requireNonNull(values); - validateRepeatedPropertyLength(key, values.length); - for (int i = 0; i < values.length; i++) { - if (values[i] == null) { - throw new IllegalArgumentException("The String at " + i + " is null."); - } else if (values[i].length() > MAX_STRING_LENGTH) { - throw new IllegalArgumentException("The String at " + i + " length is: " - + values[i].length() + ", which exceeds length limit: " - + MAX_STRING_LENGTH + "."); - } - } - mProperties.put(key, values); - } - - private void putInPropertyMap(@NonNull String key, @NonNull boolean[] values) { - Objects.requireNonNull(key); - Objects.requireNonNull(values); - validateRepeatedPropertyLength(key, values.length); - mProperties.put(key, values); - } - - private void putInPropertyMap(@NonNull String key, @NonNull double[] values) { - Objects.requireNonNull(key); - Objects.requireNonNull(values); - validateRepeatedPropertyLength(key, values.length); - mProperties.put(key, values); - } - - private void putInPropertyMap(@NonNull String key, @NonNull long[] values) { - Objects.requireNonNull(key); - Objects.requireNonNull(values); - validateRepeatedPropertyLength(key, values.length); - mProperties.put(key, values); - } - - private void putInPropertyMap(@NonNull String key, @NonNull byte[][] values) { - Objects.requireNonNull(key); - Objects.requireNonNull(values); - validateRepeatedPropertyLength(key, values.length); - mProperties.put(key, values); - } - - private void putInPropertyMap(@NonNull String key, @NonNull AppSearchDocument[] values) { - Objects.requireNonNull(key); - Objects.requireNonNull(values); - for (int i = 0; i < values.length; i++) { - if (values[i] == null) { - throw new IllegalArgumentException("The document at " + i + " is null."); - } - } - validateRepeatedPropertyLength(key, values.length); - mProperties.put(key, values); - } - - private static void validateRepeatedPropertyLength(@NonNull String key, int length) { - if (length == 0) { - throw new IllegalArgumentException("The input array is empty."); - } else if (length > MAX_REPEATED_PROPERTY_LENGTH) { - throw new IllegalArgumentException( - "Repeated property \"" + key + "\" has length " + length - + ", which exceeds the limit of " - + MAX_REPEATED_PROPERTY_LENGTH); - } - } - - /** - * Builds the {@link AppSearchDocument} object. - * @hide - */ - public AppSearchDocument build() { - // Build proto by sorting the keys in mProperties to exclude the influence of - // order. Therefore documents will generate same proto as long as the contents are - // same. Note that the order of repeated fields is still preserved. - ArrayList<String> keys = new ArrayList<>(mProperties.keySet()); - Collections.sort(keys); - for (int i = 0; i < keys.size(); i++) { - String name = keys.get(i); - Object values = mProperties.get(name); - PropertyProto.Builder propertyProto = PropertyProto.newBuilder().setName(name); - if (values instanceof boolean[]) { - for (boolean value : (boolean[]) values) { - propertyProto.addBooleanValues(value); - } - } else if (values instanceof long[]) { - for (long value : (long[]) values) { - propertyProto.addInt64Values(value); - } - } else if (values instanceof double[]) { - for (double value : (double[]) values) { - propertyProto.addDoubleValues(value); - } - } else if (values instanceof String[]) { - for (String value : (String[]) values) { - propertyProto.addStringValues(value); - } - } else if (values instanceof AppSearchDocument[]) { - for (AppSearchDocument value : (AppSearchDocument[]) values) { - propertyProto.addDocumentValues(value.getProto()); - } - } else if (values instanceof byte[][]) { - for (byte[] value : (byte[][]) values) { - propertyProto.addBytesValues(ByteString.copyFrom(value)); - } - } else { - throw new IllegalStateException( - "Property \"" + name + "\" has unsupported value type \"" - + values.getClass().getSimpleName() + "\""); - } - mProtoBuilder.addProperties(propertyProto); - } - return new AppSearchDocument(mProtoBuilder.build(), mProperties); - } - } -} diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java deleted file mode 100644 index 5b9457b77ea0..000000000000 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.appsearch; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.appsearch.AppSearchSchema.PropertyConfig; - -/** - * Encapsulates a {@link AppSearchDocument} that represent an email. - * - * <p>This class is a higher level implement of {@link AppSearchDocument}. - * - * <p>This class will eventually migrate to Jetpack, where it will become public API. - * - * @hide - */ -public class AppSearchEmail extends AppSearchDocument { - private static final String KEY_FROM = "from"; - private static final String KEY_TO = "to"; - private static final String KEY_CC = "cc"; - private static final String KEY_BCC = "bcc"; - private static final String KEY_SUBJECT = "subject"; - private static final String KEY_BODY = "body"; - - /** The name of the schema type for {@link AppSearchEmail} documents.*/ - public static final String SCHEMA_TYPE = "builtin:Email"; - - public static final AppSearchSchema SCHEMA = AppSearchSchema.newBuilder(SCHEMA_TYPE) - .addProperty(AppSearchSchema.newPropertyBuilder(KEY_FROM) - .setDataType(PropertyConfig.DATA_TYPE_STRING) - .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL) - .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) - .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) - .build() - - ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_TO) - .setDataType(PropertyConfig.DATA_TYPE_STRING) - .setCardinality(PropertyConfig.CARDINALITY_REPEATED) - .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) - .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) - .build() - - ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_CC) - .setDataType(PropertyConfig.DATA_TYPE_STRING) - .setCardinality(PropertyConfig.CARDINALITY_REPEATED) - .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) - .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) - .build() - - ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_BCC) - .setDataType(PropertyConfig.DATA_TYPE_STRING) - .setCardinality(PropertyConfig.CARDINALITY_REPEATED) - .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) - .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) - .build() - - ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_SUBJECT) - .setDataType(PropertyConfig.DATA_TYPE_STRING) - .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL) - .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) - .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) - .build() - - ).addProperty(AppSearchSchema.newPropertyBuilder(KEY_BODY) - .setDataType(PropertyConfig.DATA_TYPE_STRING) - .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL) - .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) - .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) - .build() - - ).build(); - - /** - * Creates a new {@link AppSearchEmail} from the contents of an existing - * {@link AppSearchDocument}. - * - * @param document The {@link AppSearchDocument} containing the email content. - */ - public AppSearchEmail(@NonNull AppSearchDocument document) { - super(document); - } - - /** - * Get the from address of {@link AppSearchEmail}. - * - * @return Returns the subject of {@link AppSearchEmail} or {@code null} if it's not been set - * yet. - * @hide - */ - @Nullable - public String getFrom() { - return getPropertyString(KEY_FROM); - } - - /** - * Get the destination addresses of {@link AppSearchEmail}. - * - * @return Returns the destination addresses of {@link AppSearchEmail} or {@code null} if it's - * not been set yet. - * @hide - */ - @Nullable - public String[] getTo() { - return getPropertyStringArray(KEY_TO); - } - - /** - * Get the CC list of {@link AppSearchEmail}. - * - * @return Returns the CC list of {@link AppSearchEmail} or {@code null} if it's not been set - * yet. - * @hide - */ - @Nullable - public String[] getCc() { - return getPropertyStringArray(KEY_CC); - } - - /** - * Get the BCC list of {@link AppSearchEmail}. - * - * @return Returns the BCC list of {@link AppSearchEmail} or {@code null} if it's not been set - * yet. - * @hide - */ - @Nullable - public String[] getBcc() { - return getPropertyStringArray(KEY_BCC); - } - - /** - * Get the subject of {@link AppSearchEmail}. - * - * @return Returns the value subject of {@link AppSearchEmail} or {@code null} if it's not been - * set yet. - * @hide - */ - @Nullable - public String getSubject() { - return getPropertyString(KEY_SUBJECT); - } - - /** - * Get the body of {@link AppSearchEmail}. - * - * @return Returns the body of {@link AppSearchEmail} or {@code null} if it's not been set yet. - * @hide - */ - @Nullable - public String getBody() { - return getPropertyString(KEY_BODY); - } - - /** - * The builder class for {@link AppSearchEmail}. - * @hide - */ - public static class Builder extends AppSearchDocument.Builder<AppSearchEmail.Builder> { - - /** - * Create a new {@link AppSearchEmail.Builder} - * @param uri The Uri of the Email. - * @hide - */ - public Builder(@NonNull String uri) { - super(uri, SCHEMA_TYPE); - } - - /** - * Set the from address of {@link AppSearchEmail} - * @hide - */ - @NonNull - public AppSearchEmail.Builder setFrom(@NonNull String from) { - setProperty(KEY_FROM, from); - return this; - } - - /** - * Set the destination address of {@link AppSearchEmail} - * @hide - */ - @NonNull - public AppSearchEmail.Builder setTo(@NonNull String... to) { - setProperty(KEY_TO, to); - return this; - } - - /** - * Set the CC list of {@link AppSearchEmail} - * @hide - */ - @NonNull - public AppSearchEmail.Builder setCc(@NonNull String... cc) { - setProperty(KEY_CC, cc); - return this; - } - - /** - * Set the BCC list of {@link AppSearchEmail} - * @hide - */ - @NonNull - public AppSearchEmail.Builder setBcc(@NonNull String... bcc) { - setProperty(KEY_BCC, bcc); - return this; - } - - /** - * Set the subject of {@link AppSearchEmail} - * @hide - */ - @NonNull - public AppSearchEmail.Builder setSubject(@NonNull String subject) { - setProperty(KEY_SUBJECT, subject); - return this; - } - - /** - * Set the body of {@link AppSearchEmail} - * @hide - */ - @NonNull - public AppSearchEmail.Builder setBody(@NonNull String body) { - setProperty(KEY_BODY, body); - return this; - } - - /** - * Builds the {@link AppSearchEmail} object. - * - * @hide - */ - @NonNull - @Override - public AppSearchEmail build() { - return new AppSearchEmail(super.build()); - } - } -} diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java deleted file mode 100644 index e2c9b0f74870..000000000000 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.app.appsearch; - -import android.annotation.CallbackExecutor; -import android.annotation.NonNull; -import android.annotation.SystemService; -import android.content.Context; -import android.os.RemoteException; - -import com.android.internal.infra.AndroidFuture; - -import com.google.android.icing.proto.SchemaProto; -import com.google.android.icing.proto.SearchResultProto; -import com.google.android.icing.proto.SearchSpecProto; -import com.google.android.icing.proto.StatusProto; -import com.google.android.icing.protobuf.InvalidProtocolBufferException; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; -import java.util.function.BiConsumer; - -/** - * This class provides access to the centralized AppSearch index maintained by the system. - * - * <p>Apps can index structured text documents with AppSearch, which can then be retrieved through - * the query API. - * - * @hide - */ -@SystemService(Context.APP_SEARCH_SERVICE) -public class AppSearchManager { - private final IAppSearchManager mService; - - /** @hide */ - public AppSearchManager(@NonNull IAppSearchManager service) { - mService = service; - } - - /** - * Sets the schema being used by documents provided to the {@link #putDocuments} method. - * - * <p>The schema provided here is compared to the stored copy of the schema previously supplied - * to {@link #setSchema}, if any, to determine how to treat existing documents. The following - * types of schema modifications are always safe and are made without deleting any existing - * documents: - * <ul> - * <li>Addition of new types - * <li>Addition of new - * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL - * OPTIONAL} or - * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED - * REPEATED} properties to a type - * <li>Changing the cardinality of a data type to be less restrictive (e.g. changing an - * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL - * OPTIONAL} property into a - * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REPEATED - * REPEATED} property. - * </ul> - * - * <p>The following types of schema changes are not backwards-compatible. Supplying a schema - * with such changes will result in this call throwing an {@link IllegalSchemaException} - * describing the incompatibility, and the previously set schema will remain active: - * <ul> - * <li>Removal of an existing type - * <li>Removal of a property from a type - * <li>Changing the data type ({@code boolean}, {@code long}, etc.) of an existing property - * <li>For properties of {@code Document} type, changing the schema type of - * {@code Document Documents} of that property - * <li>Changing the cardinality of a data type to be more restrictive (e.g. changing an - * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_OPTIONAL - * OPTIONAL} property into a - * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED - * REQUIRED} property). - * <li>Adding a - * {@link android.app.appsearch.AppSearchSchema.PropertyConfig#CARDINALITY_REQUIRED - * REQUIRED} property. - * </ul> - * - * <p>If you need to make non-backwards-compatible changes as described above, instead use the - * {@link #setSchema(List, boolean)} method with the {@code forceOverride} parameter set to - * {@code true}. - * - * <p>It is a no-op to set the same schema as has been previously set; this is handled - * efficiently. - * - * @param schemas The schema configs for the types used by the calling app. - * @throws IllegalSchemaException If the provided schema is invalid, or is incompatible with the - * previous schema. - * - * @hide - */ - public void setSchema(@NonNull AppSearchSchema... schemas) { - setSchema(Arrays.asList(schemas), /*forceOverride=*/false); - } - - /** - * Sets the schema being used by documents provided to the {@link #putDocuments} method. - * - * <p>This method is similar to {@link #setSchema(AppSearchSchema...)}, except for the - * {@code forceOverride} parameter. If a backwards-incompatible schema is specified but the - * {@code forceOverride} parameter is set to {@code true}, instead of throwing an - * {@link IllegalSchemaException}, all documents which are not compatible with the new schema - * will be deleted and the incompatible schema will be applied. - * - * @param schemas The schema configs for the types used by the calling app. - * @param forceOverride Whether to force the new schema to be applied even if there are - * incompatible changes versus the previously set schema. Documents which are incompatible - * with the new schema will be deleted. - * @throws IllegalSchemaException If the provided schema is invalid, or is incompatible with the - * previous schema and the {@code forceOverride} parameter is set to {@code false}. - * - * @hide - */ - public void setSchema(@NonNull List<AppSearchSchema> schemas, boolean forceOverride) { - // Prepare the merged schema for transmission. - SchemaProto.Builder schemaProtoBuilder = SchemaProto.newBuilder(); - for (AppSearchSchema schema : schemas) { - schemaProtoBuilder.addTypes(schema.getProto()); - } - - // Serialize and send the schema. - // TODO: This should use com.android.internal.infra.RemoteStream or another mechanism to - // avoid binder limits. - byte[] schemaBytes = schemaProtoBuilder.build().toByteArray(); - AndroidFuture<Void> future = new AndroidFuture<>(); - try { - mService.setSchema(schemaBytes, forceOverride, future); - } catch (RemoteException e) { - future.completeExceptionally(e); - } - getFutureOrThrow(future); - } - - /** - * Index {@link AppSearchDocument Documents} into AppSearch. - * - * <p>You should not call this method directly; instead, use the - * {@code AppSearch#putDocuments()} API provided by JetPack. - * - * <p>Each {@link AppSearchDocument Document's} {@code schemaType} field must be set to the - * name of a schema type previously registered via the {@link #setSchema} method. - * - * @param documents {@link AppSearchDocument Documents} that need to be indexed. - * @return An {@link AppSearchBatchResult} mapping the document URIs to {@link Void} if they - * were successfully indexed, or a {@link Throwable} describing the failure if they could - * not be indexed. - * @hide - */ - public AppSearchBatchResult<String, Void> putDocuments( - @NonNull List<AppSearchDocument> documents) { - // TODO(b/146386470): Transmit these documents as a RemoteStream instead of sending them in - // one big list. - List<byte[]> documentsBytes = new ArrayList<>(documents.size()); - for (AppSearchDocument document : documents) { - documentsBytes.add(document.getProto().toByteArray()); - } - AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>(); - try { - mService.putDocuments(documentsBytes, future); - } catch (RemoteException e) { - future.completeExceptionally(e); - } - return getFutureOrThrow(future); - } - - /** - * This method searches for documents based on a given query string. It also accepts - * specifications regarding how to search and format the results. - * - *<p>Currently we support following features in the raw query format: - * <ul> - * <li>AND - * <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and - * ‘cat’”). - * Example: hello world matches documents that have both ‘hello’ and ‘world’ - * <li>OR - * <p>OR joins (e.g. “match documents that have either the term ‘dog’ or - * ‘cat’”). - * Example: dog OR puppy - * <li>Exclusion - * <p>Exclude a term (e.g. “match documents that do - * not have the term ‘dog’”). - * Example: -dog excludes the term ‘dog’ - * <li>Grouping terms - * <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g. - * “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”). - * Example: (dog puppy) (cat kitten) two one group containing two terms. - * <li>Property restricts - * <p> Specifies which properties of a document to specifically match terms in (e.g. - * “match documents where the ‘subject’ property contains ‘important’”). - * Example: subject:important matches documents with the term ‘important’ in the - * ‘subject’ property - * <li>Schema type restricts - * <p>This is similar to property restricts, but allows for restricts on top-level document - * fields, such as schema_type. Clients should be able to limit their query to documents of - * a certain schema_type (e.g. “match documents that are of the ‘Email’ schema_type”). - * Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will match documents - * that contain the query term ‘dog’ and are of either the ‘Email’ schema type or the - * ‘Video’ schema type. - * </ul> - * - * <p> It is strongly recommended to use Jetpack APIs. - * - * @param queryExpression Query String to search. - * @param searchSpec Spec for setting filters, raw query etc. - * @param executor Executor on which to invoke the callback. - * @param callback Callback to receive errors resulting from the query operation. If the - * operation succeeds, the callback will be invoked with {@code null}. - * @hide - */ - @NonNull - public void query( - @NonNull String queryExpression, - @NonNull SearchSpec searchSpec, - @NonNull @CallbackExecutor Executor executor, - @NonNull BiConsumer<? super SearchResults, ? super Throwable> callback) { - AndroidFuture<byte[]> future = new AndroidFuture<>(); - future.whenCompleteAsync((searchResultBytes, err) -> { - if (err != null) { - callback.accept(null, err); - return; - } - - if (searchResultBytes != null) { - SearchResultProto searchResultProto; - try { - searchResultProto = SearchResultProto.parseFrom(searchResultBytes); - } catch (InvalidProtocolBufferException e) { - callback.accept(null, e); - return; - } - if (searchResultProto.getStatus().getCode() != StatusProto.Code.OK) { - // TODO(sidchhabra): Add better exception handling. - callback.accept( - null, - new RuntimeException(searchResultProto.getStatus().getMessage())); - return; - } - SearchResults searchResults = new SearchResults(searchResultProto); - callback.accept(searchResults, null); - return; - } - - // Nothing was supplied in the future at all - callback.accept( - null, new IllegalStateException("Unknown failure occurred while querying")); - }, executor); - - try { - SearchSpecProto searchSpecProto = searchSpec.getSearchSpecProto(); - searchSpecProto = searchSpecProto.toBuilder().setQuery(queryExpression).build(); - mService.query(searchSpecProto.toByteArray(), - searchSpec.getResultSpecProto().toByteArray(), - searchSpec.getScoringSpecProto().toByteArray(), future); - } catch (RemoteException e) { - future.completeExceptionally(e); - } - } - - private static <T> T getFutureOrThrow(@NonNull AndroidFuture<T> future) { - try { - return future.get(); - } catch (Throwable e) { - if (e instanceof ExecutionException) { - e = e.getCause(); - } - if (e instanceof RuntimeException) { - throw (RuntimeException) e; - } - if (e instanceof Error) { - throw (Error) e; - } - throw new RuntimeException(e); - } - } -} diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java deleted file mode 100644 index 02cc967e7daf..000000000000 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.app.appsearch; - -import android.annotation.SystemApi; -import android.app.SystemServiceRegistry; -import android.content.Context; - -/** - * Class holding initialization code for the AppSearch module. - * - * @hide - */ -@SystemApi -public class AppSearchManagerFrameworkInitializer { - private AppSearchManagerFrameworkInitializer() {} - - /** - * Called by {@link SystemServiceRegistry}'s static initializer and registers all AppSearch - * services to {@link Context}, so that {@link Context#getSystemService} can return them. - * - * @throws IllegalStateException if this is called from anywhere besides - * {@link SystemServiceRegistry} - */ - public static void initialize() { - SystemServiceRegistry.registerStaticService( - Context.APP_SEARCH_SERVICE, AppSearchManager.class, - (service) -> new AppSearchManager(IAppSearchManager.Stub.asInterface(service))); - } -} diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java deleted file mode 100644 index 1d54dc4971a6..000000000000 --- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.appsearch; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.util.ArraySet; - -import com.android.internal.annotations.VisibleForTesting; - -import com.google.android.icing.proto.PropertyConfigProto; -import com.google.android.icing.proto.SchemaTypeConfigProto; -import com.google.android.icing.proto.TermMatchType; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.Set; - -/** - * The AppSearch Schema for a particular type of document. - * - * <p>For example, an e-mail message or a music recording could be a schema type. - * - * <p>The schema consists of type information, properties, and config (like tokenization type). - * - * @hide - */ -public final class AppSearchSchema { - private final SchemaTypeConfigProto mProto; - - private AppSearchSchema(SchemaTypeConfigProto proto) { - mProto = proto; - } - - /** Creates a new {@link AppSearchSchema.Builder}. */ - @NonNull - public static AppSearchSchema.Builder newBuilder(@NonNull String typeName) { - return new AppSearchSchema.Builder(typeName); - } - - /** Creates a new {@link PropertyConfig.Builder}. */ - @NonNull - public static PropertyConfig.Builder newPropertyBuilder(@NonNull String propertyName) { - return new PropertyConfig.Builder(propertyName); - } - - /** - * Returns the {@link SchemaTypeConfigProto} populated by this builder. - * @hide - */ - @NonNull - @VisibleForTesting - public SchemaTypeConfigProto getProto() { - return mProto; - } - - @Override - public String toString() { - return mProto.toString(); - } - - /** Builder for {@link AppSearchSchema objects}. */ - public static final class Builder { - private final SchemaTypeConfigProto.Builder mProtoBuilder = - SchemaTypeConfigProto.newBuilder(); - - private Builder(@NonNull String typeName) { - mProtoBuilder.setSchemaType(typeName); - } - - /** Adds a property to the given type. */ - @NonNull - public AppSearchSchema.Builder addProperty(@NonNull PropertyConfig propertyConfig) { - mProtoBuilder.addProperties(propertyConfig.mProto); - return this; - } - - /** - * Constructs a new {@link AppSearchSchema} from the contents of this builder. - * - * <p>After calling this method, the builder must no longer be used. - */ - @NonNull - public AppSearchSchema build() { - Set<String> propertyNames = new ArraySet<>(); - for (PropertyConfigProto propertyConfigProto : mProtoBuilder.getPropertiesList()) { - if (!propertyNames.add(propertyConfigProto.getPropertyName())) { - throw new IllegalSchemaException( - "Property defined more than once: " - + propertyConfigProto.getPropertyName()); - } - } - return new AppSearchSchema(mProtoBuilder.build()); - } - } - - /** - * Configuration for a single property (field) of a document type. - * - * <p>For example, an {@code EmailMessage} would be a type and the {@code subject} would be - * a property. - */ - public static final class PropertyConfig { - /** Physical data-types of the contents of the property. */ - // NOTE: The integer values of these constants must match the proto enum constants in - // com.google.android.icing.proto.PropertyConfigProto.DataType.Code. - @IntDef(prefix = {"DATA_TYPE_"}, value = { - DATA_TYPE_STRING, - DATA_TYPE_INT64, - DATA_TYPE_DOUBLE, - DATA_TYPE_BOOLEAN, - DATA_TYPE_BYTES, - DATA_TYPE_DOCUMENT, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface DataType {} - - public static final int DATA_TYPE_STRING = 1; - public static final int DATA_TYPE_INT64 = 2; - public static final int DATA_TYPE_DOUBLE = 3; - public static final int DATA_TYPE_BOOLEAN = 4; - - /** Unstructured BLOB. */ - public static final int DATA_TYPE_BYTES = 5; - - /** - * Indicates that the property itself is an Document, making it part a hierarchical - * Document schema. Any property using this DataType MUST have a valid - * {@code schemaType}. - */ - public static final int DATA_TYPE_DOCUMENT = 6; - - /** The cardinality of the property (whether it is required, optional or repeated). */ - // NOTE: The integer values of these constants must match the proto enum constants in - // com.google.android.icing.proto.PropertyConfigProto.Cardinality.Code. - @IntDef(prefix = {"CARDINALITY_"}, value = { - CARDINALITY_REPEATED, - CARDINALITY_OPTIONAL, - CARDINALITY_REQUIRED, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface Cardinality {} - - /** Any number of items (including zero) [0...*]. */ - public static final int CARDINALITY_REPEATED = 1; - - /** Zero or one value [0,1]. */ - public static final int CARDINALITY_OPTIONAL = 2; - - /** Exactly one value [1]. */ - public static final int CARDINALITY_REQUIRED = 3; - - /** Encapsulates the configurations on how AppSearch should query/index these terms. */ - @IntDef(prefix = {"INDEXING_TYPE_"}, value = { - INDEXING_TYPE_NONE, - INDEXING_TYPE_EXACT_TERMS, - INDEXING_TYPE_PREFIXES, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface IndexingType {} - - /** - * Content in this property will not be tokenized or indexed. - * - * <p>Useful if the data type is not made up of terms (e.g. - * {@link PropertyConfig#DATA_TYPE_DOCUMENT} or {@link PropertyConfig#DATA_TYPE_BYTES} - * type). All the properties inside the nested property won't be indexed regardless of the - * value of {@code indexingType} for the nested properties. - */ - public static final int INDEXING_TYPE_NONE = 0; - - /** - * Content in this property should only be returned for queries matching the exact tokens - * appearing in this property. - * - * <p>Ex. A property with "fool" should NOT match a query for "foo". - */ - public static final int INDEXING_TYPE_EXACT_TERMS = 1; - - /** - * Content in this property should be returned for queries that are either exact matches or - * query matches of the tokens appearing in this property. - * - * <p>Ex. A property with "fool" <b>should</b> match a query for "foo". - */ - public static final int INDEXING_TYPE_PREFIXES = 2; - - /** Configures how tokens should be extracted from this property. */ - // NOTE: The integer values of these constants must match the proto enum constants in - // com.google.android.icing.proto.IndexingConfig.TokenizerType.Code. - @IntDef(prefix = {"TOKENIZER_TYPE_"}, value = { - TOKENIZER_TYPE_NONE, - TOKENIZER_TYPE_PLAIN, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface TokenizerType {} - - /** - * It is only valid for tokenizer_type to be 'NONE' if the data type is - * {@link PropertyConfig#DATA_TYPE_DOCUMENT}. - */ - public static final int TOKENIZER_TYPE_NONE = 0; - - /** Tokenization for plain text. */ - public static final int TOKENIZER_TYPE_PLAIN = 1; - - private final PropertyConfigProto mProto; - - private PropertyConfig(PropertyConfigProto proto) { - mProto = proto; - } - - @Override - public String toString() { - return mProto.toString(); - } - - /** - * Builder for {@link PropertyConfig}. - * - * <p>The following properties must be set, or {@link PropertyConfig} construction will - * fail: - * <ul> - * <li>dataType - * <li>cardinality - * </ul> - * - * <p>In addition, if {@code schemaType} is {@link #DATA_TYPE_DOCUMENT}, {@code schemaType} - * is also required. - */ - public static final class Builder { - private final PropertyConfigProto.Builder mPropertyConfigProto = - PropertyConfigProto.newBuilder(); - private final com.google.android.icing.proto.IndexingConfig.Builder - mIndexingConfigProto = - com.google.android.icing.proto.IndexingConfig.newBuilder(); - - private Builder(String propertyName) { - mPropertyConfigProto.setPropertyName(propertyName); - } - - /** - * Type of data the property contains (e.g. string, int, bytes, etc). - * - * <p>This property must be set. - */ - @NonNull - public PropertyConfig.Builder setDataType(@DataType int dataType) { - PropertyConfigProto.DataType.Code dataTypeProto = - PropertyConfigProto.DataType.Code.forNumber(dataType); - if (dataTypeProto == null) { - throw new IllegalArgumentException("Invalid dataType: " + dataType); - } - mPropertyConfigProto.setDataType(dataTypeProto); - return this; - } - - /** - * The logical schema-type of the contents of this property. - * - * <p>Only required when {@link #setDataType(int)} is set to - * {@link #DATA_TYPE_DOCUMENT}. Otherwise, it is ignored. - */ - @NonNull - public PropertyConfig.Builder setSchemaType(@NonNull String schemaType) { - mPropertyConfigProto.setSchemaType(schemaType); - return this; - } - - /** - * The cardinality of the property (whether it is optional, required or repeated). - * - * <p>This property must be set. - */ - @NonNull - public PropertyConfig.Builder setCardinality(@Cardinality int cardinality) { - PropertyConfigProto.Cardinality.Code cardinalityProto = - PropertyConfigProto.Cardinality.Code.forNumber(cardinality); - if (cardinalityProto == null) { - throw new IllegalArgumentException("Invalid cardinality: " + cardinality); - } - mPropertyConfigProto.setCardinality(cardinalityProto); - return this; - } - - /** - * Configures how a property should be indexed so that it can be retrieved by queries. - */ - @NonNull - public PropertyConfig.Builder setIndexingType(@IndexingType int indexingType) { - TermMatchType.Code termMatchTypeProto; - switch (indexingType) { - case INDEXING_TYPE_NONE: - termMatchTypeProto = TermMatchType.Code.UNKNOWN; - break; - case INDEXING_TYPE_EXACT_TERMS: - termMatchTypeProto = TermMatchType.Code.EXACT_ONLY; - break; - case INDEXING_TYPE_PREFIXES: - termMatchTypeProto = TermMatchType.Code.PREFIX; - break; - default: - throw new IllegalArgumentException("Invalid indexingType: " + indexingType); - } - mIndexingConfigProto.setTermMatchType(termMatchTypeProto); - return this; - } - - /** Configures how this property should be tokenized (split into words). */ - @NonNull - public PropertyConfig.Builder setTokenizerType(@TokenizerType int tokenizerType) { - com.google.android.icing.proto.IndexingConfig.TokenizerType.Code - tokenizerTypeProto = - com.google.android.icing.proto.IndexingConfig - .TokenizerType.Code.forNumber(tokenizerType); - if (tokenizerTypeProto == null) { - throw new IllegalArgumentException("Invalid tokenizerType: " + tokenizerType); - } - mIndexingConfigProto.setTokenizerType(tokenizerTypeProto); - return this; - } - - /** - * Constructs a new {@link PropertyConfig} from the contents of this builder. - * - * <p>After calling this method, the builder must no longer be used. - * - * @throws IllegalSchemaException If the property is not correctly populated (e.g. - * missing {@code dataType}). - */ - @NonNull - public PropertyConfig build() { - mPropertyConfigProto.setIndexingConfig(mIndexingConfigProto); - // TODO(b/147692920): Send the schema to Icing Lib for official validation, instead - // of partially reimplementing some of the validation Icing does here. - if (mPropertyConfigProto.getDataType() - == PropertyConfigProto.DataType.Code.UNKNOWN) { - throw new IllegalSchemaException("Missing field: dataType"); - } - if (mPropertyConfigProto.getSchemaType().isEmpty() - && mPropertyConfigProto.getDataType() - == PropertyConfigProto.DataType.Code.DOCUMENT) { - throw new IllegalSchemaException( - "Missing field: schemaType (required for configs with " - + "dataType = DOCUMENT)"); - } - if (mPropertyConfigProto.getCardinality() - == PropertyConfigProto.Cardinality.Code.UNKNOWN) { - throw new IllegalSchemaException("Missing field: cardinality"); - } - return new PropertyConfig(mPropertyConfigProto.build()); - } - } - } -} diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl deleted file mode 100644 index eef41ed7104d..000000000000 --- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright 2020, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.app.appsearch; - -import com.android.internal.infra.AndroidFuture; - -parcelable AppSearchBatchResult; - -/** {@hide} */ -interface IAppSearchManager { - /** - * Sets the schema. - * - * @param schemaBytes Serialized SchemaProto. - * @param forceOverride Whether to apply the new schema even if it is incompatible. All - * incompatible documents will be deleted. - * @param callback {@link AndroidFuture}<{@link Void}>. Will be completed with - * {@code null} upon successful completion of the setSchema call, or completed - * exceptionally if setSchema fails. - */ - void setSchema(in byte[] schemaBytes, boolean forceOverride, in AndroidFuture callback); - - /** - * Inserts documents into the index. - * - * @param documentsBytes {@link List}<byte[]> of serialized DocumentProtos. - * @param callback - * {@link AndroidFuture}<{@link AppSearchBatchResult}<{@link String}, {@link Void}>>. - * If the call fails to start, {@code callback} will be completed exceptionally. Otherwise, - * {@code callback} will be completed with an - * {@link AppSearchBatchResult}<{@link String}, {@link Void}> - * where the keys are document URIs, and the values are {@code null}. - */ - void putDocuments(in List documentsBytes, in AndroidFuture<AppSearchBatchResult> callback); - - /** - * Searches a document based on a given specifications. - * - * @param searchSpecBytes Serialized SearchSpecProto. - * @param resultSpecBytes Serialized SearchResultsProto. - * @param scoringSpecBytes Serialized ScoringSpecProto. - * @param callback {@link AndroidFuture}. Will be completed with a serialized - * {@link SearchResultsProto}, or completed exceptionally if query fails. - */ - void query(in byte[] searchSpecBytes, in byte[] resultSpecBytes, - in byte[] scoringSpecBytes, in AndroidFuture callback); -} diff --git a/apex/appsearch/framework/java/android/app/appsearch/IllegalSchemaException.java b/apex/appsearch/framework/java/android/app/appsearch/IllegalSchemaException.java deleted file mode 100644 index f9e528cd2951..000000000000 --- a/apex/appsearch/framework/java/android/app/appsearch/IllegalSchemaException.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.appsearch; - -import android.annotation.NonNull; - -/** - * Indicates that a {@link android.app.appsearch.AppSearchSchema} has logical inconsistencies such - * as unpopulated mandatory fields or illegal combinations of parameters. - * - * @hide - */ -public class IllegalSchemaException extends IllegalArgumentException { - /** - * Constructs a new {@link IllegalSchemaException}. - * - * @param message A developer-readable description of the issue with the bundle. - */ - public IllegalSchemaException(@NonNull String message) { - super(message); - } -} diff --git a/apex/appsearch/framework/java/android/app/appsearch/IllegalSearchSpecException.java b/apex/appsearch/framework/java/android/app/appsearch/IllegalSearchSpecException.java deleted file mode 100644 index 0d029f029ee5..000000000000 --- a/apex/appsearch/framework/java/android/app/appsearch/IllegalSearchSpecException.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.appsearch; - -import android.annotation.NonNull; - -/** - * Indicates that a {@link android.app.appsearch.SearchResults} has logical inconsistencies such - * as unpopulated mandatory fields or illegal combinations of parameters. - * - * @hide - */ -public class IllegalSearchSpecException extends IllegalArgumentException { - /** - * Constructs a new {@link IllegalSearchSpecException}. - * - * @param message A developer-readable description of the issue with the bundle. - */ - public IllegalSearchSpecException(@NonNull String message) { - super(message); - } -} diff --git a/apex/appsearch/framework/java/android/app/appsearch/MatchInfo.java b/apex/appsearch/framework/java/android/app/appsearch/MatchInfo.java deleted file mode 100644 index 5ce296082d70..000000000000 --- a/apex/appsearch/framework/java/android/app/appsearch/MatchInfo.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.appsearch; - -import android.annotation.NonNull; -import android.util.Range; - -import com.google.android.icing.proto.SnippetMatchProto; - -/** - * Snippet: It refers to a substring of text from the content of document that is returned as a - * part of search result. - * This class represents a match objects for any Snippets that might be present in - * {@link SearchResults} from query. Using this class user can get the full text, exact matches and - * Snippets of document content for a given match. - * - * <p>Class Example 1: - * A document contains following text in property subject: - * <p>A commonly used fake word is foo. Another nonsense word that’s used a lot is bar. - * - * <p>If the queryExpression is "foo". - * - * <p>{@link MatchInfo#getPropertyPath()} returns "subject" - * <p>{@link MatchInfo#getFullText()} returns "A commonly used fake word is foo. Another nonsense - * word that’s used a lot is bar." - * <p>{@link MatchInfo#getExactMatchPosition()} returns [29, 32] - * <p>{@link MatchInfo#getExactMatch()} returns "foo" - * <p>{@link MatchInfo#getSnippetPosition()} returns [29, 41] - * <p>{@link MatchInfo#getSnippet()} returns "is foo. Another" - * <p> - * <p>Class Example 2: - * A document contains a property name sender which contains 2 property names name and email, so - * we will have 2 property paths: {@code sender.name} and {@code sender.email}. - * <p> Let {@code sender.name = "Test Name Jr."} and {@code sender.email = "TestNameJr@gmail.com"} - * - * <p>If the queryExpression is "Test". We will have 2 matches. - * - * <p> Match-1 - * <p>{@link MatchInfo#getPropertyPath()} returns "sender.name" - * <p>{@link MatchInfo#getFullText()} returns "Test Name Jr." - * <p>{@link MatchInfo#getExactMatchPosition()} returns [0, 4] - * <p>{@link MatchInfo#getExactMatch()} returns "Test" - * <p>{@link MatchInfo#getSnippetPosition()} returns [0, 9] - * <p>{@link MatchInfo#getSnippet()} returns "Test Name Jr." - * <p> Match-2 - * <p>{@link MatchInfo#getPropertyPath()} returns "sender.email" - * <p>{@link MatchInfo#getFullText()} returns "TestNameJr@gmail.com" - * <p>{@link MatchInfo#getExactMatchPosition()} returns [0, 20] - * <p>{@link MatchInfo#getExactMatch()} returns "TestNameJr@gmail.com" - * <p>{@link MatchInfo#getSnippetPosition()} returns [0, 20] - * <p>{@link MatchInfo#getSnippet()} returns "TestNameJr@gmail.com" - * @hide - */ -// TODO(sidchhabra): Capture real snippet after integration with icingLib. -public final class MatchInfo { - - private final String mPropertyPath; - private final SnippetMatchProto mSnippetMatch; - private final AppSearchDocument mDocument; - /** - * List of content with same property path in a document when there are multiple matches in - * repeated sections. - */ - private final String[] mValues; - - /** @hide */ - public MatchInfo(@NonNull String propertyPath, @NonNull SnippetMatchProto snippetMatch, - @NonNull AppSearchDocument document) { - mPropertyPath = propertyPath; - mSnippetMatch = snippetMatch; - mDocument = document; - // In IcingLib snippeting is available for only 3 data types i.e String, double and long, - // so we need to check which of these three are requested. - // TODO (sidchhabra): getPropertyStringArray takes property name, handle for property path. - String[] values = mDocument.getPropertyStringArray(propertyPath); - if (values == null) { - values = doubleToString(mDocument.getPropertyDoubleArray(propertyPath)); - } - if (values == null) { - values = longToString(mDocument.getPropertyLongArray(propertyPath)); - } - if (values == null) { - throw new IllegalStateException("No content found for requested property path!"); - } - mValues = values; - } - - /** - * Gets the property path corresponding to the given entry. - * <p>Property Path: '.' - delimited sequence of property names indicating which property in - * the Document these snippets correspond to. - * <p>Example properties: 'body', 'sender.name', 'sender.emailaddress', etc. - * For class example 1 this returns "subject" - */ - @NonNull - public String getPropertyPath() { - return mPropertyPath; - } - - /** - * Gets the full text corresponding to the given entry. - * <p>For class example this returns "A commonly used fake word is foo. Another nonsense word - * that’s used a lot is bar." - */ - @NonNull - public String getFullText() { - return mValues[mSnippetMatch.getValuesIndex()]; - } - - /** - * Gets the exact match range corresponding to the given entry. - * <p>For class example 1 this returns [29, 32] - */ - @NonNull - public Range getExactMatchPosition() { - return new Range(mSnippetMatch.getExactMatchPosition(), - mSnippetMatch.getExactMatchPosition() + mSnippetMatch.getExactMatchBytes()); - } - - /** - * Gets the exact match corresponding to the given entry. - * <p>For class example 1 this returns "foo" - */ - @NonNull - public CharSequence getExactMatch() { - return getSubstring(getExactMatchPosition()); - } - - /** - * Gets the snippet range corresponding to the given entry. - * <p>For class example 1 this returns [29, 41] - */ - @NonNull - public Range getSnippetPosition() { - return new Range(mSnippetMatch.getWindowPosition(), - mSnippetMatch.getWindowPosition() + mSnippetMatch.getWindowBytes()); - } - - /** - * Gets the snippet corresponding to the given entry. - * <p>Snippet - Provides a subset of the content to display. The - * length of this content can be changed {@link SearchSpec.Builder#setMaxSnippetSize(int)}. - * Windowing is centered around the middle of the matched token with content on either side - * clipped to token boundaries. - * <p>For class example 1 this returns "foo. Another" - */ - @NonNull - public CharSequence getSnippet() { - return getSubstring(getSnippetPosition()); - } - - private CharSequence getSubstring(Range range) { - return getFullText() - .substring((int) range.getLower(), (int) range.getUpper()); - } - - /** Utility method to convert double[] to String[] */ - private String[] doubleToString(double[] values) { - //TODO(sidchhabra): Implement the method. - return null; - } - - /** Utility method to convert long[] to String[] */ - private String[] longToString(long[] values) { - //TODO(sidchhabra): Implement the method. - return null; - } -} diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java deleted file mode 100644 index 7287fe68f519..000000000000 --- a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.appsearch; - -import android.annotation.NonNull; -import android.annotation.Nullable; - -import com.google.android.icing.proto.SearchResultProto; -import com.google.android.icing.proto.SnippetMatchProto; -import com.google.android.icing.proto.SnippetProto; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; - -/** - * SearchResults are a list of results that are returned from a query. Each result from this - * list contains a document and may contain other fields like snippets based on request. - * This iterator class is not thread safe. - * @hide - */ -public final class SearchResults implements Iterator<SearchResults.Result> { - - private final SearchResultProto mSearchResultProto; - private int mNextIdx; - - /** @hide */ - public SearchResults(SearchResultProto searchResultProto) { - mSearchResultProto = searchResultProto; - } - - @Override - public boolean hasNext() { - return mNextIdx < mSearchResultProto.getResultsCount(); - } - - @NonNull - @Override - public Result next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - Result result = new Result(mSearchResultProto.getResults(mNextIdx)); - mNextIdx++; - return result; - } - - - - /** - * This class represents the result obtained from the query. It will contain the document which - * which matched the specified query string and specifications. - * @hide - */ - public static final class Result { - private final SearchResultProto.ResultProto mResultProto; - - @Nullable - private AppSearchDocument mDocument; - - private Result(SearchResultProto.ResultProto resultProto) { - mResultProto = resultProto; - } - - /** - * Contains the matching {@link AppSearchDocument}. - * @return Document object which matched the query. - * @hide - */ - @NonNull - public AppSearchDocument getDocument() { - if (mDocument == null) { - mDocument = new AppSearchDocument(mResultProto.getDocument()); - } - return mDocument; - } - - /** - * Contains a list of Snippets that matched the request. Only populated when requested in - * {@link SearchSpec.Builder#setMaxSnippetSize(int)}. - * @return List of matches based on {@link SearchSpec}, if snippeting is disabled and this - * method is called it will return {@code null}. Users can also restrict snippet population - * using {@link SearchSpec.Builder#setNumToSnippet} and - * {@link SearchSpec.Builder#setNumMatchesPerProperty}, for all results after that value - * this method will return {@code null}. - * @hide - */ - // TODO(sidchhabra): Replace Document with proper constructor. - @Nullable - public List<MatchInfo> getMatchInfo() { - if (!mResultProto.hasSnippet()) { - return null; - } - AppSearchDocument document = getDocument(); - List<MatchInfo> matchList = new ArrayList<>(); - for (Iterator entryProtoIterator = mResultProto.getSnippet() - .getEntriesList().iterator(); entryProtoIterator.hasNext(); ) { - SnippetProto.EntryProto entry = (SnippetProto.EntryProto) entryProtoIterator.next(); - for (Iterator snippetMatchProtoIterator = entry.getSnippetMatchesList().iterator(); - snippetMatchProtoIterator.hasNext(); ) { - matchList.add(new MatchInfo(entry.getPropertyName(), - (SnippetMatchProto) snippetMatchProtoIterator.next(), document)); - } - } - return matchList; - } - } - - @Override - public String toString() { - return mSearchResultProto.toString(); - } -} diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java b/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java deleted file mode 100644 index c276ae1fe45e..000000000000 --- a/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.appsearch; - -import android.annotation.IntDef; -import android.annotation.NonNull; - -import com.google.android.icing.proto.ResultSpecProto; -import com.google.android.icing.proto.ScoringSpecProto; -import com.google.android.icing.proto.SearchSpecProto; -import com.google.android.icing.proto.TermMatchType; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - - -/** - * This class represents the specification logic for AppSearch. It can be used to set the type of - * search, like prefix or exact only or apply filters to search for a specific schema type only etc. - * @hide - */ -// TODO(sidchhabra) : AddResultSpec fields for Snippets etc. -public final class SearchSpec { - - private final SearchSpecProto mSearchSpecProto; - private final ResultSpecProto mResultSpecProto; - private final ScoringSpecProto mScoringSpecProto; - - private SearchSpec(@NonNull SearchSpecProto searchSpecProto, - @NonNull ResultSpecProto resultSpecProto, @NonNull ScoringSpecProto scoringSpecProto) { - mSearchSpecProto = searchSpecProto; - mResultSpecProto = resultSpecProto; - mScoringSpecProto = scoringSpecProto; - } - - /** Creates a new {@link SearchSpec.Builder}. */ - @NonNull - public static SearchSpec.Builder newBuilder() { - return new SearchSpec.Builder(); - } - - /** @hide */ - @NonNull - SearchSpecProto getSearchSpecProto() { - return mSearchSpecProto; - } - - /** @hide */ - @NonNull - ResultSpecProto getResultSpecProto() { - return mResultSpecProto; - } - - /** @hide */ - @NonNull - ScoringSpecProto getScoringSpecProto() { - return mScoringSpecProto; - } - - /** Term Match Type for the query. */ - // NOTE: The integer values of these constants must match the proto enum constants in - // {@link com.google.android.icing.proto.SearchSpecProto.termMatchType} - @IntDef(prefix = {"TERM_MATCH_TYPE_"}, value = { - TERM_MATCH_TYPE_EXACT_ONLY, - TERM_MATCH_TYPE_PREFIX - }) - @Retention(RetentionPolicy.SOURCE) - public @interface TermMatchTypeCode {} - - /** - * Query terms will only match exact tokens in the index. - * <p>Ex. A query term "foo" will only match indexed token "foo", and not "foot" or "football". - */ - public static final int TERM_MATCH_TYPE_EXACT_ONLY = 1; - /** - * Query terms will match indexed tokens when the query term is a prefix of the token. - * <p>Ex. A query term "foo" will match indexed tokens like "foo", "foot", and "football". - */ - public static final int TERM_MATCH_TYPE_PREFIX = 2; - - /** Ranking Strategy for query result.*/ - // NOTE: The integer values of these constants must match the proto enum constants in - // {@link ScoringSpecProto.RankingStrategy.Code } - @IntDef(prefix = {"RANKING_STRATEGY_"}, value = { - RANKING_STRATEGY_NONE, - RANKING_STRATEGY_DOCUMENT_SCORE, - RANKING_STRATEGY_CREATION_TIMESTAMP - }) - @Retention(RetentionPolicy.SOURCE) - public @interface RankingStrategyCode {} - - /** No Ranking, results are returned in arbitrary order.*/ - public static final int RANKING_STRATEGY_NONE = 0; - /** Ranked by app-provided document scores. */ - public static final int RANKING_STRATEGY_DOCUMENT_SCORE = 1; - /** Ranked by document creation timestamps. */ - public static final int RANKING_STRATEGY_CREATION_TIMESTAMP = 2; - - /** Order for query result.*/ - // NOTE: The integer values of these constants must match the proto enum constants in - // {@link ScoringSpecProto.Order.Code } - @IntDef(prefix = {"ORDER_"}, value = { - ORDER_DESCENDING, - ORDER_ASCENDING - }) - @Retention(RetentionPolicy.SOURCE) - public @interface OrderCode {} - - /** Search results will be returned in a descending order. */ - public static final int ORDER_DESCENDING = 0; - /** Search results will be returned in an ascending order. */ - public static final int ORDER_ASCENDING = 1; - - /** Builder for {@link SearchSpec objects}. */ - public static final class Builder { - - private final SearchSpecProto.Builder mSearchSpecBuilder = SearchSpecProto.newBuilder(); - private final ResultSpecProto.Builder mResultSpecBuilder = ResultSpecProto.newBuilder(); - private final ScoringSpecProto.Builder mScoringSpecBuilder = ScoringSpecProto.newBuilder(); - private final ResultSpecProto.SnippetSpecProto.Builder mSnippetSpecBuilder = - ResultSpecProto.SnippetSpecProto.newBuilder(); - - private Builder() { - } - - /** - * Indicates how the query terms should match {@link TermMatchTypeCode} in the index. - */ - @NonNull - public Builder setTermMatchType(@TermMatchTypeCode int termMatchTypeCode) { - TermMatchType.Code termMatchTypeCodeProto = - TermMatchType.Code.forNumber(termMatchTypeCode); - if (termMatchTypeCodeProto == null) { - throw new IllegalArgumentException("Invalid term match type: " - + termMatchTypeCode); - } - mSearchSpecBuilder.setTermMatchType(termMatchTypeCodeProto); - return this; - } - - /** - * Adds a Schema type filter to {@link SearchSpec} Entry. Only search for documents that - * have the specified schema types. - * <p>If unset, the query will search over all schema types. - */ - @NonNull - public Builder setSchemaTypes(@NonNull String... schemaTypes) { - for (String schemaType : schemaTypes) { - mSearchSpecBuilder.addSchemaTypeFilters(schemaType); - } - return this; - } - - /** Sets the maximum number of results to retrieve from the query */ - @NonNull - public SearchSpec.Builder setNumToRetrieve(int numToRetrieve) { - mResultSpecBuilder.setNumToRetrieve(numToRetrieve); - return this; - } - - /** Sets ranking strategy for AppSearch results.*/ - @NonNull - public Builder setRankingStrategy(@RankingStrategyCode int rankingStrategy) { - ScoringSpecProto.RankingStrategy.Code rankingStrategyCodeProto = - ScoringSpecProto.RankingStrategy.Code.forNumber(rankingStrategy); - if (rankingStrategyCodeProto == null) { - throw new IllegalArgumentException("Invalid result ranking strategy: " - + rankingStrategyCodeProto); - } - mScoringSpecBuilder.setRankBy(rankingStrategyCodeProto); - return this; - } - - /** - * Indicates the order of returned search results, the default is DESC, meaning that results - * with higher scores come first. - * <p>This order field will be ignored if RankingStrategy = {@code RANKING_STRATEGY_NONE}. - */ - @NonNull - public Builder setOrder(@OrderCode int order) { - ScoringSpecProto.Order.Code orderCodeProto = - ScoringSpecProto.Order.Code.forNumber(order); - if (orderCodeProto == null) { - throw new IllegalArgumentException("Invalid result ranking order: " - + orderCodeProto); - } - mScoringSpecBuilder.setOrderBy(orderCodeProto); - return this; - } - - /** - * Only the first {@code numToSnippet} documents based on the ranking strategy - * will have snippet information provided. - * <p>If set to 0 (default), snippeting is disabled and - * {@link SearchResults.Result#getMatchInfo} will return {@code null} for that result. - */ - @NonNull - public SearchSpec.Builder setNumToSnippet(int numToSnippet) { - mSnippetSpecBuilder.setNumToSnippet(numToSnippet); - return this; - } - - /** - * Only the first {@code numMatchesPerProperty} matches for a every property of - * {@link AppSearchDocument} will contain snippet information. - * <p>If set to 0, snippeting is disabled and {@link SearchResults.Result#getMatchInfo} - * will return {@code null} for that result. - */ - @NonNull - public SearchSpec.Builder setNumMatchesPerProperty(int numMatchesPerProperty) { - mSnippetSpecBuilder.setNumMatchesPerProperty(numMatchesPerProperty); - return this; - } - - /** - * Sets {@code maxSnippetSize}, the maximum snippet size. Snippet windows start at - * {@code maxSnippetSize/2} bytes before the middle of the matching token and end at - * {@code maxSnippetSize/2} bytes after the middle of the matching token. It respects - * token boundaries, therefore the returned window may be smaller than requested. - * <p> Setting {@code maxSnippetSize} to 0 will disable windowing and an empty string will - * be returned. If matches enabled is also set to false, then snippeting is disabled. - * <p>Ex. {@code maxSnippetSize} = 16. "foo bar baz bat rat" with a query of "baz" will - * return a window of "bar baz bat" which is only 11 bytes long. - */ - @NonNull - public SearchSpec.Builder setMaxSnippetSize(int maxSnippetSize) { - mSnippetSpecBuilder.setMaxWindowBytes(maxSnippetSize); - return this; - } - - /** - * Constructs a new {@link SearchSpec} from the contents of this builder. - * - * <p>After calling this method, the builder must no longer be used. - */ - @NonNull - public SearchSpec build() { - if (mSearchSpecBuilder.getTermMatchType() == TermMatchType.Code.UNKNOWN) { - throw new IllegalSearchSpecException("Missing termMatchType field."); - } - mResultSpecBuilder.setSnippetSpec(mSnippetSpecBuilder); - return new SearchSpec(mSearchSpecBuilder.build(), mResultSpecBuilder.build(), - mScoringSpecBuilder.build()); - } - } -} diff --git a/apex/appsearch/service/Android.bp b/apex/appsearch/service/Android.bp deleted file mode 100644 index 04f385e8c6f6..000000000000 --- a/apex/appsearch/service/Android.bp +++ /dev/null @@ -1,24 +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. -java_library { - name: "service-appsearch", - installable: true, - srcs: ["java/**/*.java"], - libs: [ - "framework", - "framework-appsearch", - "services.core", - ], - apex_available: ["com.android.appsearch"], -} diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java deleted file mode 100644 index 6293ee7059e5..000000000000 --- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.server.appsearch; - -import android.annotation.NonNull; -import android.app.appsearch.AppSearchBatchResult; -import android.app.appsearch.IAppSearchManager; -import android.content.Context; -import android.os.Binder; -import android.os.UserHandle; - -import com.android.internal.infra.AndroidFuture; -import com.android.internal.util.Preconditions; -import com.android.server.SystemService; -import com.android.server.appsearch.impl.AppSearchImpl; -import com.android.server.appsearch.impl.FakeIcing; -import com.android.server.appsearch.impl.ImplInstanceManager; - -import com.google.android.icing.proto.DocumentProto; -import com.google.android.icing.proto.SchemaProto; -import com.google.android.icing.proto.SearchResultProto; -import com.google.android.icing.proto.SearchSpecProto; -import com.google.android.icing.protobuf.InvalidProtocolBufferException; - -import java.util.List; - -/** - * TODO(b/142567528): add comments when implement this class - */ -public class AppSearchManagerService extends SystemService { - - public AppSearchManagerService(Context context) { - super(context); - mFakeIcing = new FakeIcing(); - } - - private final FakeIcing mFakeIcing; - - @Override - public void onStart() { - publishBinderService(Context.APP_SEARCH_SERVICE, new Stub()); - } - - private class Stub extends IAppSearchManager.Stub { - @Override - public void setSchema(byte[] schemaBytes, boolean forceOverride, AndroidFuture callback) { - Preconditions.checkNotNull(schemaBytes); - Preconditions.checkNotNull(callback); - int callingUid = Binder.getCallingUidOrThrow(); - int callingUserId = UserHandle.getUserId(callingUid); - long callingIdentity = Binder.clearCallingIdentity(); - try { - SchemaProto schema = SchemaProto.parseFrom(schemaBytes); - AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); - impl.setSchema(callingUid, schema, forceOverride); - callback.complete(null); - } catch (Throwable t) { - callback.completeExceptionally(t); - } finally { - Binder.restoreCallingIdentity(callingIdentity); - } - } - - @Override - public void putDocuments( - List documentsBytes, AndroidFuture<AppSearchBatchResult> callback) { - Preconditions.checkNotNull(documentsBytes); - Preconditions.checkNotNull(callback); - int callingUid = Binder.getCallingUidOrThrow(); - int callingUserId = UserHandle.getUserId(callingUid); - long callingIdentity = Binder.clearCallingIdentity(); - try { - AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); - AppSearchBatchResult.Builder<String, Void> resultBuilder = - AppSearchBatchResult.newBuilder(); - for (int i = 0; i < documentsBytes.size(); i++) { - byte[] documentBytes = (byte[]) documentsBytes.get(i); - DocumentProto document = DocumentProto.parseFrom(documentBytes); - try { - impl.putDocument(callingUid, document); - resultBuilder.setSuccess(document.getUri(), /*value=*/ null); - } catch (Throwable t) { - resultBuilder.setFailure(document.getUri(), t); - } - } - callback.complete(resultBuilder.build()); - } catch (Throwable t) { - callback.completeExceptionally(t); - } finally { - Binder.restoreCallingIdentity(callingIdentity); - } - } - // TODO(sidchhabra):Init FakeIcing properly. - // TODO(sidchhabra): Do this in a threadpool. - @Override - public void query(@NonNull byte[] searchSpec, @NonNull byte[] resultSpec, - @NonNull byte[] scoringSpec, AndroidFuture callback) { - Preconditions.checkNotNull(searchSpec); - Preconditions.checkNotNull(resultSpec); - Preconditions.checkNotNull(scoringSpec); - SearchSpecProto searchSpecProto = null; - try { - searchSpecProto = SearchSpecProto.parseFrom(searchSpec); - } catch (InvalidProtocolBufferException e) { - throw new RuntimeException(e); - } - SearchResultProto searchResults = - mFakeIcing.query(searchSpecProto.getQuery()); - callback.complete(searchResults.toByteArray()); - } - } -} diff --git a/apex/appsearch/service/java/com/android/server/appsearch/TEST_MAPPING b/apex/appsearch/service/java/com/android/server/appsearch/TEST_MAPPING deleted file mode 100644 index ca5b8841ea49..000000000000 --- a/apex/appsearch/service/java/com/android/server/appsearch/TEST_MAPPING +++ /dev/null @@ -1,23 +0,0 @@ -{ - "presubmit": [ - { - "name": "CtsAppSearchTestCases" - }, - { - "name": "FrameworksServicesTests", - "options": [ - { - "include-filter": "com.android.server.appsearch" - } - ] - }, - { - "name": "FrameworksCoreTests", - "options": [ - { - "include-filter": "android.app.appsearch" - } - ] - } - ] -} diff --git a/apex/appsearch/service/java/com/android/server/appsearch/impl/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/impl/AppSearchImpl.java deleted file mode 100644 index 04b4b1427328..000000000000 --- a/apex/appsearch/service/java/com/android/server/appsearch/impl/AppSearchImpl.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.appsearch.impl; - -import android.annotation.NonNull; -import android.annotation.UserIdInt; -import android.content.Context; - -import com.android.internal.annotations.VisibleForTesting; - -import com.google.android.icing.proto.DocumentProto; -import com.google.android.icing.proto.PropertyConfigProto; -import com.google.android.icing.proto.PropertyProto; -import com.google.android.icing.proto.SchemaProto; -import com.google.android.icing.proto.SchemaTypeConfigProto; - -/** - * Manages interaction with {@link FakeIcing} and other components to implement AppSearch - * functionality. - */ -public final class AppSearchImpl { - private final Context mContext; - private final @UserIdInt int mUserId; - private final FakeIcing mFakeIcing = new FakeIcing(); - - AppSearchImpl(@NonNull Context context, @UserIdInt int userId) { - mContext = context; - mUserId = userId; - } - - /** - * Updates the AppSearch schema for this app. - * - * @param callingUid The uid of the app calling AppSearch. - * @param origSchema The schema to set for this app. - * @param forceOverride Whether to force-apply the schema even if it is incompatible. Documents - * which do not comply with the new schema will be deleted. - */ - public void setSchema(int callingUid, @NonNull SchemaProto origSchema, boolean forceOverride) { - // Rewrite schema type names to include the calling app's package and uid. - String typePrefix = getTypePrefix(callingUid); - SchemaProto.Builder schemaBuilder = origSchema.toBuilder(); - rewriteSchemaTypes(typePrefix, schemaBuilder); - - // TODO(b/145635424): Save in schema type map - // TODO(b/145635424): Apply the schema to Icing and report results - } - - /** - * Rewrites all types mentioned in the given {@code schemaBuilder} to prepend - * {@code typePrefix}. - * - * @param typePrefix The prefix to add - * @param schemaBuilder The schema to mutate - */ - @VisibleForTesting - void rewriteSchemaTypes( - @NonNull String typePrefix, @NonNull SchemaProto.Builder schemaBuilder) { - for (int typeIdx = 0; typeIdx < schemaBuilder.getTypesCount(); typeIdx++) { - SchemaTypeConfigProto.Builder typeConfigBuilder = - schemaBuilder.getTypes(typeIdx).toBuilder(); - - // Rewrite SchemaProto.types.schema_type - String newSchemaType = typePrefix + typeConfigBuilder.getSchemaType(); - typeConfigBuilder.setSchemaType(newSchemaType); - - // Rewrite SchemaProto.types.properties.schema_type - for (int propertyIdx = 0; - propertyIdx < typeConfigBuilder.getPropertiesCount(); - propertyIdx++) { - PropertyConfigProto.Builder propertyConfigBuilder = - typeConfigBuilder.getProperties(propertyIdx).toBuilder(); - if (!propertyConfigBuilder.getSchemaType().isEmpty()) { - String newPropertySchemaType = - typePrefix + propertyConfigBuilder.getSchemaType(); - propertyConfigBuilder.setSchemaType(newPropertySchemaType); - typeConfigBuilder.setProperties(propertyIdx, propertyConfigBuilder); - } - } - - schemaBuilder.setTypes(typeIdx, typeConfigBuilder); - } - } - - /** - * Adds a document to the AppSearch index. - * - * @param callingUid The uid of the app calling AppSearch. - * @param origDocument The document to index. - */ - public void putDocument(int callingUid, @NonNull DocumentProto origDocument) { - // Rewrite the type names to include the app's prefix - String typePrefix = getTypePrefix(callingUid); - DocumentProto.Builder documentBuilder = origDocument.toBuilder(); - rewriteDocumentTypes(typePrefix, documentBuilder); - mFakeIcing.put(documentBuilder.build()); - } - - /** - * Rewrites all types mentioned anywhere in {@code documentBuilder} to prepend - * {@code typePrefix}. - * - * @param typePrefix The prefix to add - * @param documentBuilder The document to mutate - */ - @VisibleForTesting - void rewriteDocumentTypes( - @NonNull String typePrefix, - @NonNull DocumentProto.Builder documentBuilder) { - // Rewrite the type name to include the app's prefix - String newSchema = typePrefix + documentBuilder.getSchema(); - documentBuilder.setSchema(newSchema); - - // Add namespace. If we ever allow users to set their own namespaces, this will have - // to change to prepend the prefix instead of setting the whole namespace. We will also have - // to store the namespaces in a map similar to the type map so we can rewrite queries with - // empty namespaces. - documentBuilder.setNamespace(typePrefix); - - // Recurse into derived documents - for (int propertyIdx = 0; - propertyIdx < documentBuilder.getPropertiesCount(); - propertyIdx++) { - int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount(); - if (documentCount > 0) { - PropertyProto.Builder propertyBuilder = - documentBuilder.getProperties(propertyIdx).toBuilder(); - for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) { - DocumentProto.Builder derivedDocumentBuilder = - propertyBuilder.getDocumentValues(documentIdx).toBuilder(); - rewriteDocumentTypes(typePrefix, derivedDocumentBuilder); - propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder); - } - documentBuilder.setProperties(propertyIdx, propertyBuilder); - } - } - } - - /** - * Returns a type prefix in a format like {@code com.example.package@1000/} or - * {@code com.example.sharedname:5678@1000/}. - */ - @NonNull - private String getTypePrefix(int callingUid) { - // For regular apps, this call will return the package name. If callingUid is an - // android:sharedUserId, this value may be another type of name and have a :uid suffix. - String callingUidName = mContext.getPackageManager().getNameForUid(callingUid); - if (callingUidName == null) { - // Not sure how this is possible --- maybe app was uninstalled? - throw new IllegalStateException("Failed to look up package name for uid " + callingUid); - } - return callingUidName + "@" + mUserId + "/"; - } -} diff --git a/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java b/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java deleted file mode 100644 index d07ef4bc3bf5..000000000000 --- a/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.appsearch.impl; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.SparseArray; - -import com.google.android.icing.proto.DocumentProto; -import com.google.android.icing.proto.PropertyProto; -import com.google.android.icing.proto.SearchResultProto; -import com.google.android.icing.proto.StatusProto; - -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Fake in-memory implementation of the Icing key-value store and reverse index. - * <p> - * Currently, only queries by single exact term are supported. There is no support for persistence, - * namespaces, i18n tokenization, or schema. - */ -public class FakeIcing { - private final AtomicInteger mNextDocId = new AtomicInteger(); - private final Map<String, Integer> mUriToDocIdMap = new ArrayMap<>(); - /** Array of Documents where index into the array is the docId. */ - private final SparseArray<DocumentProto> mDocStore = new SparseArray<>(); - /** Map of term to posting-list (the set of DocIds containing that term). */ - private final Map<String, Set<Integer>> mIndex = new ArrayMap<>(); - - /** - * Inserts a document into the index. - * - * @param document The document to insert. - */ - public void put(@NonNull DocumentProto document) { - String uri = document.getUri(); - - // Update mDocIdMap - Integer docId = mUriToDocIdMap.get(uri); - if (docId != null) { - // Delete the old doc - mDocStore.remove(docId); - } - - // Allocate a new docId - docId = mNextDocId.getAndIncrement(); - mUriToDocIdMap.put(uri, docId); - - // Update mDocStore - mDocStore.put(docId, document); - - // Update mIndex - indexDocument(docId, document); - } - - /** - * Retrieves a document from the index. - * - * @param uri The URI of the document to retrieve. - * @return The body of the document, or {@code null} if no such document exists. - */ - @Nullable - public DocumentProto get(@NonNull String uri) { - Integer docId = mUriToDocIdMap.get(uri); - if (docId == null) { - return null; - } - return mDocStore.get(docId); - } - - /** - * Returns documents containing the given term. - * - * @param term A single exact term to look up in the index. - * @return A {@link SearchResultProto} containing the matching documents, which may have no - * results if no documents match. - */ - @NonNull - public SearchResultProto query(@NonNull String term) { - String normTerm = normalizeString(term); - Set<Integer> docIds = mIndex.get(normTerm); - SearchResultProto.Builder results = SearchResultProto.newBuilder() - .setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.OK)); - if (docIds == null || docIds.isEmpty()) { - return results.build(); - } - - for (int docId : docIds) { - DocumentProto document = mDocStore.get(docId); - if (document != null) { - results.addResults( - SearchResultProto.ResultProto.newBuilder().setDocument(document)); - } - } - return results.build(); - } - - /** - * Deletes a document by its URI. - * - * @param uri The URI of the document to be deleted. - */ - public void delete(@NonNull String uri) { - // Update mDocIdMap - Integer docId = mUriToDocIdMap.get(uri); - if (docId != null) { - // Delete the old doc - mDocStore.remove(docId); - mUriToDocIdMap.remove(uri); - } - } - - private void indexDocument(int docId, DocumentProto document) { - for (PropertyProto property : document.getPropertiesList()) { - for (String stringValue : property.getStringValuesList()) { - String[] words = normalizeString(stringValue).split("\\s+"); - for (String word : words) { - indexTerm(docId, word); - } - } - for (Long longValue : property.getInt64ValuesList()) { - indexTerm(docId, longValue.toString()); - } - for (Double doubleValue : property.getDoubleValuesList()) { - indexTerm(docId, doubleValue.toString()); - } - for (Boolean booleanValue : property.getBooleanValuesList()) { - indexTerm(docId, booleanValue.toString()); - } - // Intentionally skipping bytes values - for (DocumentProto documentValue : property.getDocumentValuesList()) { - indexDocument(docId, documentValue); - } - } - } - - private void indexTerm(int docId, String term) { - Set<Integer> postingList = mIndex.get(term); - if (postingList == null) { - postingList = new ArraySet<>(); - mIndex.put(term, postingList); - } - postingList.add(docId); - } - - /** Strips out punctuation and converts to lowercase. */ - private static String normalizeString(String input) { - return input.replaceAll("\\p{P}", "").toLowerCase(Locale.getDefault()); - } -} diff --git a/apex/appsearch/service/java/com/android/server/appsearch/impl/ImplInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/impl/ImplInstanceManager.java deleted file mode 100644 index 395e30e89dc0..000000000000 --- a/apex/appsearch/service/java/com/android/server/appsearch/impl/ImplInstanceManager.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.appsearch.impl; - -import android.annotation.NonNull; -import android.annotation.UserIdInt; -import android.content.Context; -import android.util.SparseArray; - -/** - * Manages the lifecycle of instances of {@link AppSearchImpl}. - * - * <p>These instances are managed per unique device-user. - */ -public final class ImplInstanceManager { - private static final SparseArray<AppSearchImpl> sInstances = new SparseArray<>(); - - /** - * Gets an instance of AppSearchImpl for the given user. - * - * <p>If no AppSearchImpl instance exists for this user, Icing will be initialized and one will - * be created. - * - * @param context The Android context - * @param userId The multi-user userId of the device user calling AppSearch - * @return An initialized {@link AppSearchImpl} for this user - */ - @NonNull - public static AppSearchImpl getInstance(@NonNull Context context, @UserIdInt int userId) { - AppSearchImpl instance = sInstances.get(userId); - if (instance == null) { - synchronized (ImplInstanceManager.class) { - instance = sInstances.get(userId); - if (instance == null) { - instance = new AppSearchImpl(context, userId); - sInstances.put(userId, instance); - } - } - } - return instance; - } -} diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java index 05c661127eab..49adaa8efd4b 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java @@ -939,6 +939,12 @@ public class BlobStoreManagerService extends SystemService { } } + void runIdleMaintenance() { + synchronized (mBlobsLock) { + handleIdleMaintenanceLocked(); + } + } + @GuardedBy("mBlobsLock") private void dumpSessionsLocked(IndentingPrintWriter fout, DumpArgs dumpArgs) { for (int i = 0, userCount = mSessions.size(); i < userCount; ++i) { @@ -1408,9 +1414,7 @@ public class BlobStoreManagerService extends SystemService { private class LocalService extends BlobStoreManagerInternal { @Override public void onIdleMaintenance() { - synchronized (mBlobsLock) { - handleIdleMaintenanceLocked(); - } + runIdleMaintenance(); } } diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java index d58294b8b941..72af323e9d5f 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java @@ -44,6 +44,8 @@ class BlobStoreManagerShellCommand extends ShellCommand { return runClearAllBlobs(pw); case "delete-blob": return runDeleteBlob(pw); + case "idle-maintenance": + return runIdleMaintenance(pw); default: return handleDefaultCommands(cmd); } @@ -84,6 +86,11 @@ class BlobStoreManagerShellCommand extends ShellCommand { return 0; } + private int runIdleMaintenance(PrintWriter pw) { + mService.runIdleMaintenance(); + return 0; + } + @Override public void onHelp() { final PrintWriter pw = getOutPrintWriter(); @@ -112,6 +119,8 @@ class BlobStoreManagerShellCommand extends ShellCommand { pw.println(" --expiry: Expiry time of the blob to delete, in milliseconds."); pw.println(" --label: Label of the blob to delete."); pw.println(" --tag: Tag of the blob to delete."); + pw.println("idle-maintenance"); + pw.println(" Run idle maintenance which takes care of removing stale data."); pw.println(); } diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java index cc4044ed46b9..62701e52781d 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java @@ -347,12 +347,12 @@ class BlobStoreSession extends IBlobStoreSession.Stub { @Override public void close() { - closeSession(STATE_CLOSED); + closeSession(STATE_CLOSED, false /* sendCallback */); } @Override public void abandon() { - closeSession(STATE_ABANDONED); + closeSession(STATE_ABANDONED, true /* sendCallback */); } @Override @@ -360,11 +360,11 @@ class BlobStoreSession extends IBlobStoreSession.Stub { synchronized (mSessionLock) { mBlobCommitCallback = callback; - closeSession(STATE_COMMITTED); + closeSession(STATE_COMMITTED, true /* sendCallback */); } } - private void closeSession(int state) { + private void closeSession(int state, boolean sendCallback) { assertCallerIsOwner(); synchronized (mSessionLock) { if (mState != STATE_OPENED) { @@ -381,7 +381,9 @@ class BlobStoreSession extends IBlobStoreSession.Stub { mState = state; revokeAllFdsLocked(); - mListener.onStateChanged(this); + if (sendCallback) { + mListener.onStateChanged(this); + } } } @@ -457,6 +459,10 @@ class BlobStoreSession extends IBlobStoreSession.Stub { return "<abandoned>"; case STATE_COMMITTED: return "<committed>"; + case STATE_VERIFIED_VALID: + return "<verified_valid>"; + case STATE_VERIFIED_INVALID: + return "<verified_invalid>"; default: Slog.wtf(TAG, "Unknown state: " + state); return "<unknown>"; diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp index 1bd770a1ab99..8185bb036b22 100644 --- a/apex/statsd/framework/Android.bp +++ b/apex/statsd/framework/Android.bp @@ -43,6 +43,7 @@ filegroup { ], visibility: [ "//frameworks/base", // For the "global" stubs. + "//frameworks/base/apex/statsd:__subpackages__", ], } @@ -74,8 +75,6 @@ java_library { hostdex: true, // for hiddenapi check visibility: [ "//frameworks/base/apex/statsd:__subpackages__", - // TODO(b/149928788): Remove when tests are moved. - "//frameworks/base/core/tests/coretests:__pkg__", ], apex_available: [ "com.android.os.statsd", @@ -164,3 +163,26 @@ java_library { "//frameworks/opt/net/wifi/service" // wifi service ] } + +android_test { + name: "FrameworkStatsdTest", + platform_apis: true, + srcs: [ + // TODO(b/147705194): Use framework-statsd as a lib dependency instead. + ":framework-statsd-sources", + "test/**/*.java", + ], + manifest: "test/AndroidManifest.xml", + static_libs: [ + "androidx.test.rules", + "truth-prebuilt", + ], + libs: [ + "android.test.runner.stubs", + "android.test.base.stubs", + ], + test_suites: [ + "device-tests", + ], +} + diff --git a/apex/statsd/framework/test/AndroidManifest.xml b/apex/statsd/framework/test/AndroidManifest.xml new file mode 100644 index 000000000000..8f89d2332b12 --- /dev/null +++ b/apex/statsd/framework/test/AndroidManifest.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2020 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.os.statsd.framework.test" + > + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.os.statsd.framework.test" + android:label="Framework Statsd Tests" /> + +</manifest> diff --git a/apex/statsd/framework/test/TEST_MAPPING b/apex/statsd/framework/test/TEST_MAPPING new file mode 100644 index 000000000000..f38795819189 --- /dev/null +++ b/apex/statsd/framework/test/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit" : [ + { + "name" : "FrameworkStatsdTest" + } + ] +} diff --git a/core/tests/coretests/src/android/app/PullAtomMetadataTest.java b/apex/statsd/framework/test/src/android/app/PullAtomMetadataTest.java index 0ae613400b18..0ae613400b18 100644 --- a/core/tests/coretests/src/android/app/PullAtomMetadataTest.java +++ b/apex/statsd/framework/test/src/android/app/PullAtomMetadataTest.java diff --git a/core/tests/coretests/src/android/util/StatsEventTest.java b/apex/statsd/framework/test/src/android/util/StatsEventTest.java index ac25e2734ac9..ac25e2734ac9 100644 --- a/core/tests/coretests/src/android/util/StatsEventTest.java +++ b/apex/statsd/framework/test/src/android/util/StatsEventTest.java diff --git a/api/current.txt b/api/current.txt index 02b87342329c..563665fb519a 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4572,14 +4572,17 @@ package android.app { field public static final int REASON_ANR = 6; // 0x6 field public static final int REASON_CRASH = 4; // 0x4 field public static final int REASON_CRASH_NATIVE = 5; // 0x5 + field public static final int REASON_DEPENDENCY_DIED = 12; // 0xc field public static final int REASON_EXCESSIVE_RESOURCE_USAGE = 9; // 0x9 field public static final int REASON_EXIT_SELF = 1; // 0x1 field public static final int REASON_INITIALIZATION_FAILURE = 7; // 0x7 field public static final int REASON_LOW_MEMORY = 3; // 0x3 - field public static final int REASON_OTHER = 10; // 0xa + field public static final int REASON_OTHER = 13; // 0xd field public static final int REASON_PERMISSION_CHANGE = 8; // 0x8 field public static final int REASON_SIGNALED = 2; // 0x2 field public static final int REASON_UNKNOWN = 0; // 0x0 + field public static final int REASON_USER_REQUESTED = 10; // 0xa + field public static final int REASON_USER_STOPPED = 11; // 0xb } public final class AsyncNotedAppOp implements android.os.Parcelable { @@ -42784,7 +42787,7 @@ package android.security.keystore { method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean); method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...); method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean); - method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationParameters(@IntRange(from=0xffffffff) int, int); + method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationParameters(@IntRange(from=0) int, int); method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean); method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean); method @Deprecated @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(@IntRange(from=0xffffffff) int); @@ -42902,7 +42905,7 @@ package android.security.keystore { method @NonNull public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean); method @NonNull public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...); method @NonNull public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean); - method @NonNull public android.security.keystore.KeyProtection.Builder setUserAuthenticationParameters(@IntRange(from=0xffffffff) int, int); + method @NonNull public android.security.keystore.KeyProtection.Builder setUserAuthenticationParameters(@IntRange(from=0) int, int); method @NonNull public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean); method @NonNull public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean); method @Deprecated @NonNull public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(@IntRange(from=0xffffffff) int); diff --git a/api/system-current.txt b/api/system-current.txt index 71877089aec4..c51fab44cbf3 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -921,14 +921,6 @@ package android.app.admin { } -package android.app.appsearch { - - public class AppSearchManagerFrameworkInitializer { - method public static void initialize(); - } - -} - package android.app.assist { public static class AssistStructure.ViewNode { @@ -8140,8 +8132,8 @@ package android.os { method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportFullWifiLockReleasedFromSource(@NonNull android.os.WorkSource); method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiBatchedScanStartedFromSource(@NonNull android.os.WorkSource, @IntRange(from=0) int); method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiBatchedScanStoppedFromSource(@NonNull android.os.WorkSource); - method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastDisabled(int); - method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastEnabled(int); + method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastDisabled(@NonNull android.os.WorkSource); + method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastEnabled(@NonNull android.os.WorkSource); method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiOff(); method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiOn(); method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiRssiChanged(@IntRange(from=0xffffff81, to=0) int); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index a53fc3508001..2399e374540d 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -16,10 +16,6 @@ package android.app; -import static android.util.StatsLogInternal.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__DEFAULT; -import static android.util.StatsLogInternal.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__RARELY_USED; -import static android.util.StatsLogInternal.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__UNIFORM; - import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.IntDef; @@ -74,6 +70,7 @@ import com.android.internal.os.RuntimeInit; import com.android.internal.os.ZygoteInit; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DataClass; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.Parcelling; import com.android.internal.util.Preconditions; @@ -666,15 +663,31 @@ public class AppOpsManager { } } + // These constants are redefined here to work around a metalava limitation/bug where + // @IntDef is not able to see @hide symbols when they are hidden via package hiding: + // frameworks/base/core/java/com/android/internal/package.html + + /** @hide */ + public static final int SAMPLING_STRATEGY_DEFAULT = + FrameworkStatsLog.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__DEFAULT; + + /** @hide */ + public static final int SAMPLING_STRATEGY_UNIFORM = + FrameworkStatsLog.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__UNIFORM; + + /** @hide */ + public static final int SAMPLING_STRATEGY_RARELY_USED = + FrameworkStatsLog.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__RARELY_USED; + /** * Strategies used for message sampling * @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = {"RUNTIME_APP_OPS_ACCESS__SAMPLING_STRATEGY__"}, value = { - RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__DEFAULT, - RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__UNIFORM, - RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__RARELY_USED + @IntDef(prefix = {"SAMPLING_STRATEGY_"}, value = { + SAMPLING_STRATEGY_DEFAULT, + SAMPLING_STRATEGY_UNIFORM, + SAMPLING_STRATEGY_RARELY_USED }) public @interface SamplingStrategy {} diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java index c55453e94960..5df3257f2444 100644 --- a/core/java/android/app/ApplicationExitInfo.java +++ b/core/java/android/app/ApplicationExitInfo.java @@ -16,6 +16,7 @@ package android.app; +import android.annotation.CurrentTimeMillisLong; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -121,11 +122,30 @@ public final class ApplicationExitInfo implements Parcelable { public static final int REASON_EXCESSIVE_RESOURCE_USAGE = 9; /** - * Application process was killed by the system for various other reasons, - * for example, the application package got disabled by the user; - * {@link #getDescription} will specify the cause given by the system. + * Application process was killed because of the user request, for example, + * user clicked the "Force stop" button of the application in the Settings, + * or removed the application away from Recents. */ - public static final int REASON_OTHER = 10; + public static final int REASON_USER_REQUESTED = 10; + + /** + * Application process was killed, because the user it is running as on devices + * with mutlple users, was stopped. + */ + public static final int REASON_USER_STOPPED = 11; + + /** + * Application process was killed because its dependency was going away, for example, + * a stable content provider connection's client will be killed if the provider is killed. + */ + public static final int REASON_DEPENDENCY_DIED = 12; + + /** + * Application process was killed by the system for various other reasons which are + * not by problems in apps and not actionable by apps, for example, the system just + * finished updates; {@link #getDescription} will specify the cause given by the system. + */ + public static final int REASON_OTHER = 13; /** * Application process kills subreason is unknown. @@ -202,6 +222,105 @@ public final class ApplicationExitInfo implements Parcelable { public static final int SUBREASON_EXCESSIVE_CPU = 7; /** + * System update has done (so the system update process should be killed); + * this would be set only when the reason is {@link #REASON_OTHER}. + * + * For internal use only. + * @hide + */ + public static final int SUBREASON_SYSTEM_UPDATE_DONE = 8; + + /** + * Kill all foreground services, for now it only occurs when enabling the quiet + * mode for the managed profile; + * this would be set only when the reason is {@link #REASON_OTHER}. + * + * For internal use only. + * @hide + */ + public static final int SUBREASON_KILL_ALL_FG = 9; + + /** + * All background processes except certain ones were killed, for now it only occurs + * when the density of the default display is changed; + * this would be set only when the reason is {@link #REASON_OTHER}. + * + * For internal use only. + * @hide + */ + public static final int SUBREASON_KILL_ALL_BG_EXCEPT = 10; + + /** + * The process associated with the UID was explicitly killed, for example, + * it could be because of platform compatibility overrides; + * this would be set only when the reason is {@link #REASON_OTHER}. + * + * For internal use only. + * @hide + */ + public static final int SUBREASON_KILL_UID = 11; + + /** + * The process was explicitly killed with its PID, typically because of + * the low memory for surfaces; + * this would be set only when the reason is {@link #REASON_OTHER}. + * + * For internal use only. + * @hide + */ + public static final int SUBREASON_KILL_PID = 12; + + /** + * The start of the process was invalid; + * this would be set only when the reason is {@link #REASON_OTHER}. + * + * For internal use only. + * @hide + */ + public static final int SUBREASON_INVALID_START = 13; + + /** + * The process was killed because it's in an invalid state, typically + * it's triggered from SHELL; + * this would be set only when the reason is {@link #REASON_OTHER}. + * + * For internal use only. + * @hide + */ + public static final int SUBREASON_INVALID_STATE = 14; + + /** + * The process was killed when it's imperceptible to user, because it was + * in a bad state; + * this would be set only when the reason is {@link #REASON_OTHER}. + * + * For internal use only. + * @hide + */ + public static final int SUBREASON_IMPERCEPTIBLE = 15; + + /** + * The process was killed because it's being moved out from LRU list; + * this would be set only when the reason is {@link #REASON_OTHER}. + * + * For internal use only. + * @hide + */ + public static final int SUBREASON_REMOVE_LRU = 16; + + /** + * The process was killed because it's isolated and was in a cached state; + * this would be set only when the reason is {@link #REASON_OTHER}. + * + * For internal use only. + * @hide + */ + public static final int SUBREASON_ISOLATED_NOT_NEEDED = 17; + + // If there is any OEM code which involves additional app kill reasons, it should + // be categorized in {@link #REASON_OTHER}, with subreason code starting from 1000. + + /** * @see {@link #getPid} */ private int mPid; @@ -254,7 +373,7 @@ public final class ApplicationExitInfo implements Parcelable { /** * @see {@link #getTimestamp} */ - private long mTimestamp; + private @CurrentTimeMillisLong long mTimestamp; /** * @see {@link #getDescription} @@ -293,6 +412,9 @@ public final class ApplicationExitInfo implements Parcelable { REASON_INITIALIZATION_FAILURE, REASON_PERMISSION_CHANGE, REASON_EXCESSIVE_RESOURCE_USAGE, + REASON_USER_REQUESTED, + REASON_USER_STOPPED, + REASON_DEPENDENCY_DIED, REASON_OTHER, }) @Retention(RetentionPolicy.SOURCE) @@ -308,6 +430,16 @@ public final class ApplicationExitInfo implements Parcelable { SUBREASON_LARGE_CACHED, SUBREASON_MEMORY_PRESSURE, SUBREASON_EXCESSIVE_CPU, + SUBREASON_SYSTEM_UPDATE_DONE, + SUBREASON_KILL_ALL_FG, + SUBREASON_KILL_ALL_BG_EXCEPT, + SUBREASON_KILL_UID, + SUBREASON_KILL_PID, + SUBREASON_INVALID_START, + SUBREASON_INVALID_STATE, + SUBREASON_IMPERCEPTIBLE, + SUBREASON_REMOVE_LRU, + SUBREASON_ISOLATED_NOT_NEEDED, }) @Retention(RetentionPolicy.SOURCE) public @interface SubReason {} @@ -403,7 +535,7 @@ public final class ApplicationExitInfo implements Parcelable { * The timestamp of the process's death, in milliseconds since the epoch, * as returned by {@link System#currentTimeMillis System.currentTimeMillis()}. */ - public long getTimestamp() { + public @CurrentTimeMillisLong long getTimestamp() { return mTimestamp; } @@ -564,7 +696,7 @@ public final class ApplicationExitInfo implements Parcelable { * * @hide */ - public void setTimestamp(final long timestamp) { + public void setTimestamp(final @CurrentTimeMillisLong long timestamp) { mTimestamp = timestamp; } @@ -656,6 +788,8 @@ public final class ApplicationExitInfo implements Parcelable { mRss = other.mRss; mTimestamp = other.mTimestamp; mDescription = other.mDescription; + mPackageName = other.mPackageName; + mPackageList = other.mPackageList; } private ApplicationExitInfo(@NonNull Parcel in) { @@ -748,6 +882,12 @@ public final class ApplicationExitInfo implements Parcelable { return "PERMISSION CHANGE"; case REASON_EXCESSIVE_RESOURCE_USAGE: return "EXCESSIVE RESOURCE USAGE"; + case REASON_USER_REQUESTED: + return "USER REQUESTED"; + case REASON_USER_STOPPED: + return "USER STOPPED"; + case REASON_DEPENDENCY_DIED: + return "DEPENDENCY DIED"; case REASON_OTHER: return "OTHER KILLS BY SYSTEM"; default: @@ -772,6 +912,26 @@ public final class ApplicationExitInfo implements Parcelable { return "MEMORY PRESSURE"; case SUBREASON_EXCESSIVE_CPU: return "EXCESSIVE CPU USAGE"; + case SUBREASON_SYSTEM_UPDATE_DONE: + return "SYSTEM UPDATE_DONE"; + case SUBREASON_KILL_ALL_FG: + return "KILL ALL FG"; + case SUBREASON_KILL_ALL_BG_EXCEPT: + return "KILL ALL BG EXCEPT"; + case SUBREASON_KILL_UID: + return "KILL UID"; + case SUBREASON_KILL_PID: + return "KILL PID"; + case SUBREASON_INVALID_START: + return "INVALID START"; + case SUBREASON_INVALID_STATE: + return "INVALID STATE"; + case SUBREASON_IMPERCEPTIBLE: + return "IMPERCEPTIBLE"; + case SUBREASON_REMOVE_LRU: + return "REMOVE LRU"; + case SUBREASON_ISOLATED_NOT_NEEDED: + return "ISOLATED NOT NEEDED"; default: return "UNKNOWN"; } diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index be07b3725bde..a3bcc9cee39b 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -23,7 +23,6 @@ import android.annotation.SystemApi; import android.app.ContextImpl.ServiceInitializationState; import android.app.admin.DevicePolicyManager; import android.app.admin.IDevicePolicyManager; -import android.app.appsearch.AppSearchManagerFrameworkInitializer; import android.app.blob.BlobStoreManagerFrameworkInitializer; import android.app.contentsuggestions.ContentSuggestionsManager; import android.app.contentsuggestions.IContentSuggestionsManager; @@ -1343,7 +1342,6 @@ public final class SystemServiceRegistry { JobSchedulerFrameworkInitializer.registerServiceWrappers(); BlobStoreManagerFrameworkInitializer.initialize(); TelephonyFrameworkInitializer.registerServiceWrappers(); - AppSearchManagerFrameworkInitializer.initialize(); WifiFrameworkInitializer.registerServiceWrappers(); StatsFrameworkInitializer.registerServiceWrappers(); } finally { diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index a8f7610ecaf0..aba86e9f1054 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -5109,16 +5109,6 @@ public abstract class Context { /** * Use with {@link #getSystemService(String)} to retrieve an - * {@link android.app.appsearch.AppSearchManager} for - * indexing and querying app data managed by the system. - * - * @see #getSystemService(String) - * @hide - */ - public static final String APP_SEARCH_SERVICE = "app_search"; - - /** - * Use with {@link #getSystemService(String)} to retrieve an * {@link android.content.integrity.AppIntegrityManager}. * @hide */ diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java index f2e16b46422f..a9585c62866b 100644 --- a/core/java/android/os/BatteryStatsManager.java +++ b/core/java/android/os/BatteryStatsManager.java @@ -350,12 +350,13 @@ public final class BatteryStatsManager { /** * Indicates that an app has acquired the wifi multicast lock. * - * @param uid UID of the app that acquired the wifi lock (to be used for battery blaming). + * @param ws Worksource with the uid of the app that acquired the wifi lock (to be used for + * battery blaming). */ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) - public void reportWifiMulticastEnabled(int uid) { + public void reportWifiMulticastEnabled(@NonNull WorkSource ws) { try { - mBatteryStats.noteWifiMulticastEnabled(uid); + mBatteryStats.noteWifiMulticastEnabled(ws.getAttributionUid()); } catch (RemoteException e) { e.rethrowFromSystemServer(); } @@ -364,12 +365,13 @@ public final class BatteryStatsManager { /** * Indicates that an app has released the wifi multicast lock. * - * @param uid UID of the app that released the wifi lock (to be used for battery blaming). + * @param ws Worksource with the uid of the app that released the wifi lock (to be used for + * battery blaming). */ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) - public void reportWifiMulticastDisabled(int uid) { + public void reportWifiMulticastDisabled(@NonNull WorkSource ws) { try { - mBatteryStats.noteWifiMulticastDisabled(uid); + mBatteryStats.noteWifiMulticastDisabled(ws.getAttributionUid()); } catch (RemoteException e) { e.rethrowFromSystemServer(); } diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java index 223f92054f79..de274c082c80 100644 --- a/core/java/android/os/UpdateEngine.java +++ b/core/java/android/os/UpdateEngine.java @@ -559,6 +559,37 @@ public class UpdateEngine { } } + private static class CleanupAppliedPayloadCallback extends IUpdateEngineCallback.Stub { + private int mErrorCode = ErrorCodeConstants.ERROR; + private boolean mCompleted = false; + private Object mLock = new Object(); + private int getResult() { + synchronized (mLock) { + while (!mCompleted) { + try { + mLock.wait(); + } catch (InterruptedException ex) { + // do nothing, just wait again. + } + } + return mErrorCode; + } + } + + @Override + public void onStatusUpdate(int status, float percent) { + } + + @Override + public void onPayloadApplicationComplete(int errorCode) { + synchronized (mLock) { + mErrorCode = errorCode; + mCompleted = true; + mLock.notifyAll(); + } + } + } + /** * Cleanup files used by the previous update and free up space after the * device has been booted successfully into the new build. @@ -590,8 +621,10 @@ public class UpdateEngine { @WorkerThread @ErrorCode public int cleanupAppliedPayload() { + CleanupAppliedPayloadCallback callback = new CleanupAppliedPayloadCallback(); try { - return mUpdateEngine.cleanupSuccessfulUpdate(); + mUpdateEngine.cleanupSuccessfulUpdate(callback); + return callback.getResult(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/os/connectivity/WifiBatteryStats.java b/core/java/android/os/connectivity/WifiBatteryStats.java index 3c30f6343405..7e6ebcfc61db 100644 --- a/core/java/android/os/connectivity/WifiBatteryStats.java +++ b/core/java/android/os/connectivity/WifiBatteryStats.java @@ -215,7 +215,7 @@ public final class WifiBatteryStats implements Parcelable { * Returns the number of bytes transmitted over wifi within * {@link #getLoggingDurationMillis()}. * - * @return Number of packets received. + * @return Number of bytes transmitted. */ public long getNumBytesTx() { return mNumBytesTx; @@ -225,7 +225,7 @@ public final class WifiBatteryStats implements Parcelable { * Returns the number of packets received over wifi within * {@link #getLoggingDurationMillis()}. * - * @return Number of bytes transmitted. + * @return Number of packets received. */ public long getNumPacketsRx() { return mNumPacketsRx; diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index f745e4376896..6ab61850480d 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -854,6 +854,11 @@ public class ResolverActivity extends Activity implements private void setAlwaysButtonEnabled(boolean hasValidSelection, int checkedPos, boolean filtered) { + if (mMultiProfilePagerAdapter.getCurrentUserHandle() != getUser()) { + // Never allow the inactive profile to always open an app. + mAlwaysButton.setEnabled(false); + return; + } boolean enabled = false; ResolveInfo ri = null; if (hasValidSelection) { @@ -877,19 +882,21 @@ public class ResolverActivity extends Activity implements } } - ActivityInfo activityInfo = ri.activityInfo; + if (ri != null) { + ActivityInfo activityInfo = ri.activityInfo; - boolean hasRecordPermission = - mPm.checkPermission(android.Manifest.permission.RECORD_AUDIO, - activityInfo.packageName) - == android.content.pm.PackageManager.PERMISSION_GRANTED; + boolean hasRecordPermission = + mPm.checkPermission(android.Manifest.permission.RECORD_AUDIO, + activityInfo.packageName) + == android.content.pm.PackageManager.PERMISSION_GRANTED; - if (!hasRecordPermission) { - // OK, we know the record permission, is this a capture device - boolean hasAudioCapture = - getIntent().getBooleanExtra( - ResolverActivity.EXTRA_IS_AUDIO_CAPTURE_DEVICE, false); - enabled = !hasAudioCapture; + if (!hasRecordPermission) { + // OK, we know the record permission, is this a capture device + boolean hasAudioCapture = + getIntent().getBooleanExtra( + ResolverActivity.EXTRA_IS_AUDIO_CAPTURE_DEVICE, false); + enabled = !hasAudioCapture; + } } mAlwaysButton.setEnabled(enabled); } @@ -1567,10 +1574,26 @@ public class ResolverActivity extends Activity implements viewPager.setVisibility(View.VISIBLE); tabHost.setCurrentTab(mMultiProfilePagerAdapter.getCurrentPage()); - mMultiProfilePagerAdapter.setOnProfileSelectedListener(tabHost::setCurrentTab); + mMultiProfilePagerAdapter.setOnProfileSelectedListener( + index -> { + tabHost.setCurrentTab(index); + resetButtonBar(); + resetCheckedItem(); + }); findViewById(R.id.resolver_tab_divider).setVisibility(View.VISIBLE); } + private void resetCheckedItem() { + if (!isIntentPicker()) { + return; + } + mLastSelected = ListView.INVALID_POSITION; + ListView inactiveListView = (ListView) mMultiProfilePagerAdapter.getInactiveAdapterView(); + if (inactiveListView.getCheckedItemCount() > 0) { + inactiveListView.setItemChecked(inactiveListView.getCheckedItemPosition(), false); + } + } + private void resetTabsHeaderStyle(TabWidget tabWidget) { for (int i = 0; i < tabWidget.getChildCount(); i++) { TextView title = tabWidget.getChildAt(i).findViewById(android.R.id.title); @@ -1677,6 +1700,10 @@ public class ResolverActivity extends Activity implements } private void resetAlwaysOrOnceButtonBar() { + // Disable both buttons initially + setAlwaysButtonEnabled(false, ListView.INVALID_POSITION, false); + mOnceButton.setEnabled(false); + int filteredPosition = mMultiProfilePagerAdapter.getActiveListAdapter() .getFilteredPosition(); if (useLayoutWithDefault() && filteredPosition != ListView.INVALID_POSITION) { diff --git a/core/jni/Android.bp b/core/jni/Android.bp index ade2c7d86faf..9ddaa981c382 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -1,13 +1,4 @@ -genrule { - name: "android_util_StatsLogInternal.cpp", - tools: ["stats-log-api-gen"], - cmd: "$(location stats-log-api-gen) --jni $(genDir)/android_util_StatsLogInternal.cpp", - out: [ - "android_util_StatsLogInternal.cpp", - ], -} - cc_library_shared { name: "libandroid_runtime", host_supported: true, @@ -277,7 +268,6 @@ cc_library_shared { // our headers include libnativewindow's public headers "libnativewindow", ], - generated_sources: ["android_util_StatsLogInternal.cpp"], header_libs: ["bionic_libc_platform_headers"], }, host: { diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index c41398c97ca0..ba7aef7c208e 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -108,7 +108,6 @@ namespace android { extern int register_android_app_admin_SecurityLog(JNIEnv* env); extern int register_android_content_AssetManager(JNIEnv* env); extern int register_android_util_EventLog(JNIEnv* env); -extern int register_android_util_StatsLogInternal(JNIEnv* env); extern int register_android_util_Log(JNIEnv* env); extern int register_android_util_MemoryIntArray(JNIEnv* env); extern int register_android_content_StringBlock(JNIEnv* env); @@ -1435,7 +1434,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_util_EventLog), REG_JNI(register_android_util_Log), REG_JNI(register_android_util_MemoryIntArray), - REG_JNI(register_android_util_StatsLogInternal), REG_JNI(register_android_app_admin_SecurityLog), REG_JNI(register_android_content_AssetManager), REG_JNI(register_android_content_StringBlock), diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index cfd3c0915002..c72668f84fb1 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -33,7 +33,6 @@ // Static whitelist of open paths that the zygote is allowed to keep open. static const char* kPathWhitelist[] = { - "/apex/com.android.appsearch/javalib/framework-appsearch.jar", "/apex/com.android.conscrypt/javalib/conscrypt.jar", "/apex/com.android.ipsec/javalib/ike.jar", "/apex/com.android.media/javalib/updatable-media.jar", diff --git a/core/proto/android/app/appexit_enums.proto b/core/proto/android/app/appexit_enums.proto new file mode 100644 index 000000000000..491e1dc203b5 --- /dev/null +++ b/core/proto/android/app/appexit_enums.proto @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; +option java_multiple_files = true; + +package android.app; + +/** + * The reason code that why app process is killed. + */ +enum AppExitReasonCode { + /** + * Application process died due to unknown reason. + */ + REASON_UNKNOWN = 0; + + /** + * Application process exit normally by itself, for example, + * via {@link android.os.Process#exit}; {@link #status} will specify the exit code. + * + * <p>Applications should normally not do this, as the system has a better knowledge + * in terms of process management.</p> + */ + REASON_EXIT_SELF = 1; + + /** + * Application process died due to the result of an OS signal; for example, + * {@link android.os.Process#SIGNAL_KILL}; {@link #status} will specify the signum. + */ + REASON_SIGNALED = 2; + + /** + * Application process was killed by the system low memory killer, meaning the system was + * under memory pressure at the time of kill. + */ + REASON_LOW_MEMORY = 3; + + /** + * Application process died because of an unhandled exception in Java code. + */ + REASON_CRASH = 4; + + /** + * Application process died because it's crashed due to a native code crash. + */ + REASON_CRASH_NATIVE = 5; + + /** + * Application process was killed due to being unresponsive (ANR). + */ + REASON_ANR = 6; + + /** + * Application process was killed because it took too long to attach to the system + * during the start. + */ + REASON_INITIALIZATION_FAILURE = 7; + + /** + * Application process was killed because of initialization failure, + * for example, it took too long to attach to the system during the start, + * or there was an error during initialization. + */ + REASON_PERMISSION_CHANGE = 8; + + /** + * Application process was killed by the activity manager due to excessive resource usage. + */ + REASON_EXCESSIVE_RESOURCE_USAGE = 9; + + /** + * Application process was killed because of the user request, for example, + * user clicked the "Force stop" button of the application in the Settings, + * or swiped away the application from Recents. + */ + REASON_USER_REQUESTED = 10; + + /** + * Application process was killed, because the user they are running as on devices + * with mutlple users, was stopped. + */ + REASON_USER_STOPPED = 11; + + /** + * Application process was killed because its dependency was going away, for example, + * a stable content provider connection's client will be killed if the provider is killed. + */ + REASON_DEPENDENCY_DIED = 12; + + /** + * Application process was killed by the system for various other reasons, + * for example, the application package got disabled by the user; + * {@link #description} will specify the cause given by the system. + */ + REASON_OTHER = 13; +} + +/** + * The supplemental reason code that why app process is killed + */ +enum AppExitSubReasonCode { + /** + * Application process kills subReason is unknown. + */ + SUBREASON_UNKNOWN = 0; + + /** + * Application process was killed because user quit it on the "wait for debugger" dialog. + */ + SUBREASON_WAIT_FOR_DEBUGGER = 1; + + /** + * Application process was killed by the activity manager because there were too many cached + * processes. + */ + SUBREASON_TOO_MANY_CACHED = 2; + + /** + * Application process was killed by the activity manager because there were too many empty + * processes. + */ + SUBREASON_TOO_MANY_EMPTY = 3; + + /** + * Application process was killed by the activity manager because there were too many cached + * processes and this process had been in empty state for a long time. + */ + SUBREASON_TRIM_EMPTY = 4; + + /** + * Application process was killed by the activity manager because system was on + * memory pressure and this process took large amount of cached memory. + */ + SUBREASON_LARGE_CACHED = 5; + + /** + * Application process was killed by the activity manager because the system was on + * low memory pressure for a significant amount of time since last idle. + */ + SUBREASON_MEMORY_PRESSURE = 6; + + /** + * Application process was killed by the activity manager due to excessive CPU usage. + */ + SUBREASON_EXCESSIVE_CPU = 7; + + /** + * System update has done (so the system update process should be killed). + */ + SUBREASON_SYSTEM_UPDATE_DONE = 8; + + /** + * Kill all foreground services, for now it only occurs when enabling the quiet + * mode for the managed profile. + */ + SUBREASON_KILL_ALL_FG = 9; + + /** + * All background processes except certain ones were killed, for now it only occurs + * when the density of the default display is changed. + */ + SUBREASON_KILL_ALL_BG_EXCEPT = 10; + + /** + * The process associated with the UID was explicitly killed, for example, + * it could be because of permission changes. + */ + SUBREASON_KILL_UID = 11; + + /** + * The process was explicitly killed with its PID, typically because of + * the low memory for surfaces. + */ + SUBREASON_KILL_PID = 12; + + /** + * The start of the process was invalid. + */ + SUBREASON_INVALID_START = 13; + + /** + * The process was killed because it's in an invalid state, typically + * it's triggered from SHELL. + */ + SUBREASON_INVALID_STATE = 14; + + /** + * The process was killed when it's imperceptible to user, because it was + * in a bad state. + */ + SUBREASON_IMPERCEPTIBLE = 15; + + /** + * The process was killed because it's being moved out from LRU list. + */ + SUBREASON_REMOVE_LRU = 16; + + /** + * The process was killed because it's isolated and was in a cached state. + */ + SUBREASON_ISOLATED_NOT_NEEDED = 17; +} + +/** + * The relative importance level that the system places on a process. + * Keep sync with the definitions in + * {@link android.app.ActivityManager.RunningAppProcessInfo} + */ +enum Importance { + option allow_alias = true; + + IMPORTANCE_FOREGROUND = 100; + IMPORTANCE_FOREGROUND_SERVICE = 125; + IMPORTANCE_TOP_SLEEPING_PRE_28 = 150; + IMPORTANCE_VISIBLE = 200; + IMPORTANCE_PERCEPTIBLE_PRE_26 = 130; + IMPORTANCE_PERCEPTIBLE = 230; + IMPORTANCE_CANT_SAVE_STATE_PRE_26 = 170; + IMPORTANCE_SERVICE = 300; + IMPORTANCE_TOP_SLEEPING = 325; + IMPORTANCE_CANT_SAVE_STATE = 350; + IMPORTANCE_CACHED = 400; + IMPORTANCE_BACKGROUND = 400; + IMPORTANCE_EMPTY = 500; + IMPORTANCE_GONE = 1000; +} diff --git a/core/proto/android/app/appexitinfo.proto b/core/proto/android/app/appexitinfo.proto index 6a4922000805..66173f60bfd5 100644 --- a/core/proto/android/app/appexitinfo.proto +++ b/core/proto/android/app/appexitinfo.proto @@ -20,6 +20,7 @@ option java_multiple_files = true; package android.app; import "frameworks/base/core/proto/android/privacy.proto"; +import "frameworks/base/core/proto/android/app/appexit_enums.proto"; /** * An android.app.ApplicationExitInfo object. @@ -33,150 +34,9 @@ message ApplicationExitInfoProto { optional int32 defining_uid = 4; optional string process_name = 5; optional int32 connection_group = 6; - - enum ReasonCode { - /** - * Application process died due to unknown reason. - */ - REASON_UNKNOWN = 0; - - /** - * Application process exit normally by itself, for example, - * via {@link android.os.Process#exit}; {@link #status} will specify the exit code. - * - * <p>Applications should normally not do this, as the system has a better knowledge - * in terms of process management.</p> - */ - REASON_EXIT_SELF = 1; - - /** - * Application process died due to the result of an OS signal; for example, - * {@link android.os.Process#SIGNAL_KILL}; {@link #status} will specify the signum. - */ - REASON_SIGNALED = 2; - - /** - * Application process was killed by the system low memory killer, meaning the system was - * under memory pressure at the time of kill. - */ - REASON_LOW_MEMORY = 3; - - /** - * Application process died because of an unhandled exception in Java code. - */ - REASON_CRASH = 4; - - /** - * Application process died because it's crashed due to a native code crash. - */ - REASON_CRASH_NATIVE = 5; - - /** - * Application process was killed due to being unresponsive (ANR). - */ - REASON_ANR = 6; - - /** - * Application process was killed because it took too long to attach to the system - * during the start. - */ - REASON_INITIALIZATION_FAILURE = 7; - - /** - * Application process was killed because of initialization failure, - * for example, it took too long to attach to the system during the start, - * or there was an error during initialization. - */ - REASON_PERMISSION_CHANGE = 8; - - /** - * Application process was killed by the activity manager due to excessive resource usage. - */ - REASON_EXCESSIVE_RESOURCE_USAGE = 9; - - /** - * Application process was killed by the system for various other reasons, - * for example, the application package got disabled by the user; - * {@link #description} will specify the cause given by the system. - */ - REASON_OTHER = 10; - - } - optional ReasonCode reason = 7; - - enum SubReason { - /** - * Application process kills subReason is unknown. - */ - SUBREASON_UNKNOWN = 0; - - /** - * Application process was killed because user quit it on the "wait for debugger" dialog. - */ - SUBREASON_WAIT_FOR_DEBUGGER = 1; - - /** - * Application process was killed by the activity manager because there were too many cached - * processes. - */ - SUBREASON_TOO_MANY_CACHED = 2; - - /** - * Application process was killed by the activity manager because there were too many empty - * processes. - */ - SUBREASON_TOO_MANY_EMPTY = 3; - - /** - * Application process was killed by the activity manager because there were too many cached - * processes and this process had been in empty state for a long time. - */ - SUBREASON_TRIM_EMPTY = 4; - - /** - * Application process was killed by the activity manager because system was on - * memory pressure and this process took large amount of cached memory. - */ - SUBREASON_LARGE_CACHED = 5; - - /** - * Application process was killed by the activity manager because the system was on - * low memory pressure for a significant amount of time since last idle. - */ - SUBREASON_MEMORY_PRESSURE = 6; - - /** - * Application process was killed by the activity manager due to excessive CPU usage. - */ - SUBREASON_EXCESSIVE_CPU = 7; - } - - optional SubReason sub_reason = 8; - + optional AppExitReasonCode reason = 7; + optional AppExitSubReasonCode sub_reason = 8; optional int32 status = 9; - - enum Importance { - option allow_alias = true; - /** - * Keep sync with the definitions in - * {@link android.app.ActivityManager.RunningAppProcessInfo} - */ - IMPORTANCE_FOREGROUND = 100; - IMPORTANCE_FOREGROUND_SERVICE = 125; - IMPORTANCE_TOP_SLEEPING_PRE_28 = 150; - IMPORTANCE_VISIBLE = 200; - IMPORTANCE_PERCEPTIBLE_PRE_26 = 130; - IMPORTANCE_PERCEPTIBLE = 230; - IMPORTANCE_CANT_SAVE_STATE_PRE_26 = 170; - IMPORTANCE_SERVICE = 300; - IMPORTANCE_TOP_SLEEPING = 325; - IMPORTANCE_CANT_SAVE_STATE = 350; - IMPORTANCE_CACHED = 400; - IMPORTANCE_BACKGROUND = 400; - IMPORTANCE_EMPTY = 500; - IMPORTANCE_GONE = 1000; - } - optional Importance importance = 10; optional int64 pss = 11; optional int64 rss = 12; diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index eb760b9c45cf..8d51a6000086 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -53,10 +53,7 @@ android_test { "android.test.base", "android.test.mock", "framework-atb-backward-compatibility", - // TODO(b/149928788): Remove this when statsd tests move into the statsd dir. - "framework-statsd", "framework", - "icing-java-proto-lite", "ext", "framework-res", ], diff --git a/core/tests/coretests/src/android/app/appsearch/AppSearchDocumentTest.java b/core/tests/coretests/src/android/app/appsearch/AppSearchDocumentTest.java deleted file mode 100644 index 4a4f13676cb3..000000000000 --- a/core/tests/coretests/src/android/app/appsearch/AppSearchDocumentTest.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.appsearch; - -import static com.google.common.truth.Truth.assertThat; - -import static org.testng.Assert.assertThrows; - -import androidx.test.filters.SmallTest; - -import com.google.android.icing.proto.DocumentProto; -import com.google.android.icing.proto.PropertyProto; -import com.google.android.icing.protobuf.ByteString; - -import org.junit.Test; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; - -@SmallTest -public class AppSearchDocumentTest { - private static final byte[] sByteArray1 = new byte[]{(byte) 1, (byte) 2, (byte) 3}; - private static final byte[] sByteArray2 = new byte[]{(byte) 4, (byte) 5, (byte) 6}; - private static final AppSearchDocument sDocumentProperties1 = new AppSearchDocument - .Builder("sDocumentProperties1", "sDocumentPropertiesSchemaType1") - .build(); - private static final AppSearchDocument sDocumentProperties2 = new AppSearchDocument - .Builder("sDocumentProperties2", "sDocumentPropertiesSchemaType2") - .build(); - - @Test - public void testDocumentEquals_Identical() { - AppSearchDocument document1 = new AppSearchDocument.Builder("uri1", "schemaType1") - .setCreationTimestampMillis(5L) - .setTtlMillis(1L) - .setProperty("longKey1", 1L, 2L, 3L) - .setProperty("doubleKey1", 1.0, 2.0, 3.0) - .setProperty("booleanKey1", true, false, true) - .setProperty("stringKey1", "test-value1", "test-value2", "test-value3") - .setProperty("byteKey1", sByteArray1, sByteArray2) - .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2) - .build(); - AppSearchDocument document2 = new AppSearchDocument.Builder("uri1", "schemaType1") - .setCreationTimestampMillis(5L) - .setTtlMillis(1L) - .setProperty("longKey1", 1L, 2L, 3L) - .setProperty("doubleKey1", 1.0, 2.0, 3.0) - .setProperty("booleanKey1", true, false, true) - .setProperty("stringKey1", "test-value1", "test-value2", "test-value3") - .setProperty("byteKey1", sByteArray1, sByteArray2) - .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2) - .build(); - assertThat(document1).isEqualTo(document2); - assertThat(document1.hashCode()).isEqualTo(document2.hashCode()); - } - - @Test - public void testDocumentEquals_DifferentOrder() { - AppSearchDocument document1 = new AppSearchDocument.Builder("uri1", "schemaType1") - .setCreationTimestampMillis(5L) - .setProperty("longKey1", 1L, 2L, 3L) - .setProperty("byteKey1", sByteArray1, sByteArray2) - .setProperty("doubleKey1", 1.0, 2.0, 3.0) - .setProperty("booleanKey1", true, false, true) - .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2) - .setProperty("stringKey1", "test-value1", "test-value2", "test-value3") - .build(); - - // Create second document with same parameter but different order. - AppSearchDocument document2 = new AppSearchDocument.Builder("uri1", "schemaType1") - .setCreationTimestampMillis(5L) - .setProperty("booleanKey1", true, false, true) - .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2) - .setProperty("stringKey1", "test-value1", "test-value2", "test-value3") - .setProperty("doubleKey1", 1.0, 2.0, 3.0) - .setProperty("byteKey1", sByteArray1, sByteArray2) - .setProperty("longKey1", 1L, 2L, 3L) - .build(); - assertThat(document1).isEqualTo(document2); - assertThat(document1.hashCode()).isEqualTo(document2.hashCode()); - } - - @Test - public void testDocumentEquals_Failure() { - AppSearchDocument document1 = new AppSearchDocument.Builder("uri1", "schemaType1") - .setCreationTimestampMillis(5L) - .setProperty("longKey1", 1L, 2L, 3L) - .build(); - - // Create second document with same order but different value. - AppSearchDocument document2 = new AppSearchDocument.Builder("uri1", "schemaType1") - .setCreationTimestampMillis(5L) - .setProperty("longKey1", 1L, 2L, 4L) // Different - .build(); - assertThat(document1).isNotEqualTo(document2); - assertThat(document1.hashCode()).isNotEqualTo(document2.hashCode()); - } - - @Test - public void testDocumentEquals_Failure_RepeatedFieldOrder() { - AppSearchDocument document1 = new AppSearchDocument.Builder("uri1", "schemaType1") - .setCreationTimestampMillis(5L) - .setProperty("booleanKey1", true, false, true) - .build(); - - // Create second document with same order but different value. - AppSearchDocument document2 = new AppSearchDocument.Builder("uri1", "schemaType1") - .setCreationTimestampMillis(5L) - .setProperty("booleanKey1", true, true, false) // Different - .build(); - assertThat(document1).isNotEqualTo(document2); - assertThat(document1.hashCode()).isNotEqualTo(document2.hashCode()); - } - - @Test - public void testDocumentGetSingleValue() { - AppSearchDocument document = new AppSearchDocument.Builder("uri1", "schemaType1") - .setCreationTimestampMillis(5L) - .setScore(1) - .setTtlMillis(1L) - .setProperty("longKey1", 1L) - .setProperty("doubleKey1", 1.0) - .setProperty("booleanKey1", true) - .setProperty("stringKey1", "test-value1") - .setProperty("byteKey1", sByteArray1) - .setProperty("documentKey1", sDocumentProperties1) - .build(); - assertThat(document.getUri()).isEqualTo("uri1"); - assertThat(document.getTtlMillis()).isEqualTo(1L); - assertThat(document.getSchemaType()).isEqualTo("schemaType1"); - assertThat(document.getCreationTimestampMillis()).isEqualTo(5); - assertThat(document.getScore()).isEqualTo(1); - assertThat(document.getPropertyLong("longKey1")).isEqualTo(1L); - assertThat(document.getPropertyDouble("doubleKey1")).isEqualTo(1.0); - assertThat(document.getPropertyBoolean("booleanKey1")).isTrue(); - assertThat(document.getPropertyString("stringKey1")).isEqualTo("test-value1"); - assertThat(document.getPropertyBytes("byteKey1")) - .asList().containsExactly((byte) 1, (byte) 2, (byte) 3); - assertThat(document.getPropertyDocument("documentKey1")).isEqualTo(sDocumentProperties1); - } - - @Test - public void testDocumentGetArrayValues() { - AppSearchDocument document = new AppSearchDocument.Builder("uri1", "schemaType1") - .setCreationTimestampMillis(5L) - .setProperty("longKey1", 1L, 2L, 3L) - .setProperty("doubleKey1", 1.0, 2.0, 3.0) - .setProperty("booleanKey1", true, false, true) - .setProperty("stringKey1", "test-value1", "test-value2", "test-value3") - .setProperty("byteKey1", sByteArray1, sByteArray2) - .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2) - .build(); - - assertThat(document.getUri()).isEqualTo("uri1"); - assertThat(document.getSchemaType()).isEqualTo("schemaType1"); - assertThat(document.getPropertyLongArray("longKey1")).asList().containsExactly(1L, 2L, 3L); - assertThat(document.getPropertyDoubleArray("doubleKey1")).usingExactEquality() - .containsExactly(1.0, 2.0, 3.0); - assertThat(document.getPropertyBooleanArray("booleanKey1")).asList() - .containsExactly(true, false, true); - assertThat(document.getPropertyStringArray("stringKey1")).asList() - .containsExactly("test-value1", "test-value2", "test-value3"); - assertThat(document.getPropertyBytesArray("byteKey1")).asList() - .containsExactly(sByteArray1, sByteArray2); - assertThat(document.getPropertyDocumentArray("documentKey1")).asList() - .containsExactly(sDocumentProperties1, sDocumentProperties2); - } - - @Test - public void testDocumentGetValues_DifferentTypes() { - AppSearchDocument document = new AppSearchDocument.Builder("uri1", "schemaType1") - .setScore(1) - .setProperty("longKey1", 1L) - .setProperty("booleanKey1", true, false, true) - .setProperty("stringKey1", "test-value1", "test-value2", "test-value3") - .build(); - - // Get a value for a key that doesn't exist - assertThat(document.getPropertyDouble("doubleKey1")).isNull(); - assertThat(document.getPropertyDoubleArray("doubleKey1")).isNull(); - - // Get a value with a single element as an array and as a single value - assertThat(document.getPropertyLong("longKey1")).isEqualTo(1L); - assertThat(document.getPropertyLongArray("longKey1")).asList().containsExactly(1L); - - // Get a value with multiple elements as an array and as a single value - assertThat(document.getPropertyString("stringKey1")).isEqualTo("test-value1"); - assertThat(document.getPropertyStringArray("stringKey1")).asList() - .containsExactly("test-value1", "test-value2", "test-value3"); - - // Get a value of the wrong type - assertThat(document.getPropertyDouble("longKey1")).isNull(); - assertThat(document.getPropertyDoubleArray("longKey1")).isNull(); - } - - @Test - public void testDocumentInvalid() { - AppSearchDocument.Builder builder = new AppSearchDocument.Builder("uri1", "schemaType1"); - assertThrows( - IllegalArgumentException.class, () -> builder.setProperty("test", new boolean[]{})); - } - - @Test - public void testDocumentProtoPopulation() { - AppSearchDocument document = new AppSearchDocument.Builder("uri1", "schemaType1") - .setCreationTimestampMillis(5L) - .setScore(1) - .setTtlMillis(1L) - .setProperty("longKey1", 1L) - .setProperty("doubleKey1", 1.0) - .setProperty("booleanKey1", true) - .setProperty("stringKey1", "test-value1") - .setProperty("byteKey1", sByteArray1) - .setProperty("documentKey1", sDocumentProperties1) - .build(); - - // Create the Document proto. Need to sort the property order by key. - DocumentProto.Builder documentProtoBuilder = DocumentProto.newBuilder() - .setUri("uri1") - .setSchema("schemaType1") - .setCreationTimestampMs(5L) - .setScore(1) - .setTtlMs(1L); - HashMap<String, PropertyProto.Builder> propertyProtoMap = new HashMap<>(); - propertyProtoMap.put("longKey1", - PropertyProto.newBuilder().setName("longKey1").addInt64Values(1L)); - propertyProtoMap.put("doubleKey1", - PropertyProto.newBuilder().setName("doubleKey1").addDoubleValues(1.0)); - propertyProtoMap.put("booleanKey1", - PropertyProto.newBuilder().setName("booleanKey1").addBooleanValues(true)); - propertyProtoMap.put("stringKey1", - PropertyProto.newBuilder().setName("stringKey1").addStringValues("test-value1")); - propertyProtoMap.put("byteKey1", - PropertyProto.newBuilder().setName("byteKey1").addBytesValues( - ByteString.copyFrom(sByteArray1))); - propertyProtoMap.put("documentKey1", - PropertyProto.newBuilder().setName("documentKey1") - .addDocumentValues(sDocumentProperties1.getProto())); - List<String> sortedKey = new ArrayList<>(propertyProtoMap.keySet()); - Collections.sort(sortedKey); - for (String key : sortedKey) { - documentProtoBuilder.addProperties(propertyProtoMap.get(key)); - } - assertThat(document.getProto()).isEqualTo(documentProtoBuilder.build()); - } -} diff --git a/core/tests/coretests/src/android/app/appsearch/AppSearchEmailTest.java b/core/tests/coretests/src/android/app/appsearch/AppSearchEmailTest.java deleted file mode 100644 index 6aa16cc1e323..000000000000 --- a/core/tests/coretests/src/android/app/appsearch/AppSearchEmailTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.appsearch; - -import static com.google.common.truth.Truth.assertThat; - -import androidx.test.filters.SmallTest; - -import org.junit.Test; - -@SmallTest -public class AppSearchEmailTest { - - @Test - public void testBuildEmailAndGetValue() { - AppSearchEmail email = new AppSearchEmail.Builder("uri") - .setFrom("FakeFromAddress") - .setCc("CC1", "CC2") - // Score and Property are mixed into the middle to make sure DocumentBuilder's - // methods can be interleaved with EmailBuilder's methods. - .setScore(1) - .setProperty("propertyKey", "propertyValue1", "propertyValue2") - .setSubject("subject") - .setBody("EmailBody") - .build(); - - assertThat(email.getUri()).isEqualTo("uri"); - assertThat(email.getFrom()).isEqualTo("FakeFromAddress"); - assertThat(email.getTo()).isNull(); - assertThat(email.getCc()).asList().containsExactly("CC1", "CC2"); - assertThat(email.getBcc()).isNull(); - assertThat(email.getScore()).isEqualTo(1); - assertThat(email.getPropertyString("propertyKey")).isEqualTo("propertyValue1"); - assertThat(email.getPropertyStringArray("propertyKey")).asList().containsExactly( - "propertyValue1", "propertyValue2"); - assertThat(email.getSubject()).isEqualTo("subject"); - assertThat(email.getBody()).isEqualTo("EmailBody"); - } -} diff --git a/core/tests/coretests/src/android/app/appsearch/AppSearchSchemaTest.java b/core/tests/coretests/src/android/app/appsearch/AppSearchSchemaTest.java deleted file mode 100644 index 08ec2d0b1067..000000000000 --- a/core/tests/coretests/src/android/app/appsearch/AppSearchSchemaTest.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.appsearch; - -import static com.google.common.truth.Truth.assertThat; - -import static org.testng.Assert.assertThrows; -import static org.testng.Assert.expectThrows; - -import android.app.appsearch.AppSearchSchema.PropertyConfig; - -import androidx.test.filters.SmallTest; - -import com.google.android.icing.proto.IndexingConfig.TokenizerType; -import com.google.android.icing.proto.PropertyConfigProto; -import com.google.android.icing.proto.SchemaTypeConfigProto; -import com.google.android.icing.proto.TermMatchType; - -import org.junit.Test; - -@SmallTest -public class AppSearchSchemaTest { - @Test - public void testGetProto_Email() { - AppSearchSchema emailSchema = AppSearchSchema.newBuilder("Email") - .addProperty(AppSearchSchema.newPropertyBuilder("subject") - .setDataType(PropertyConfig.DATA_TYPE_STRING) - .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL) - .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) - .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) - .build() - ).addProperty(AppSearchSchema.newPropertyBuilder("body") - .setDataType(PropertyConfig.DATA_TYPE_STRING) - .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL) - .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) - .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) - .build() - ).build(); - - SchemaTypeConfigProto expectedEmailProto = SchemaTypeConfigProto.newBuilder() - .setSchemaType("Email") - .addProperties(PropertyConfigProto.newBuilder() - .setPropertyName("subject") - .setDataType(PropertyConfigProto.DataType.Code.STRING) - .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL) - .setIndexingConfig( - com.google.android.icing.proto.IndexingConfig.newBuilder() - .setTokenizerType(TokenizerType.Code.PLAIN) - .setTermMatchType(TermMatchType.Code.PREFIX) - ) - ).addProperties(PropertyConfigProto.newBuilder() - .setPropertyName("body") - .setDataType(PropertyConfigProto.DataType.Code.STRING) - .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL) - .setIndexingConfig( - com.google.android.icing.proto.IndexingConfig.newBuilder() - .setTokenizerType(TokenizerType.Code.PLAIN) - .setTermMatchType(TermMatchType.Code.PREFIX) - ) - ).build(); - - assertThat(emailSchema.getProto()).isEqualTo(expectedEmailProto); - } - - @Test - public void testGetProto_MusicRecording() { - AppSearchSchema musicRecordingSchema = AppSearchSchema.newBuilder("MusicRecording") - .addProperty(AppSearchSchema.newPropertyBuilder("artist") - .setDataType(PropertyConfig.DATA_TYPE_STRING) - .setCardinality(PropertyConfig.CARDINALITY_REPEATED) - .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) - .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) - .build() - ).addProperty(AppSearchSchema.newPropertyBuilder("pubDate") - .setDataType(PropertyConfig.DATA_TYPE_INT64) - .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL) - .setIndexingType(PropertyConfig.INDEXING_TYPE_NONE) - .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_NONE) - .build() - ).build(); - - SchemaTypeConfigProto expectedMusicRecordingProto = SchemaTypeConfigProto.newBuilder() - .setSchemaType("MusicRecording") - .addProperties(PropertyConfigProto.newBuilder() - .setPropertyName("artist") - .setDataType(PropertyConfigProto.DataType.Code.STRING) - .setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED) - .setIndexingConfig( - com.google.android.icing.proto.IndexingConfig.newBuilder() - .setTokenizerType(TokenizerType.Code.PLAIN) - .setTermMatchType(TermMatchType.Code.PREFIX) - ) - ).addProperties(PropertyConfigProto.newBuilder() - .setPropertyName("pubDate") - .setDataType(PropertyConfigProto.DataType.Code.INT64) - .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL) - .setIndexingConfig( - com.google.android.icing.proto.IndexingConfig.newBuilder() - .setTokenizerType(TokenizerType.Code.NONE) - .setTermMatchType(TermMatchType.Code.UNKNOWN) - ) - ).build(); - - assertThat(musicRecordingSchema.getProto()).isEqualTo(expectedMusicRecordingProto); - } - - @Test - public void testInvalidEnums() { - PropertyConfig.Builder builder = AppSearchSchema.newPropertyBuilder("test"); - assertThrows(IllegalArgumentException.class, () -> builder.setDataType(99)); - assertThrows(IllegalArgumentException.class, () -> builder.setCardinality(99)); - } - - @Test - public void testMissingFields() { - PropertyConfig.Builder builder = AppSearchSchema.newPropertyBuilder("test"); - Exception e = expectThrows(IllegalSchemaException.class, builder::build); - assertThat(e).hasMessageThat().contains("Missing field: dataType"); - - builder.setDataType(PropertyConfig.DATA_TYPE_DOCUMENT); - e = expectThrows(IllegalSchemaException.class, builder::build); - assertThat(e).hasMessageThat().contains("Missing field: schemaType"); - - builder.setSchemaType("TestType"); - e = expectThrows(IllegalSchemaException.class, builder::build); - assertThat(e).hasMessageThat().contains("Missing field: cardinality"); - - builder.setCardinality(PropertyConfig.CARDINALITY_REPEATED); - builder.build(); - } - - @Test - public void testDuplicateProperties() { - AppSearchSchema.Builder builder = AppSearchSchema.newBuilder("Email") - .addProperty(AppSearchSchema.newPropertyBuilder("subject") - .setDataType(PropertyConfig.DATA_TYPE_STRING) - .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL) - .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) - .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) - .build() - ).addProperty(AppSearchSchema.newPropertyBuilder("subject") - .setDataType(PropertyConfig.DATA_TYPE_STRING) - .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL) - .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES) - .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN) - .build() - ); - - Exception e = expectThrows(IllegalSchemaException.class, builder::build); - assertThat(e).hasMessageThat().contains("Property defined more than once: subject"); - } -} diff --git a/core/tests/coretests/src/android/app/appsearch/SearchResultsTest.java b/core/tests/coretests/src/android/app/appsearch/SearchResultsTest.java deleted file mode 100644 index 21259cc81758..000000000000 --- a/core/tests/coretests/src/android/app/appsearch/SearchResultsTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.appsearch; - -import static com.google.common.truth.Truth.assertThat; - -import static org.testng.Assert.assertThrows; - -import androidx.test.filters.SmallTest; - -import com.google.android.icing.proto.DocumentProto; -import com.google.android.icing.proto.SearchResultProto; - -import org.junit.Test; - -@SmallTest -public class SearchResultsTest { - - @Test - public void testSearchResultsEqual() { - final String uri = "testUri"; - final String schemaType = "testSchema"; - SearchResultProto.ResultProto result1 = SearchResultProto.ResultProto.newBuilder() - .setDocument(DocumentProto.newBuilder() - .setUri(uri) - .setSchema(schemaType) - .build()) - .build(); - SearchResultProto searchResults1 = SearchResultProto.newBuilder() - .addResults(result1) - .build(); - SearchResults res1 = new SearchResults(searchResults1); - SearchResultProto.ResultProto result2 = SearchResultProto.ResultProto.newBuilder() - .setDocument(DocumentProto.newBuilder() - .setUri(uri) - .setSchema(schemaType) - .build()) - .build(); - SearchResultProto searchResults2 = SearchResultProto.newBuilder() - .addResults(result2) - .build(); - SearchResults res2 = new SearchResults(searchResults2); - assertThat(res1.toString()).isEqualTo(res2.toString()); - } - - @Test - public void buildSearchSpecWithoutTermMatchType() { - assertThrows(RuntimeException.class, () -> SearchSpec.newBuilder() - .setSchemaTypes("testSchemaType") - .build()); - } -} diff --git a/core/tests/coretests/src/android/app/appsearch/SnippetTest.java b/core/tests/coretests/src/android/app/appsearch/SnippetTest.java deleted file mode 100644 index 3103708f985d..000000000000 --- a/core/tests/coretests/src/android/app/appsearch/SnippetTest.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.appsearch; - -import static com.google.common.truth.Truth.assertThat; - -import androidx.test.filters.SmallTest; - -import com.google.android.icing.proto.DocumentProto; -import com.google.android.icing.proto.PropertyProto; -import com.google.android.icing.proto.SearchResultProto; -import com.google.android.icing.proto.SnippetMatchProto; -import com.google.android.icing.proto.SnippetProto; - -import org.junit.Test; - -@SmallTest -public class SnippetTest { - - // TODO(sidchhabra): Add tests for Double and Long Snippets. - @Test - public void testSingleStringSnippet() { - - final String propertyKeyString = "content"; - final String propertyValueString = "A commonly used fake word is foo.\n" - + " Another nonsense word that’s used a lot\n" - + " is bar.\n"; - final String uri = "uri1"; - final String schemaType = "schema1"; - final String searchWord = "foo"; - final String exactMatch = "foo"; - final String window = "is foo"; - - // Building the SearchResult received from query. - PropertyProto property = PropertyProto.newBuilder() - .setName(propertyKeyString) - .addStringValues(propertyValueString) - .build(); - DocumentProto documentProto = DocumentProto.newBuilder() - .setUri(uri) - .setSchema(schemaType) - .addProperties(property) - .build(); - SnippetProto snippetProto = SnippetProto.newBuilder() - .addEntries(SnippetProto.EntryProto.newBuilder() - .setPropertyName(propertyKeyString) - .addSnippetMatches(SnippetMatchProto.newBuilder() - .setValuesIndex(0) - .setExactMatchPosition(29) - .setExactMatchBytes(3) - .setWindowPosition(26) - .setWindowBytes(6) - .build()) - .build()) - .build(); - SearchResultProto.ResultProto resultProto = SearchResultProto.ResultProto.newBuilder() - .setDocument(documentProto) - .setSnippet(snippetProto) - .build(); - SearchResultProto searchResultProto = SearchResultProto.newBuilder() - .addResults(resultProto) - .build(); - SearchResults searchResults = new SearchResults(searchResultProto); - - // Making ResultReader and getting Snippet values. - while (searchResults.hasNext()) { - SearchResults.Result result = searchResults.next(); - MatchInfo match = result.getMatchInfo().get(0); - assertThat(match.getPropertyPath()).isEqualTo(propertyKeyString); - assertThat(match.getFullText()).isEqualTo(propertyValueString); - assertThat(match.getExactMatch()).isEqualTo(exactMatch); - assertThat(match.getSnippet()).isEqualTo(window); - } - } - - // TODO(sidchhabra): Add tests for Double and Long Snippets. - @Test - public void testNoSnippets() { - - final String propertyKeyString = "content"; - final String propertyValueString = "A commonly used fake word is foo.\n" - + " Another nonsense word that’s used a lot\n" - + " is bar.\n"; - final String uri = "uri1"; - final String schemaType = "schema1"; - final String searchWord = "foo"; - final String exactMatch = "foo"; - final String window = "is foo"; - - // Building the SearchResult received from query. - PropertyProto property = PropertyProto.newBuilder() - .setName(propertyKeyString) - .addStringValues(propertyValueString) - .build(); - DocumentProto documentProto = DocumentProto.newBuilder() - .setUri(uri) - .setSchema(schemaType) - .addProperties(property) - .build(); - SearchResultProto.ResultProto resultProto = SearchResultProto.ResultProto.newBuilder() - .setDocument(documentProto) - .build(); - SearchResultProto searchResultProto = SearchResultProto.newBuilder() - .addResults(resultProto) - .build(); - SearchResults searchResults = new SearchResults(searchResultProto); - - while (searchResults.hasNext()) { - SearchResults.Result result = searchResults.next(); - assertThat(result.getMatchInfo()).isEqualTo(null); - } - } - - @Test - public void testMultipleStringSnippet() { - final String searchWord = "Test"; - - // Building the SearchResult received from query. - PropertyProto property1 = PropertyProto.newBuilder() - .setName("sender.name") - .addStringValues("Test Name Jr.") - .build(); - PropertyProto property2 = PropertyProto.newBuilder() - .setName("sender.email") - .addStringValues("TestNameJr@gmail.com") - .build(); - DocumentProto documentProto = DocumentProto.newBuilder() - .setUri("uri1") - .setSchema("schema1") - .addProperties(property1) - .addProperties(property2) - .build(); - SnippetProto snippetProto = SnippetProto.newBuilder() - .addEntries( - SnippetProto.EntryProto.newBuilder() - .setPropertyName("sender.name") - .addSnippetMatches( - SnippetMatchProto.newBuilder() - .setValuesIndex(0) - .setExactMatchPosition(0) - .setExactMatchBytes(4) - .setWindowPosition(0) - .setWindowBytes(9) - .build()) - .build()) - .addEntries( - SnippetProto.EntryProto.newBuilder() - .setPropertyName("sender.email") - .addSnippetMatches( - SnippetMatchProto.newBuilder() - .setValuesIndex(0) - .setExactMatchPosition(0) - .setExactMatchBytes(20) - .setWindowPosition(0) - .setWindowBytes(20) - .build()) - .build() - ) - .build(); - SearchResultProto.ResultProto resultProto = SearchResultProto.ResultProto.newBuilder() - .setDocument(documentProto) - .setSnippet(snippetProto) - .build(); - SearchResultProto searchResultProto = SearchResultProto.newBuilder() - .addResults(resultProto) - .build(); - SearchResults searchResults = new SearchResults(searchResultProto); - - // Making ResultReader and getting Snippet values. - while (searchResults.hasNext()) { - SearchResults.Result result = searchResults.next(); - - MatchInfo match1 = result.getMatchInfo().get(0); - assertThat(match1.getPropertyPath()).isEqualTo("sender.name"); - assertThat(match1.getFullText()).isEqualTo("Test Name Jr."); - assertThat(match1.getExactMatch()).isEqualTo("Test"); - assertThat(match1.getSnippet()).isEqualTo("Test Name"); - - MatchInfo match2 = result.getMatchInfo().get(1); - assertThat(match2.getPropertyPath()).isEqualTo("sender.email"); - assertThat(match2.getFullText()).isEqualTo("TestNameJr@gmail.com"); - assertThat(match2.getExactMatch()).isEqualTo("TestNameJr@gmail.com"); - assertThat(match2.getSnippet()).isEqualTo("TestNameJr@gmail.com"); - } - } -} diff --git a/core/tests/coretests/src/android/app/appsearch/impl/CustomerDocumentTest.java b/core/tests/coretests/src/android/app/appsearch/impl/CustomerDocumentTest.java deleted file mode 100644 index b29483c2e3b3..000000000000 --- a/core/tests/coretests/src/android/app/appsearch/impl/CustomerDocumentTest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.appsearch.impl; - -import static com.google.common.truth.Truth.assertThat; - -import android.annotation.NonNull; -import android.app.appsearch.AppSearchDocument; - -import androidx.test.filters.SmallTest; - -import org.junit.Test; - -/** - * Tests that {@link AppSearchDocument} and {@link AppSearchDocument.Builder} are extendable by - * developers. - * - * <p>This class is intentionally in a different package than {@link AppSearchDocument} to make sure - * there are no package-private methods required for external developers to add custom types. - */ -@SmallTest -public class CustomerDocumentTest { - - private static byte[] sByteArray1 = new byte[]{(byte) 1, (byte) 2, (byte) 3}; - private static byte[] sByteArray2 = new byte[]{(byte) 4, (byte) 5, (byte) 6}; - private static AppSearchDocument sDocumentProperties1 = new AppSearchDocument - .Builder("sDocumentProperties1", "sDocumentPropertiesSchemaType1") - .build(); - private static AppSearchDocument sDocumentProperties2 = new AppSearchDocument - .Builder("sDocumentProperties2", "sDocumentPropertiesSchemaType2") - .build(); - - @Test - public void testBuildCustomerDocument() { - CustomerDocument customerDocument = new CustomerDocument.Builder("uri1") - .setScore(1) - .setCreationTimestampMillis(0) - .setProperty("longKey1", 1L, 2L, 3L) - .setProperty("doubleKey1", 1.0, 2.0, 3.0) - .setProperty("booleanKey1", true, false, true) - .setProperty("stringKey1", "test-value1", "test-value2", "test-value3") - .setProperty("byteKey1", sByteArray1, sByteArray2) - .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2) - .build(); - - assertThat(customerDocument.getUri()).isEqualTo("uri1"); - assertThat(customerDocument.getSchemaType()).isEqualTo("customerDocument"); - assertThat(customerDocument.getScore()).isEqualTo(1); - assertThat(customerDocument.getCreationTimestampMillis()).isEqualTo(0L); - assertThat(customerDocument.getPropertyLongArray("longKey1")).asList() - .containsExactly(1L, 2L, 3L); - assertThat(customerDocument.getPropertyDoubleArray("doubleKey1")).usingExactEquality() - .containsExactly(1.0, 2.0, 3.0); - assertThat(customerDocument.getPropertyBooleanArray("booleanKey1")).asList() - .containsExactly(true, false, true); - assertThat(customerDocument.getPropertyStringArray("stringKey1")).asList() - .containsExactly("test-value1", "test-value2", "test-value3"); - assertThat(customerDocument.getPropertyBytesArray("byteKey1")).asList() - .containsExactly(sByteArray1, sByteArray2); - assertThat(customerDocument.getPropertyDocumentArray("documentKey1")).asList() - .containsExactly(sDocumentProperties1, sDocumentProperties2); - } - - /** - * An example document type for test purposes, defined outside of - * {@link android.app.appsearch.AppSearch} (the way an external developer would define it). - */ - private static class CustomerDocument extends AppSearchDocument { - private CustomerDocument(AppSearchDocument document) { - super(document); - } - - public static class Builder extends AppSearchDocument.Builder<CustomerDocument.Builder> { - private Builder(@NonNull String uri) { - super(uri, "customerDocument"); - } - - @Override - public CustomerDocument build() { - return new CustomerDocument(super.build()); - } - } - } -} diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index d683041fbfdc..d9d2eea3536e 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -1264,8 +1264,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu * successfully. * * @param timeout duration in seconds or {@code 0} if user authentication must take place - * for every use of the key. {@code -1} is also accepted for legacy purposes. It is - * functionally the same as {@code 0}. + * for every use of the key. * @param type set of authentication types which can authorize use of the key. See * {@link KeyProperties}.{@code AUTH} flags. * @@ -1275,12 +1274,10 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu * @see KeyguardManager */ @NonNull - public Builder setUserAuthenticationParameters(@IntRange(from = -1) int timeout, + public Builder setUserAuthenticationParameters(@IntRange(from = 0) int timeout, @KeyProperties.AuthEnum int type) { - if (timeout < -1) { - throw new IllegalArgumentException("timeout must be -1 or larger"); - } else if (timeout == -1) { - timeout = 0; + if (timeout < 0) { + throw new IllegalArgumentException("timeout must be 0 or larger"); } mUserAuthenticationValidityDurationSeconds = timeout; mUserAuthenticationType = type; diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java index e230b7c3708b..8120a93e30e9 100644 --- a/keystore/java/android/security/keystore/KeyProtection.java +++ b/keystore/java/android/security/keystore/KeyProtection.java @@ -894,8 +894,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { * successfully. * * @param timeout duration in seconds or {@code 0} if user authentication must take place - * for every use of the key. {@code -1} is also accepted for legacy purposes. It is - * functionally the same as {@code 0}. + * for every use of the key. * @param type set of authentication types which can authorize use of the key. See * {@link KeyProperties}.{@code AUTH} flags. * @@ -905,12 +904,10 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs { * @see KeyguardManager */ @NonNull - public Builder setUserAuthenticationParameters(@IntRange(from = -1) int timeout, + public Builder setUserAuthenticationParameters(@IntRange(from = 0) int timeout, @KeyProperties.AuthEnum int type) { - if (timeout < -1) { - throw new IllegalArgumentException("timeout must be -1 or larger"); - } else if (timeout == -1) { - timeout = 0; + if (timeout < 0) { + throw new IllegalArgumentException("timeout must be 0 or larger"); } mUserAuthenticationValidityDurationSeconds = timeout; mUserAuthenticationType = type; diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 31e45558139d..6761435a8171 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -27,6 +27,7 @@ #include "DamageAccumulator.h" #include "pipeline/skia/SkiaDisplayList.h" #endif +#include "utils/FatVector.h" #include "utils/MathUtils.h" #include "utils/StringUtils.h" #include "utils/TraceUtils.h" @@ -36,7 +37,6 @@ #include <atomic> #include <sstream> #include <string> -#include <ui/FatVector.h> namespace android { namespace uirenderer { diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index c0ec2174bb35..d55e5b0ce836 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -27,8 +27,6 @@ #include <androidfw/ResourceTypes.h> -#include <ui/FatVector.h> - #include "AnimatorManager.h" #include "CanvasTransform.h" #include "Debug.h" @@ -37,6 +35,7 @@ #include "RenderProperties.h" #include "pipeline/skia/SkiaDisplayList.h" #include "pipeline/skia/SkiaLayer.h" +#include "utils/FatVector.h" #include <vector> diff --git a/libs/hwui/jni/FontFamily.cpp b/libs/hwui/jni/FontFamily.cpp index a2fef1e19328..0ce04a2437b9 100644 --- a/libs/hwui/jni/FontFamily.cpp +++ b/libs/hwui/jni/FontFamily.cpp @@ -29,9 +29,9 @@ #include <hwui/MinikinSkia.h> #include <hwui/Typeface.h> +#include <utils/FatVector.h> #include <minikin/FontFamily.h> #include <minikin/LocaleList.h> -#include <ui/FatVector.h> #include <memory> @@ -104,7 +104,7 @@ static jlong FontFamily_getFamilyReleaseFunc(CRITICAL_JNI_PARAMS) { static bool addSkTypeface(NativeFamilyBuilder* builder, sk_sp<SkData>&& data, int ttcIndex, jint weight, jint italic) { - FatVector<SkFontArguments::Axis, 2> skiaAxes; + uirenderer::FatVector<SkFontArguments::Axis, 2> skiaAxes; for (const auto& axis : builder->axes) { skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value}); } diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp index 5714cd1d0390..7e8f8d8d173c 100644 --- a/libs/hwui/jni/fonts/Font.cpp +++ b/libs/hwui/jni/fonts/Font.cpp @@ -28,8 +28,8 @@ #include <hwui/MinikinSkia.h> #include <hwui/Typeface.h> +#include <utils/FatVector.h> #include <minikin/FontFamily.h> -#include <ui/FatVector.h> #include <memory> @@ -93,7 +93,7 @@ static jlong Font_Builder_build(JNIEnv* env, jobject clazz, jlong builderPtr, jo sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize, release_global_ref, reinterpret_cast<void*>(fontRef))); - FatVector<SkFontArguments::Axis, 2> skiaAxes; + uirenderer::FatVector<SkFontArguments::Axis, 2> skiaAxes; for (const auto& axis : builder->axes) { skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value}); } diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h index d669f84c5ee2..cfc0f9b258da 100644 --- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h +++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h @@ -21,7 +21,7 @@ #include <SkCanvas.h> #include <SkDrawable.h> -#include <ui/FatVector.h> +#include <utils/FatVector.h> namespace android { namespace uirenderer { diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index 206b58f62ea7..cae3e3b5188c 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -27,6 +27,7 @@ #include "pipeline/skia/SkiaOpenGLPipeline.h" #include "pipeline/skia/SkiaVulkanPipeline.h" #include "renderstate/RenderState.h" +#include "utils/FatVector.h" #include "utils/TimeUtils.h" #include "utils/TraceUtils.h" @@ -39,8 +40,6 @@ #include <utils/Mutex.h> #include <thread> -#include <ui/FatVector.h> - namespace android { namespace uirenderer { namespace renderthread { diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index ba70afc8b8d2..a5355fc3499d 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -23,13 +23,13 @@ #include <GrContext.h> #include <GrTypes.h> #include <android/sync.h> -#include <ui/FatVector.h> #include <vk/GrVkExtensions.h> #include <vk/GrVkTypes.h> #include "Properties.h" #include "RenderThread.h" #include "renderstate/RenderState.h" +#include "utils/FatVector.h" #include "utils/TraceUtils.h" namespace android { diff --git a/libs/hwui/tests/unit/FatVectorTests.cpp b/libs/hwui/tests/unit/FatVectorTests.cpp index 6585a6249b44..8523e6c9e973 100644 --- a/libs/hwui/tests/unit/FatVectorTests.cpp +++ b/libs/hwui/tests/unit/FatVectorTests.cpp @@ -15,7 +15,7 @@ */ #include <gtest/gtest.h> -#include <ui/FatVector.h> +#include <utils/FatVector.h> #include <tests/common/TestUtils.h> diff --git a/libs/hwui/utils/FatVector.h b/libs/hwui/utils/FatVector.h new file mode 100644 index 000000000000..49f1984b779f --- /dev/null +++ b/libs/hwui/utils/FatVector.h @@ -0,0 +1,96 @@ +/* + * Copyright 2015, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_FAT_VECTOR_H +#define ANDROID_FAT_VECTOR_H + +#include "utils/Macros.h" + +#include <stddef.h> +#include <stdlib.h> +#include <utils/Log.h> +#include <type_traits> + +#include <vector> + +namespace android { +namespace uirenderer { + +template <typename T, size_t SIZE> +class InlineStdAllocator { +public: + struct Allocation { + PREVENT_COPY_AND_ASSIGN(Allocation); + + public: + Allocation(){}; + // char array instead of T array, so memory is uninitialized, with no destructors run + char array[sizeof(T) * SIZE]; + bool inUse = false; + }; + + typedef T value_type; // needed to implement std::allocator + typedef T* pointer; // needed to implement std::allocator + + explicit InlineStdAllocator(Allocation& allocation) : mAllocation(allocation) {} + InlineStdAllocator(const InlineStdAllocator& other) : mAllocation(other.mAllocation) {} + ~InlineStdAllocator() {} + + T* allocate(size_t num, const void* = 0) { + if (!mAllocation.inUse && num <= SIZE) { + mAllocation.inUse = true; + return (T*)mAllocation.array; + } else { + return (T*)malloc(num * sizeof(T)); + } + } + + void deallocate(pointer p, size_t num) { + if (p == (T*)mAllocation.array) { + mAllocation.inUse = false; + } else { + // 'free' instead of delete here - destruction handled separately + free(p); + } + } + Allocation& mAllocation; +}; + +/** + * std::vector with SIZE elements preallocated into an internal buffer. + * + * Useful for avoiding the cost of malloc in cases where only SIZE or + * fewer elements are needed in the common case. + */ +template <typename T, size_t SIZE> +class FatVector : public std::vector<T, InlineStdAllocator<T, SIZE>> { +public: + FatVector() + : std::vector<T, InlineStdAllocator<T, SIZE>>( + InlineStdAllocator<T, SIZE>(mAllocation)) { + this->reserve(SIZE); + } + + explicit FatVector(size_t capacity) : FatVector() { this->resize(capacity); } + +private: + typename InlineStdAllocator<T, SIZE>::Allocation mAllocation; +}; + +} // namespace uirenderer +} // namespace android + +#endif // ANDROID_FAT_VECTOR_H diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java index 256c5d51c421..5077e18b06e4 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java @@ -81,11 +81,6 @@ public class AssistManager { void onGestureCompletion(float velocity); /** - * Called with the Bundle from VoiceInteractionSessionListener.onSetUiHints. - */ - void processBundle(Bundle hints); - - /** * Hides any SysUI for the assistant, but _does not_ close the assistant itself. */ void hide(); diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java index f201a6fb1137..68242f0a0ac2 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java +++ b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java @@ -26,7 +26,6 @@ import android.content.Context; import android.graphics.PixelFormat; import android.metrics.LogMaker; import android.os.Build; -import android.os.Bundle; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; @@ -94,11 +93,6 @@ public class DefaultUiController implements AssistManager.UiController { } @Override // AssistManager.UiController - public void processBundle(Bundle bundle) { - Log.e(TAG, "Bundle received but handling is not implemented; ignoring"); - } - - @Override // AssistManager.UiController public void onInvocationProgress(int type, float progress) { boolean invocationWasInProgress = mInvocationInProgress; diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java index 1ae3d4f482f4..fb348f483c46 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java @@ -42,6 +42,8 @@ import android.view.WindowManagerGlobal; import java.io.PrintWriter; +import javax.inject.Inject; + /** * Handles bounds calculation for PIP on Phone and other form factors, it keeps tracking variant * state changes originated from Window Manager and is the source of truth for PiP window bounds. @@ -81,9 +83,10 @@ public class PipBoundsHandler { private boolean mIsShelfShowing; private int mShelfHeight; - public PipBoundsHandler(Context context) { + @Inject + public PipBoundsHandler(Context context, PipSnapAlgorithm pipSnapAlgorithm) { mContext = context; - mSnapAlgorithm = new PipSnapAlgorithm(context); + mSnapAlgorithm = pipSnapAlgorithm; mWindowManager = WindowManagerGlobal.getWindowManagerService(); reloadResources(); // Initialize the aspect ratio to the default aspect ratio. Don't do this in reload diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java b/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java index 6bd28c5e7221..6df6b5ae76cc 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java @@ -25,6 +25,8 @@ import android.util.Size; import java.io.PrintWriter; +import javax.inject.Inject; + /** * Calculates the snap targets and the snap position for the PIP given a position and a velocity. * All bounds are relative to the display top/left. @@ -39,6 +41,7 @@ public class PipSnapAlgorithm { private int mOrientation = Configuration.ORIENTATION_UNDEFINED; + @Inject public PipSnapAlgorithm(Context context) { Resources res = context.getResources(); mContext = context; diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index 8ada3c393222..4b97d134761e 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -41,6 +41,7 @@ import com.android.systemui.UiOffloadThread; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.pip.BasePipManager; import com.android.systemui.pip.PipBoundsHandler; +import com.android.systemui.pip.PipSnapAlgorithm; import com.android.systemui.pip.PipTaskOrganizer; import com.android.systemui.shared.recents.IPinnedStackAnimationListener; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -205,7 +206,9 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio public PipManager(Context context, BroadcastDispatcher broadcastDispatcher, DisplayController displayController, FloatingContentCoordinator floatingContentCoordinator, - DeviceConfigProxy deviceConfig) { + DeviceConfigProxy deviceConfig, + PipBoundsHandler pipBoundsHandler, + PipSnapAlgorithm pipSnapAlgorithm) { mContext = context; mActivityManager = ActivityManager.getService(); @@ -218,7 +221,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener); final IActivityTaskManager activityTaskManager = ActivityTaskManager.getService(); - mPipBoundsHandler = new PipBoundsHandler(context); + mPipBoundsHandler = pipBoundsHandler; mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler); mPipTaskOrganizer.registerPipTransitionCallback(this); mInputConsumerController = InputConsumerController.getPipInputConsumer(); @@ -227,7 +230,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio mInputConsumerController); mTouchHandler = new PipTouchHandler(context, mActivityManager, activityTaskManager, mMenuController, mInputConsumerController, mPipBoundsHandler, mPipTaskOrganizer, - floatingContentCoordinator, deviceConfig); + floatingContentCoordinator, deviceConfig, pipSnapAlgorithm); mAppOpsListener = new PipAppOpsListener(context, mActivityManager, mTouchHandler.getMotionHelper()); displayController.addDisplayChangingController(mRotationController); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index c3212b8b8078..90db91a7a29e 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -166,7 +166,8 @@ public class PipTouchHandler { PipBoundsHandler pipBoundsHandler, PipTaskOrganizer pipTaskOrganizer, FloatingContentCoordinator floatingContentCoordinator, - DeviceConfigProxy deviceConfig) { + DeviceConfigProxy deviceConfig, + PipSnapAlgorithm pipSnapAlgorithm) { // Initialize the Pip input consumer mContext = context; mActivityManager = activityManager; @@ -174,7 +175,7 @@ public class PipTouchHandler { mMenuController = menuController; mMenuController.addListener(new PipMenuListener()); mDismissViewController = new PipDismissViewController(context); - mSnapAlgorithm = new PipSnapAlgorithm(mContext); + mSnapAlgorithm = pipSnapAlgorithm; mFlingAnimationUtils = new FlingAnimationUtils(context.getResources().getDisplayMetrics(), 2.5f); mGesture = new DefaultPipTouchGesture(); diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index f28c3f6e71ec..ca44f6b364a7 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -228,13 +228,14 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio } @Inject - public PipManager(Context context, BroadcastDispatcher broadcastDispatcher) { + public PipManager(Context context, BroadcastDispatcher broadcastDispatcher, + PipBoundsHandler pipBoundsHandler) { if (mInitialized) { return; } mInitialized = true; mContext = context; - mPipBoundsHandler = new PipBoundsHandler(context); + mPipBoundsHandler = pipBoundsHandler; mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler); mPipTaskOrganizer.registerPipTransitionCallback(this); mActivityTaskManager = ActivityTaskManager.getService(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java index 3b00684786b8..b12db2b44e3d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java @@ -58,7 +58,7 @@ public class PipBoundsHandlerTest extends SysuiTestCase { @Before public void setUp() throws Exception { initializeMockResources(); - mPipBoundsHandler = new PipBoundsHandler(mContext); + mPipBoundsHandler = new PipBoundsHandler(mContext, new PipSnapAlgorithm(mContext)); mPipBoundsHandler.onDisplayInfoChanged(mDefaultDisplayInfo); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java index 2c9fd2c64291..5d0349dbbb60 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java @@ -64,6 +64,7 @@ import com.android.systemui.statusbar.notification.collection.inflation.Notifica import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; +import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag; import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent; import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; @@ -76,6 +77,7 @@ import com.android.systemui.util.time.FakeSystemClock; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -84,12 +86,11 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; -import java.util.concurrent.CountDownLatch; - /** * Functional tests for notification inflation from {@link NotificationEntryManager}. */ @SmallTest +@Ignore("Flaking") @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) public class NotificationEntryManagerInflationTest extends SysuiTestCase { @@ -131,7 +132,6 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { private NotificationEntryManager mEntryManager; private NotificationRowBinderImpl mRowBinder; private Handler mHandler; - private CountDownLatch mCountDownLatch; @Before public void setUp() { @@ -305,7 +305,9 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { verify(mEntryListener).onPendingEntryAdded(entryCaptor.capture()); NotificationEntry entry = entryCaptor.getValue(); - waitForInflation(); + // Wait for inflation + // row inflation, system notification, remote views, contracted view + waitForMessages(4); // THEN the notification has its row inflated assertNotNull(entry.getRow()); @@ -332,7 +334,7 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { NotificationEntry.class); verify(mEntryListener).onPendingEntryAdded(entryCaptor.capture()); NotificationEntry entry = entryCaptor.getValue(); - waitForInflation(); + waitForMessages(4); Mockito.reset(mEntryListener); Mockito.reset(mPresenter); @@ -340,7 +342,9 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { // WHEN the notification is updated mEntryManager.updateNotification(mSbn, mRankingMap); - waitForInflation(); + // Wait for inflation + // remote views, contracted view + waitForMessages(2); // THEN the notification has its row and inflated assertNotNull(entry.getRow()); @@ -353,31 +357,32 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { verify(mPresenter).updateNotificationViews(); } - private void waitForInflation() { + /** + * Wait for a certain number of messages to finish before continuing, timing out if they never + * occur. + * + * As part of the inflation pipeline, the main thread is forced to deal with several callbacks + * due to the nature of the API used (generally because they're {@link android.os.AsyncTask} + * callbacks). In order, these are + * + * 1) Callback after row inflation. See {@link RowInflaterTask}. + * 2) Callback checking if row is system notification. See + * {@link ExpandableNotificationRow#setEntry} + * 3) Callback after remote views are created. See + * {@link NotificationContentInflater.AsyncInflationTask}. + * 4-6) Callback after each content view is inflated/rebound from remote view. See + * {@link NotificationContentInflater#applyRemoteView} and {@link InflationFlag}. + * + * Depending on the test, only some of these will be necessary. For example, generally, not + * every content view is inflated or the row may not be inflated if one already exists. + * + * Currently, the burden is on the developer to figure these out until we have a much more + * test-friendly way of executing inflation logic (i.e. pass in an executor). + */ + private void waitForMessages(int numMessages) { mHandler.postDelayed(TIMEOUT_RUNNABLE, TIMEOUT_TIME); - final CountDownLatch latch = new CountDownLatch(1); - NotificationEntryListener inflationListener = new NotificationEntryListener() { - @Override - public void onEntryInflated(NotificationEntry entry) { - latch.countDown(); - } - - @Override - public void onEntryReinflated(NotificationEntry entry) { - latch.countDown(); - } - - @Override - public void onInflationError(StatusBarNotification notification, Exception exception) { - latch.countDown(); - } - }; - mEntryManager.addNotificationEntryListener(inflationListener); - while (latch.getCount() != 0) { - TestableLooper.get(this).processMessages(1); - } + TestableLooper.get(this).processMessages(numMessages); mHandler.removeCallbacks(TIMEOUT_RUNNABLE); - mEntryManager.removeNotificationEntryListener(inflationListener); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index fbcb0102eb47..9058ac451455 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -81,6 +81,8 @@ import static android.os.Process.removeAllProcessGroups; import static android.os.Process.sendSignal; import static android.os.Process.setThreadPriority; import static android.os.Process.setThreadScheduler; +import static android.permission.PermissionManager.KILL_APP_REASON_GIDS_CHANGED; +import static android.permission.PermissionManager.KILL_APP_REASON_PERMISSIONS_REVOKED; import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES; import static android.provider.Settings.Global.DEBUG_APP; import static android.provider.Settings.Global.NETWORK_ACCESS_TIMEOUT_MS; @@ -4243,7 +4245,8 @@ public class ActivityManagerService extends IActivityManager.Stub } synchronized (this) { mProcessList.killPackageProcessesLocked(packageName, appId, targetUserId, - ProcessList.SERVICE_ADJ, "kill background"); + ProcessList.SERVICE_ADJ, ApplicationExitInfo.REASON_USER_REQUESTED, + ApplicationExitInfo.SUBREASON_UNKNOWN, "kill background"); } } } finally { @@ -4269,7 +4272,10 @@ public class ActivityManagerService extends IActivityManager.Stub // because this method is also used to simulate low memory. mAllowLowerMemLevel = true; mProcessList.killPackageProcessesLocked(null /* packageName */, -1 /* appId */, - UserHandle.USER_ALL, ProcessList.CACHED_APP_MIN_ADJ, "kill all background"); + UserHandle.USER_ALL, ProcessList.CACHED_APP_MIN_ADJ, + ApplicationExitInfo.REASON_USER_REQUESTED, + ApplicationExitInfo.SUBREASON_UNKNOWN, + "kill all background"); doLowMemReportIfNeededLocked(null); } @@ -4757,6 +4763,9 @@ public class ActivityManagerService extends IActivityManager.Stub boolean didSomething = mProcessList.killPackageProcessesLocked(packageName, appId, userId, ProcessList.INVALID_ADJ, callerWillRestart, false /* allowRestart */, doit, evenPersistent, true /* setRemoved */, + packageName == null ? ApplicationExitInfo.REASON_USER_STOPPED + : ApplicationExitInfo.REASON_USER_REQUESTED, + ApplicationExitInfo.SUBREASON_UNKNOWN, packageName == null ? ("stop user " + userId) : ("stop " + packageName)); didSomething |= @@ -4820,7 +4829,10 @@ public class ActivityManagerService extends IActivityManager.Stub @GuardedBy("this") private final void processContentProviderPublishTimedOutLocked(ProcessRecord app) { cleanupAppInLaunchingProvidersLocked(app, true); - mProcessList.removeProcessLocked(app, false, true, "timeout publishing content providers"); + mProcessList.removeProcessLocked(app, false, true, + ApplicationExitInfo.REASON_INITIALIZATION_FAILURE, + ApplicationExitInfo.SUBREASON_UNKNOWN, + "timeout publishing content providers"); } @GuardedBy("this") @@ -4925,7 +4937,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (pid > 0 && pid != MY_PID) { killProcessQuiet(pid); //TODO: killProcessGroup(app.info.uid, pid); - mProcessList.noteAppKill(app, ApplicationExitInfo.REASON_OTHER, + mProcessList.noteAppKill(app, ApplicationExitInfo.REASON_INITIALIZATION_FAILURE, ApplicationExitInfo.SUBREASON_UNKNOWN, "attach failed"); } else { try { @@ -9054,7 +9066,8 @@ public class ActivityManagerService extends IActivityManager.Stub } int adj = proc.setAdj; if (adj >= worstType && !proc.killedByAm) { - proc.kill(reason, ApplicationExitInfo.REASON_OTHER, true); + proc.kill(reason, ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.SUBREASON_KILL_PID, true); killed = true; } } @@ -9068,10 +9081,17 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { final long identity = Binder.clearCallingIdentity(); try { + boolean permissionChange = KILL_APP_REASON_PERMISSIONS_REVOKED.equals(reason) + || KILL_APP_REASON_GIDS_CHANGED.equals(reason); mProcessList.killPackageProcessesLocked(null /* packageName */, appId, userId, ProcessList.PERSISTENT_PROC_ADJ, false /* callerWillRestart */, true /* callerWillRestart */, true /* doit */, true /* evenPersistent */, - false /* setRemoved */, reason != null ? reason : "kill uid"); + false /* setRemoved */, + permissionChange ? ApplicationExitInfo.REASON_PERMISSION_CHANGE + : ApplicationExitInfo.REASON_OTHER, + permissionChange ? ApplicationExitInfo.SUBREASON_UNKNOWN + : ApplicationExitInfo.SUBREASON_KILL_UID, + reason != null ? reason : "kill uid"); } finally { Binder.restoreCallingIdentity(identity); } @@ -9396,7 +9416,10 @@ public class ActivityManagerService extends IActivityManager.Stub for (int i=procsToKill.size()-1; i>=0; i--) { ProcessRecord proc = procsToKill.get(i); Slog.i(TAG, "Removing system update proc: " + proc); - mProcessList.removeProcessLocked(proc, true, false, "system update done"); + mProcessList.removeProcessLocked(proc, true, false, + ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.SUBREASON_SYSTEM_UPDATE_DONE, + "system update done"); } } @@ -14400,7 +14423,8 @@ public class ActivityManagerService extends IActivityManager.Stub + cpr.name.flattenToShortString() + " in dying proc " + (proc != null ? proc.processName : "??") + " (adj " + (proc != null ? proc.setAdj : "??") + ")", - ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.REASON_DEPENDENCY_DIED, + ApplicationExitInfo.SUBREASON_UNKNOWN, true); } } else if (capp.thread != null && conn.provider.provider != null) { @@ -15892,7 +15916,10 @@ public class ActivityManagerService extends IActivityManager.Stub -1); mProcessList.killPackageProcessesLocked(ssp, UserHandle.getAppId(extraUid), - userId, ProcessList.INVALID_ADJ, "change " + ssp); + userId, ProcessList.INVALID_ADJ, + ApplicationExitInfo.REASON_USER_REQUESTED, + ApplicationExitInfo.SUBREASON_UNKNOWN, + "change " + ssp); } cleanupDisabledPackageComponentsLocked(ssp, userId, intent.getStringArrayExtra( @@ -18622,7 +18649,10 @@ public class ActivityManagerService extends IActivityManager.Stub final int N = procs.size(); for (int i = 0; i < N; i++) { - mProcessList.removeProcessLocked(procs.get(i), false, true, "kill all fg"); + mProcessList.removeProcessLocked(procs.get(i), false, true, + ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.SUBREASON_KILL_ALL_FG, + "kill all fg"); } } } @@ -18844,7 +18874,8 @@ public class ActivityManagerService extends IActivityManager.Stub final ProcessRecord pr = (ProcessRecord) wpc.mOwner; if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND && pr.curReceivers.isEmpty()) { - pr.kill("remove task", ApplicationExitInfo.REASON_OTHER, true); + pr.kill("remove task", ApplicationExitInfo.REASON_USER_REQUESTED, + ApplicationExitInfo.SUBREASON_UNKNOWN, true); } else { // We delay killing processes that are not in the background or running a // receiver. @@ -18861,7 +18892,7 @@ public class ActivityManagerService extends IActivityManager.Stub true /* keepIfLarge */); if (proc != null) { mProcessList.removeProcessLocked(proc, false /* callerWillRestart */, - true /* allowRestart */, reason); + true /* allowRestart */, ApplicationExitInfo.REASON_OTHER, reason); } } } @@ -19547,7 +19578,10 @@ public class ActivityManagerService extends IActivityManager.Stub try { synchronized(this) { mProcessList.killPackageProcessesLocked(packageName, UserHandle.getAppId(pkgUid), - userId, ProcessList.FOREGROUND_APP_ADJ, "dep: " + packageName); + userId, ProcessList.FOREGROUND_APP_ADJ, + ApplicationExitInfo.REASON_DEPENDENCY_DIED, + ApplicationExitInfo.SUBREASON_UNKNOWN, + "dep: " + packageName); } } finally { Binder.restoreCallingIdentity(callingId); diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 789f7199948d..b1fc0296518b 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -395,7 +395,7 @@ class AppErrors { () -> { synchronized (mService) { killAppImmediateLocked(p, ApplicationExitInfo.REASON_OTHER, - ApplicationExitInfo.SUBREASON_UNKNOWN, + ApplicationExitInfo.SUBREASON_INVALID_STATE, "forced", "killed for invalid state"); } }, @@ -510,8 +510,8 @@ class AppErrors { stopReportingCrashesLocked(r); } if (res == AppErrorDialog.RESTART) { - mService.mProcessList.removeProcessLocked(r, false, true, "crash", - ApplicationExitInfo.REASON_CRASH); + mService.mProcessList.removeProcessLocked(r, false, true, + ApplicationExitInfo.REASON_CRASH, "crash"); if (taskId != INVALID_TASK_ID) { try { mService.startActivityFromRecents(taskId, @@ -529,8 +529,8 @@ class AppErrors { // Kill it with fire! mService.mAtmInternal.onHandleAppCrash(r.getWindowProcessController()); if (!r.isPersistent()) { - mService.mProcessList.removeProcessLocked(r, false, false, "crash", - ApplicationExitInfo.REASON_CRASH); + mService.mProcessList.removeProcessLocked(r, false, false, + ApplicationExitInfo.REASON_CRASH, "crash"); mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */); } } finally { @@ -747,8 +747,8 @@ class AppErrors { // Don't let services in this process be restarted and potentially // annoy the user repeatedly. Unless it is persistent, since those // processes run critical code. - mService.mProcessList.removeProcessLocked(app, false, tryAgain, "crash", - ApplicationExitInfo.REASON_CRASH); + mService.mProcessList.removeProcessLocked(app, false, tryAgain, + ApplicationExitInfo.REASON_CRASH, "crash"); mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */); if (!showBackground) { return false; diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java index cba6b92bf440..a09aa64476c1 100644 --- a/services/core/java/com/android/server/am/AppExitInfoTracker.java +++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java @@ -348,6 +348,7 @@ public final class AppExitInfoTracker { } else { // always override the existing info since we are now more informational. info.setReason(raw.getReason()); + info.setSubReason(raw.getSubReason()); info.setStatus(0); info.setTimestamp(System.currentTimeMillis()); info.setDescription(raw.getDescription()); diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index e7b467adf487..aa37b4accc40 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -840,7 +840,8 @@ public final class OomAdjuster { // definition not re-use the same process again, and it is // good to avoid having whatever code was running in them // left sitting around after no longer needed. - app.kill("isolated not needed", ApplicationExitInfo.REASON_OTHER, true); + app.kill("isolated not needed", ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.SUBREASON_ISOLATED_NOT_NEEDED, true); } else { // Keeping this process, update its uid. updateAppUidRecLocked(app); @@ -2166,7 +2167,8 @@ public final class OomAdjuster { } if (app.waitingToKill != null && app.curReceivers.isEmpty() && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) { - app.kill(app.waitingToKill, ApplicationExitInfo.REASON_OTHER, true); + app.kill(app.waitingToKill, ApplicationExitInfo.REASON_USER_REQUESTED, + ApplicationExitInfo.SUBREASON_UNKNOWN, true); success = false; } else { int processGroup; diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 3a5447edfdf0..a9d18e05e350 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -2378,7 +2378,7 @@ public final class ProcessList { killProcessQuiet(pid); Process.killProcessGroup(app.uid, app.pid); noteAppKill(app, ApplicationExitInfo.REASON_OTHER, - ApplicationExitInfo.SUBREASON_UNKNOWN, reason); + ApplicationExitInfo.SUBREASON_INVALID_START, reason); return false; } mService.mBatteryStatsService.noteProcessStart(app.processName, app.info.uid); @@ -2463,7 +2463,7 @@ public final class ProcessList { killProcessQuiet(app.pid); ProcessList.killProcessGroup(app.uid, app.pid); noteAppKill(app, ApplicationExitInfo.REASON_OTHER, - ApplicationExitInfo.SUBREASON_UNKNOWN, "hasn't been killed"); + ApplicationExitInfo.SUBREASON_REMOVE_LRU, "hasn't been killed"); } else { app.pendingStart = false; } @@ -2481,10 +2481,11 @@ public final class ProcessList { @GuardedBy("mService") boolean killPackageProcessesLocked(String packageName, int appId, int userId, int minOomAdj, - String reason) { + int reasonCode, int subReason, String reason) { return killPackageProcessesLocked(packageName, appId, userId, minOomAdj, false /* callerWillRestart */, true /* allowRestart */, true /* doit */, - false /* evenPersistent */, false /* setRemoved */, reason); + false /* evenPersistent */, false /* setRemoved */, reasonCode, + subReason, reason); } @GuardedBy("mService") @@ -2517,7 +2518,8 @@ public final class ProcessList { @GuardedBy("mService") final boolean killPackageProcessesLocked(String packageName, int appId, int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart, - boolean doit, boolean evenPersistent, boolean setRemoved, String reason) { + boolean doit, boolean evenPersistent, boolean setRemoved, int reasonCode, + int subReason, String reason) { ArrayList<ProcessRecord> procs = new ArrayList<>(); // Remove all processes this package may have touched: all with the @@ -2589,7 +2591,8 @@ public final class ProcessList { int N = procs.size(); for (int i=0; i<N; i++) { - removeProcessLocked(procs.get(i), callerWillRestart, allowRestart, reason); + removeProcessLocked(procs.get(i), callerWillRestart, allowRestart, + reasonCode, subReason, reason); } killAppZygotesLocked(packageName, appId, userId, false /* force */); mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_END); @@ -2598,13 +2601,14 @@ public final class ProcessList { @GuardedBy("mService") boolean removeProcessLocked(ProcessRecord app, - boolean callerWillRestart, boolean allowRestart, String reason) { - return removeProcessLocked(app, callerWillRestart, allowRestart, reason, - ApplicationExitInfo.REASON_OTHER); + boolean callerWillRestart, boolean allowRestart, int reasonCode, String reason) { + return removeProcessLocked(app, callerWillRestart, allowRestart, reasonCode, + ApplicationExitInfo.SUBREASON_UNKNOWN, reason); } - boolean removeProcessLocked(ProcessRecord app, - boolean callerWillRestart, boolean allowRestart, String reason, int reasonCode) { + @GuardedBy("mService") + boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart, + boolean allowRestart, int reasonCode, int subReason, String reason) { final String name = app.processName; final int uid = app.uid; if (DEBUG_PROCESSES) Slog.d(TAG_PROCESSES, @@ -2640,7 +2644,7 @@ public final class ProcessList { needRestart = true; } } - app.kill(reason, reasonCode, true); + app.kill(reason, reasonCode, subReason, true); mService.handleAppDiedLocked(app, willRestart, allowRestart); if (willRestart) { removeLruProcessLocked(app); @@ -2838,7 +2842,8 @@ public final class ProcessList { final int N = procs.size(); for (int i = 0; i < N; i++) { - removeProcessLocked(procs.get(i), false, true, "kill all background except"); + removeProcessLocked(procs.get(i), false, true, ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.SUBREASON_KILL_ALL_BG_EXCEPT, "kill all background except"); } } @@ -4004,7 +4009,8 @@ public final class ProcessList { return false; } - app.kill(reason, ApplicationExitInfo.REASON_OTHER, true); + app.kill(reason, ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.SUBREASON_IMPERCEPTIBLE, true); if (!app.isolated) { mLastProcessKillTimes.put(app.processName, app.uid, SystemClock.uptimeMillis()); diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 85f36aab0be7..45c3aebe8bd5 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -40,6 +40,8 @@ import static android.app.AppOpsManager.OP_NONE; import static android.app.AppOpsManager.OP_PLAY_AUDIO; import static android.app.AppOpsManager.OP_RECORD_AUDIO; import static android.app.AppOpsManager.OpEventProxyInfo; +import static android.app.AppOpsManager.SAMPLING_STRATEGY_RARELY_USED; +import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM; import static android.app.AppOpsManager.UID_STATE_BACKGROUND; import static android.app.AppOpsManager.UID_STATE_CACHED; import static android.app.AppOpsManager.UID_STATE_FOREGROUND; @@ -60,8 +62,6 @@ import static android.content.Intent.ACTION_PACKAGE_REMOVED; import static android.content.Intent.EXTRA_REPLACING; import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS; import static android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP; -import static android.util.StatsLogInternal.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__RARELY_USED; -import static android.util.StatsLogInternal.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__UNIFORM; import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS; @@ -5683,7 +5683,7 @@ public class AppOpsService extends IAppOpsService.Stub { if (mRarelyUsedPackages.contains(packageName)) { mRarelyUsedPackages.remove(packageName); if (ThreadLocalRandom.current().nextFloat() < 0.5f) { - mSamplingStrategy = RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__RARELY_USED; + mSamplingStrategy = SAMPLING_STRATEGY_RARELY_USED; resampleAppOpForPackageLocked(packageName); } } @@ -5692,7 +5692,7 @@ public class AppOpsService extends IAppOpsService.Stub { /** Resamples package and appop to watch from the list provided. */ private void resamplePackageAndAppOpLocked(@NonNull List<String> packageNames) { if (!packageNames.isEmpty()) { - mSamplingStrategy = RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__UNIFORM; + mSamplingStrategy = SAMPLING_STRATEGY_UNIFORM; resampleAppOpForPackageLocked(packageNames.get( ThreadLocalRandom.current().nextInt(packageNames.size()))); } diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java index 49a2901d4f9f..1292f6c121b4 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java @@ -203,15 +203,18 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware checkPreemptPermissions(); // Input validation (always valid). - synchronized (this) { - // State validation (always valid). - - // From here on, every exception isn't client's fault. - try { - mDelegate.setExternalCaptureState(active); - } catch (Exception e) { - throw handleException(e); - } + // State validation (always valid). + + // Normally, we would acquire a lock here. However, we do not access any state here so it + // is safe to not lock. This call is typically done from a different context than all the + // other calls and may result in a deadlock if we lock here (between the audio server and + // the system server). + + // From here on, every exception isn't client's fault. + try { + mDelegate.setExternalCaptureState(active); + } catch (Exception e) { + throw handleException(e); } } diff --git a/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java b/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java index cddcabe80f33..06c2354c7a7d 100644 --- a/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java +++ b/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java @@ -30,6 +30,8 @@ import android.os.UserHandle; import android.util.Log; import android.util.Slog; +import com.android.internal.annotations.VisibleForTesting; + import java.util.ArrayList; import java.util.Collections; @@ -140,7 +142,8 @@ final class TvRemoteProviderWatcher { } } - private boolean verifyServiceTrusted(ServiceInfo serviceInfo) { + @VisibleForTesting + boolean verifyServiceTrusted(ServiceInfo serviceInfo) { if (serviceInfo.permission == null || !serviceInfo.permission.equals( Manifest.permission.BIND_TV_REMOTE_SERVICE)) { // If the service does not require this permission then any app could diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 107b0a1c2da8..b019e9dd03ba 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -294,8 +294,6 @@ public final class SystemServer { "com.android.server.DeviceIdleController"; private static final String BLOB_STORE_MANAGER_SERVICE_CLASS = "com.android.server.blob.BlobStoreManagerService"; - private static final String APP_SEARCH_MANAGER_SERVICE_CLASS = - "com.android.server.appsearch.AppSearchManagerService"; private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector"; @@ -2178,10 +2176,6 @@ public final class SystemServer { mSystemServiceManager.startBootPhase(t, SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY); t.traceEnd(); - t.traceBegin("AppSearchManagerService"); - mSystemServiceManager.startService(APP_SEARCH_MANAGER_SERVICE_CLASS); - t.traceEnd(); - ConcurrentUtils.waitForFutureNoInterrupt(mBlobStoreServiceStart, START_BLOB_STORE_SERVICE); diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp index d148c21b7d6e..449e75cd11a0 100644 --- a/services/tests/servicestests/Android.bp +++ b/services/tests/servicestests/Android.bp @@ -43,7 +43,6 @@ android_test { "platformprotosnano", "hamcrest-library", "servicestests-utils", - "service-appsearch", "service-jobscheduler", "service-permission", // TODO: remove once Android migrates to JUnit 4.12, diff --git a/services/tests/servicestests/src/com/android/server/appsearch/impl/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/impl/AppSearchImplTest.java deleted file mode 100644 index 34ade818f062..000000000000 --- a/services/tests/servicestests/src/com/android/server/appsearch/impl/AppSearchImplTest.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.server.appsearch.impl; - -import static com.google.common.truth.Truth.assertThat; - -import static org.testng.Assert.expectThrows; - -import android.annotation.UserIdInt; -import android.content.Context; -import android.os.UserHandle; - -import androidx.test.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; - -import com.google.android.icing.proto.IndexingConfig; -import com.google.android.icing.proto.PropertyConfigProto; -import com.google.android.icing.proto.SchemaProto; -import com.google.android.icing.proto.SchemaTypeConfigProto; -import com.google.android.icing.proto.TermMatchType; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -public class AppSearchImplTest { - private final Context mContext = InstrumentationRegistry.getContext(); - private final @UserIdInt int mUserId = UserHandle.getCallingUserId(); - - @Test - public void testRewriteSchemaTypes() { - SchemaProto inSchema = SchemaProto.newBuilder() - .addTypes(SchemaTypeConfigProto.newBuilder() - .setSchemaType("TestType") - .addProperties(PropertyConfigProto.newBuilder() - .setPropertyName("subject") - .setDataType(PropertyConfigProto.DataType.Code.STRING) - .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL) - .setIndexingConfig( - IndexingConfig.newBuilder() - .setTokenizerType( - IndexingConfig.TokenizerType.Code.PLAIN) - .setTermMatchType(TermMatchType.Code.PREFIX) - .build() - ).build() - ).addProperties(PropertyConfigProto.newBuilder() - .setPropertyName("link") - .setDataType(PropertyConfigProto.DataType.Code.DOCUMENT) - .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL) - .setSchemaType("RefType") - .build() - ).build() - ).build(); - - SchemaProto expectedSchema = SchemaProto.newBuilder() - .addTypes(SchemaTypeConfigProto.newBuilder() - .setSchemaType("com.android.server.appsearch.impl@42:TestType") - .addProperties(PropertyConfigProto.newBuilder() - .setPropertyName("subject") - .setDataType(PropertyConfigProto.DataType.Code.STRING) - .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL) - .setIndexingConfig( - IndexingConfig.newBuilder() - .setTokenizerType( - IndexingConfig.TokenizerType.Code.PLAIN) - .setTermMatchType(TermMatchType.Code.PREFIX) - .build() - ).build() - ).addProperties(PropertyConfigProto.newBuilder() - .setPropertyName("link") - .setDataType(PropertyConfigProto.DataType.Code.DOCUMENT) - .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL) - .setSchemaType("com.android.server.appsearch.impl@42:RefType") - .build() - ).build() - ).build(); - - AppSearchImpl impl = new AppSearchImpl(mContext, mUserId); - SchemaProto.Builder actualSchema = inSchema.toBuilder(); - impl.rewriteSchemaTypes("com.android.server.appsearch.impl@42:", actualSchema); - - assertThat(actualSchema.build()).isEqualTo(expectedSchema); - } - - @Test - public void testPackageNotFound() { - AppSearchImpl impl = new AppSearchImpl(mContext, mUserId); - IllegalStateException e = expectThrows( - IllegalStateException.class, - () -> impl.setSchema( - /*callingUid=*/Integer.MAX_VALUE, - SchemaProto.getDefaultInstance(), - /*forceOverride=*/false)); - assertThat(e).hasMessageThat().contains("Failed to look up package name"); - } -} diff --git a/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java b/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java deleted file mode 100644 index 07b655652fac..000000000000 --- a/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.server.appsearch.impl; - -import static com.google.common.truth.Truth.assertThat; - -import androidx.test.runner.AndroidJUnit4; - -import com.google.android.icing.proto.DocumentProto; -import com.google.android.icing.proto.PropertyProto; -import com.google.android.icing.proto.SearchResultProto; -import com.google.android.icing.proto.StatusProto; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.ArrayList; -import java.util.List; - -@RunWith(AndroidJUnit4.class) -public class FakeIcingTest { - @Test - public void query() { - FakeIcing icing = new FakeIcing(); - icing.put(createDoc("uri:cat", "The cat said meow")); - icing.put(createDoc("uri:dog", "The dog said woof")); - - assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat"); - assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog"); - assertThat(queryGetUris(icing, "fred")).isEmpty(); - } - - @Test - public void queryNorm() { - FakeIcing icing = new FakeIcing(); - icing.put(createDoc("uri:cat", "The cat said meow")); - icing.put(createDoc("uri:dog", "The dog said woof")); - - assertThat(queryGetUris(icing, "the")).containsExactly("uri:cat", "uri:dog"); - assertThat(queryGetUris(icing, "The")).containsExactly("uri:cat", "uri:dog"); - assertThat(queryGetUris(icing, "tHe")).containsExactly("uri:cat", "uri:dog"); - } - - @Test - public void get() { - DocumentProto cat = createDoc("uri:cat", "The cat said meow"); - FakeIcing icing = new FakeIcing(); - icing.put(cat); - assertThat(icing.get("uri:cat")).isEqualTo(cat); - } - - @Test - public void replace() { - DocumentProto cat = createDoc("uri:cat", "The cat said meow"); - DocumentProto dog = createDoc("uri:dog", "The dog said woof"); - - FakeIcing icing = new FakeIcing(); - icing.put(cat); - icing.put(dog); - - assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat"); - assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog"); - assertThat(icing.get("uri:cat")).isEqualTo(cat); - - // Replace - DocumentProto cat2 = createDoc("uri:cat", "The cat said purr"); - DocumentProto bird = createDoc("uri:bird", "The cat said tweet"); - icing.put(cat2); - icing.put(bird); - - assertThat(queryGetUris(icing, "meow")).isEmpty(); - assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog", "uri:bird"); - assertThat(icing.get("uri:cat")).isEqualTo(cat2); - } - - @Test - public void delete() { - DocumentProto cat = createDoc("uri:cat", "The cat said meow"); - DocumentProto dog = createDoc("uri:dog", "The dog said woof"); - - FakeIcing icing = new FakeIcing(); - icing.put(cat); - icing.put(dog); - - assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat"); - assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog"); - assertThat(icing.get("uri:cat")).isEqualTo(cat); - - // Delete - icing.delete("uri:cat"); - icing.delete("uri:notreal"); - - assertThat(queryGetUris(icing, "meow")).isEmpty(); - assertThat(queryGetUris(icing, "said")).containsExactly("uri:dog"); - assertThat(icing.get("uri:cat")).isNull(); - } - - private static DocumentProto createDoc(String uri, String body) { - return DocumentProto.newBuilder() - .setUri(uri) - .addProperties(PropertyProto.newBuilder().addStringValues(body)) - .build(); - } - - private static List<String> queryGetUris(FakeIcing icing, String term) { - List<String> uris = new ArrayList<>(); - SearchResultProto results = icing.query(term); - assertThat(results.getStatus().getCode()).isEqualTo(StatusProto.Code.OK); - for (SearchResultProto.ResultProto result : results.getResultsList()) { - uris.add(result.getDocument().getUri()); - } - return uris; - } -} diff --git a/services/tests/servicestests/src/com/android/server/tv/TvRemoteProviderWatcherTest.java b/services/tests/servicestests/src/com/android/server/tv/TvRemoteProviderWatcherTest.java new file mode 100644 index 000000000000..0a2bb620eb11 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/tv/TvRemoteProviderWatcherTest.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.tv; + +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.when; +import static org.mockito.hamcrest.MockitoHamcrest.argThat; + +import android.Manifest; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.ServiceInfo; +import android.content.res.Resources; +import android.os.Looper; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +public class TvRemoteProviderWatcherTest { + private static final String TV_REMOTE_SERVICE_PACKAGE_NAME = + "com.google.android.tv.remote.service"; + + @Mock + Context mMockContext; + @Mock + PackageManager mMockPackageManager; + @Mock + Resources mMockResources; + + private TvRemoteProviderWatcher mTvRemoteProviderWatcher; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + if (Looper.myLooper() == null) { + Looper.prepare(); + } + + when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager); + when(mMockContext.getResources()).thenReturn(mMockResources); + + when(mMockResources.getString(com.android.internal.R.string.config_tvRemoteServicePackage)) + .thenReturn(TV_REMOTE_SERVICE_PACKAGE_NAME); + + + when(mMockPackageManager.checkPermission( + argThat(not(Manifest.permission.TV_VIRTUAL_REMOTE_CONTROLLER)), + anyString())).thenReturn( + PackageManager.PERMISSION_DENIED); + + when(mMockPackageManager.checkPermission( + anyString(), + argThat(not(TV_REMOTE_SERVICE_PACKAGE_NAME)))).thenReturn( + PackageManager.PERMISSION_DENIED); + + when(mMockPackageManager.checkPermission(Manifest.permission.TV_VIRTUAL_REMOTE_CONTROLLER, + TV_REMOTE_SERVICE_PACKAGE_NAME)).thenReturn(PackageManager.PERMISSION_GRANTED); + + mTvRemoteProviderWatcher = new TvRemoteProviderWatcher(mMockContext, new Object()); + } + + @Test + public void tvServiceIsTrusted() { + assertTrue(mTvRemoteProviderWatcher.verifyServiceTrusted(createTvServiceInfo())); + } + + @Test + public void permissionIsRequired() { + ServiceInfo serviceInfo = createTvServiceInfo(); + serviceInfo.permission = null; + + assertFalse(mTvRemoteProviderWatcher.verifyServiceTrusted(serviceInfo)); + } + + @Test + public void permissionMustBeBindRemote() { + ServiceInfo serviceInfo = createTvServiceInfo(); + serviceInfo.permission = Manifest.permission.BIND_TV_INPUT; + assertFalse(mTvRemoteProviderWatcher.verifyServiceTrusted(serviceInfo)); + } + + @Test + public void packageNameMustMatch() { + ServiceInfo serviceInfo = createTvServiceInfo(); + serviceInfo.packageName = "some.random.package"; + assertFalse(mTvRemoteProviderWatcher.verifyServiceTrusted(serviceInfo)); + } + + @Test + public void packageManagerPermissionIsRequired() { + reset(mMockPackageManager); + when(mMockPackageManager.checkPermission(anyString(), anyString())).thenReturn( + PackageManager.PERMISSION_DENIED); + + assertFalse(mTvRemoteProviderWatcher.verifyServiceTrusted(createTvServiceInfo())); + } + + @Test + public void whitelistingPackageNameIsRequired() { + reset(mMockResources); + when(mMockResources.getString(anyInt())).thenReturn(""); + + // Create a new watcher, as the resources are read in the constructor of the class + if (Looper.myLooper() == null) { + Looper.prepare(); + } + + TvRemoteProviderWatcher watcher = + new TvRemoteProviderWatcher(mMockContext, new Object()); + assertFalse(watcher.verifyServiceTrusted(createTvServiceInfo())); + } + + private ServiceInfo createTvServiceInfo() { + ServiceInfo serviceInfo = new ServiceInfo(); + + serviceInfo.name = "ATV Remote Service"; + serviceInfo.packageName = TV_REMOTE_SERVICE_PACKAGE_NAME; + serviceInfo.permission = Manifest.permission.BIND_TV_REMOTE_SERVICE; + + return serviceInfo; + } +} diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp index 843e82023afe..cbf6fe88e565 100644 --- a/tools/stats_log_api_gen/Android.bp +++ b/tools/stats_log_api_gen/Android.bp @@ -26,11 +26,9 @@ cc_binary_host { "java_writer_q.cpp", "main.cpp", "native_writer.cpp", - "native_writer_q.cpp", "utils.cpp", ], cflags: [ - //"-DSTATS_SCHEMA_LEGACY", "-Wall", "-Werror", ], diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp index 8bccd7150050..aa356f1c35d2 100644 --- a/tools/stats_log_api_gen/Collation.cpp +++ b/tools/stats_log_api_gen/Collation.cpp @@ -237,6 +237,16 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, errorCount++; continue; } + + if (field->is_repeated() && + !(javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || javaType == JAVA_TYPE_KEY_VALUE_PAIR)) { + print_error(field, + "Repeated fields are not supported in atoms. Please make field %s not " + "repeated.\n", + field->name().c_str()); + errorCount++; + continue; + } } // Check that if there's an attribution chain, it's at position 1. diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp index c29936b96c14..209d511c8a05 100644 --- a/tools/stats_log_api_gen/java_writer.cpp +++ b/tools/stats_log_api_gen/java_writer.cpp @@ -59,9 +59,6 @@ static int write_java_methods( } // Print method signature. - if (DEFAULT_MODULE_NAME == moduleName) { - fprintf(out, " /** @hide */\n"); - } fprintf(out, " public static void write(int code"); vector<java_type_t> signature = signature_to_modules_it->first; int argIndex = 1; @@ -273,9 +270,6 @@ int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attribut fprintf(out, "\n"); fprintf(out, "/**\n"); fprintf(out, " * Utility class for logging statistics events.\n"); - if (DEFAULT_MODULE_NAME == moduleName) { - fprintf(out, " * @hide\n"); - } fprintf(out, " */\n"); fprintf(out, "public class %s {\n", javaClass.c_str()); diff --git a/tools/stats_log_api_gen/java_writer_q.cpp b/tools/stats_log_api_gen/java_writer_q.cpp index 12c050d8ef8d..8f2112a03e46 100644 --- a/tools/stats_log_api_gen/java_writer_q.cpp +++ b/tools/stats_log_api_gen/java_writer_q.cpp @@ -609,69 +609,5 @@ int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms, return errors; } -#if defined(STATS_SCHEMA_LEGACY) -static void write_java_method( - FILE* out, - const string& method_name, - const map<vector<java_type_t>, set<string>>& signatures_to_modules, - const AtomDecl &attributionDecl) { - - for (auto signature_to_modules_it = signatures_to_modules.begin(); - signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { - vector<java_type_t> signature = signature_to_modules_it->first; - fprintf(out, " /** @hide */\n"); - fprintf(out, " public static native int %s(int code", method_name.c_str()); - int argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - fprintf(out, ", %s[] %s", - java_type_name(chainField.javaType), chainField.name.c_str()); - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", android.util.SparseArray<Object> valueMap"); - } else { - fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ");\n"); - fprintf(out, "\n"); - } -} - -int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, - const bool supportWorkSource) { - // Print prelude - fprintf(out, "// This file is autogenerated\n"); - fprintf(out, "\n"); - fprintf(out, "package android.util;\n"); - fprintf(out, "\n"); - fprintf(out, "\n"); - fprintf(out, "/**\n"); - fprintf(out, " * API For logging statistics events.\n"); - fprintf(out, " * @hide\n"); - fprintf(out, " */\n"); - fprintf(out, "public class StatsLogInternal {\n"); - write_java_atom_codes(out, atoms, DEFAULT_MODULE_NAME); - - write_java_enum_values(out, atoms, DEFAULT_MODULE_NAME); - - // Print write methods - fprintf(out, " // Write methods\n"); - write_java_method(out, "write", atoms.signatures_to_modules, attributionDecl); - write_java_method(out, "write_non_chained", atoms.non_chained_signatures_to_modules, - attributionDecl); - if (supportWorkSource) { - write_java_work_source_methods(out, atoms.signatures_to_modules, DEFAULT_MODULE_NAME); - } - - fprintf(out, "}\n"); - - return 0; -} -#endif - } // namespace stats_log_api_gen } // namespace android diff --git a/tools/stats_log_api_gen/java_writer_q.h b/tools/stats_log_api_gen/java_writer_q.h index 7d734df1e118..6ccb225ce973 100644 --- a/tools/stats_log_api_gen/java_writer_q.h +++ b/tools/stats_log_api_gen/java_writer_q.h @@ -49,9 +49,5 @@ int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, const string& moduleName, const string& javaClass, const string& javaPackage, const bool supportWorkSource); -#if defined(STATS_SCHEMA_LEGACY) -int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, - const bool supportWorkSource); -#endif } // namespace stats_log_api_gen } // namespace android diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp index ddbf22c7f12a..120c2a2caada 100644 --- a/tools/stats_log_api_gen/main.cpp +++ b/tools/stats_log_api_gen/main.cpp @@ -1,10 +1,7 @@ - #include "Collation.h" #include "atoms_info_writer.h" -#if !defined(STATS_SCHEMA_LEGACY) #include "java_writer.h" -#endif #include "java_writer_q.h" #include "native_writer.h" #include "utils.h" @@ -28,463 +25,6 @@ namespace stats_log_api_gen { using android::os::statsd::Atom; -// Hide the JNI write helpers that are not used in the new schema. -// TODO(b/145100015): Remove this and other JNI related functionality once StatsEvent migration is -// complete. -#if defined(STATS_SCHEMA_LEGACY) -// JNI helpers. -static const char* -jni_type_name(java_type_t type) -{ - switch (type) { - case JAVA_TYPE_BOOLEAN: - return "jboolean"; - case JAVA_TYPE_INT: - case JAVA_TYPE_ENUM: - return "jint"; - case JAVA_TYPE_LONG: - return "jlong"; - case JAVA_TYPE_FLOAT: - return "jfloat"; - case JAVA_TYPE_DOUBLE: - return "jdouble"; - case JAVA_TYPE_STRING: - return "jstring"; - case JAVA_TYPE_BYTE_ARRAY: - return "jbyteArray"; - default: - return "UNKNOWN"; - } -} - -static const char* -jni_array_type_name(java_type_t type) -{ - switch (type) { - case JAVA_TYPE_INT: - return "jintArray"; - case JAVA_TYPE_FLOAT: - return "jfloatArray"; - case JAVA_TYPE_STRING: - return "jobjectArray"; - default: - return "UNKNOWN"; - } -} - -static string -jni_function_name(const string& method_name, const vector<java_type_t>& signature) -{ - string result("StatsLog_" + method_name); - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - switch (*arg) { - case JAVA_TYPE_BOOLEAN: - result += "_boolean"; - break; - case JAVA_TYPE_INT: - case JAVA_TYPE_ENUM: - result += "_int"; - break; - case JAVA_TYPE_LONG: - result += "_long"; - break; - case JAVA_TYPE_FLOAT: - result += "_float"; - break; - case JAVA_TYPE_DOUBLE: - result += "_double"; - break; - case JAVA_TYPE_STRING: - result += "_String"; - break; - case JAVA_TYPE_ATTRIBUTION_CHAIN: - result += "_AttributionChain"; - break; - case JAVA_TYPE_KEY_VALUE_PAIR: - result += "_KeyValuePairs"; - break; - case JAVA_TYPE_BYTE_ARRAY: - result += "_bytes"; - break; - default: - result += "_UNKNOWN"; - break; - } - } - return result; -} - -static const char* -java_type_signature(java_type_t type) -{ - switch (type) { - case JAVA_TYPE_BOOLEAN: - return "Z"; - case JAVA_TYPE_INT: - case JAVA_TYPE_ENUM: - return "I"; - case JAVA_TYPE_LONG: - return "J"; - case JAVA_TYPE_FLOAT: - return "F"; - case JAVA_TYPE_DOUBLE: - return "D"; - case JAVA_TYPE_STRING: - return "Ljava/lang/String;"; - case JAVA_TYPE_BYTE_ARRAY: - return "[B"; - default: - return "UNKNOWN"; - } -} - -static string -jni_function_signature(const vector<java_type_t>& signature, const AtomDecl &attributionDecl) -{ - string result("(I"); - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - result += "["; - result += java_type_signature(chainField.javaType); - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - result += "Landroid/util/SparseArray;"; - } else { - result += java_type_signature(*arg); - } - } - result += ")I"; - return result; -} - -static void write_key_value_map_jni(FILE* out) { - fprintf(out, " std::map<int, int32_t> int32_t_map;\n"); - fprintf(out, " std::map<int, int64_t> int64_t_map;\n"); - fprintf(out, " std::map<int, float> float_map;\n"); - fprintf(out, " std::map<int, char const*> string_map;\n\n"); - - fprintf(out, " jclass jmap_class = env->FindClass(\"android/util/SparseArray\");\n"); - - fprintf(out, " jmethodID jget_size_method = env->GetMethodID(jmap_class, \"size\", \"()I\");\n"); - fprintf(out, " jmethodID jget_key_method = env->GetMethodID(jmap_class, \"keyAt\", \"(I)I\");\n"); - fprintf(out, " jmethodID jget_value_method = env->GetMethodID(jmap_class, \"valueAt\", \"(I)Ljava/lang/Object;\");\n\n"); - - - fprintf(out, " std::vector<std::unique_ptr<ScopedUtfChars>> scoped_ufs;\n\n"); - - fprintf(out, " jclass jint_class = env->FindClass(\"java/lang/Integer\");\n"); - fprintf(out, " jclass jlong_class = env->FindClass(\"java/lang/Long\");\n"); - fprintf(out, " jclass jfloat_class = env->FindClass(\"java/lang/Float\");\n"); - fprintf(out, " jclass jstring_class = env->FindClass(\"java/lang/String\");\n"); - fprintf(out, " jmethodID jget_int_method = env->GetMethodID(jint_class, \"intValue\", \"()I\");\n"); - fprintf(out, " jmethodID jget_long_method = env->GetMethodID(jlong_class, \"longValue\", \"()J\");\n"); - fprintf(out, " jmethodID jget_float_method = env->GetMethodID(jfloat_class, \"floatValue\", \"()F\");\n\n"); - - fprintf(out, " jint jsize = env->CallIntMethod(value_map, jget_size_method);\n"); - fprintf(out, " for(int i = 0; i < jsize; i++) {\n"); - fprintf(out, " jint key = env->CallIntMethod(value_map, jget_key_method, i);\n"); - fprintf(out, " jobject jvalue_obj = env->CallObjectMethod(value_map, jget_value_method, i);\n"); - fprintf(out, " if (jvalue_obj == NULL) { continue; }\n"); - fprintf(out, " if (env->IsInstanceOf(jvalue_obj, jint_class)) {\n"); - fprintf(out, " int32_t_map[key] = env->CallIntMethod(jvalue_obj, jget_int_method);\n"); - fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jlong_class)) {\n"); - fprintf(out, " int64_t_map[key] = env->CallLongMethod(jvalue_obj, jget_long_method);\n"); - fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jfloat_class)) {\n"); - fprintf(out, " float_map[key] = env->CallFloatMethod(jvalue_obj, jget_float_method);\n"); - fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jstring_class)) {\n"); - fprintf(out, " std::unique_ptr<ScopedUtfChars> utf(new ScopedUtfChars(env, (jstring)jvalue_obj));\n"); - fprintf(out, " if (utf->c_str() != NULL) { string_map[key] = utf->c_str(); }\n"); - fprintf(out, " scoped_ufs.push_back(std::move(utf));\n"); - fprintf(out, " }\n"); - fprintf(out, " }\n"); -} - -static int -write_stats_log_jni_method(FILE* out, const string& java_method_name, const string& cpp_method_name, - const map<vector<java_type_t>, set<string>>& signatures_to_modules, - const AtomDecl &attributionDecl) { - // Print write methods - for (auto signature_to_modules_it = signatures_to_modules.begin(); - signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { - vector<java_type_t> signature = signature_to_modules_it->first; - int argIndex; - - fprintf(out, "static int\n"); - fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code", - jni_function_name(java_method_name, signature).c_str()); - argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - fprintf(out, ", %s %s", jni_array_type_name(chainField.javaType), - chainField.name.c_str()); - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", jobject value_map"); - } else { - fprintf(out, ", %s arg%d", jni_type_name(*arg), argIndex); - } - argIndex++; - } - fprintf(out, ")\n"); - - fprintf(out, "{\n"); - - // Prepare strings - argIndex = 1; - bool hadStringOrChain = false; - bool isKeyValuePairAtom = false; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - if (*arg == JAVA_TYPE_STRING) { - hadStringOrChain = true; - fprintf(out, " const char* str%d;\n", argIndex); - fprintf(out, " if (arg%d != NULL) {\n", argIndex); - fprintf(out, " str%d = env->GetStringUTFChars(arg%d, NULL);\n", - argIndex, argIndex); - fprintf(out, " } else {\n"); - fprintf(out, " str%d = NULL;\n", argIndex); - fprintf(out, " }\n"); - } else if (*arg == JAVA_TYPE_BYTE_ARRAY) { - hadStringOrChain = true; - fprintf(out, " jbyte* jbyte_array%d;\n", argIndex); - fprintf(out, " const char* str%d;\n", argIndex); - fprintf(out, " int str%d_length = 0;\n", argIndex); - fprintf(out, - " if (arg%d != NULL && env->GetArrayLength(arg%d) > " - "0) {\n", - argIndex, argIndex); - fprintf(out, - " jbyte_array%d = " - "env->GetByteArrayElements(arg%d, NULL);\n", - argIndex, argIndex); - fprintf(out, - " str%d_length = env->GetArrayLength(arg%d);\n", - argIndex, argIndex); - fprintf(out, - " str%d = " - "reinterpret_cast<char*>(env->GetByteArrayElements(arg%" - "d, NULL));\n", - argIndex, argIndex); - fprintf(out, " } else {\n"); - fprintf(out, " jbyte_array%d = NULL;\n", argIndex); - fprintf(out, " str%d = NULL;\n", argIndex); - fprintf(out, " }\n"); - - fprintf(out, - " android::util::BytesField bytesField%d(str%d, " - "str%d_length);", - argIndex, argIndex, argIndex); - - } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - hadStringOrChain = true; - for (auto chainField : attributionDecl.fields) { - fprintf(out, " size_t %s_length = env->GetArrayLength(%s);\n", - chainField.name.c_str(), chainField.name.c_str()); - if (chainField.name != attributionDecl.fields.front().name) { - fprintf(out, " if (%s_length != %s_length) {\n", - chainField.name.c_str(), - attributionDecl.fields.front().name.c_str()); - fprintf(out, " return -EINVAL;\n"); - fprintf(out, " }\n"); - } - if (chainField.javaType == JAVA_TYPE_INT) { - fprintf(out, " jint* %s_array = env->GetIntArrayElements(%s, NULL);\n", - chainField.name.c_str(), chainField.name.c_str()); - } else if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, " std::vector<%s> %s_vec;\n", - cpp_type_name(chainField.javaType), chainField.name.c_str()); - fprintf(out, " std::vector<ScopedUtfChars*> scoped_%s_vec;\n", - chainField.name.c_str()); - fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n", - chainField.name.c_str()); - fprintf(out, " jstring jstr = " - "(jstring)env->GetObjectArrayElement(%s, i);\n", - chainField.name.c_str()); - fprintf(out, " if (jstr == NULL) {\n"); - fprintf(out, " %s_vec.push_back(NULL);\n", - chainField.name.c_str()); - fprintf(out, " } else {\n"); - fprintf(out, " ScopedUtfChars* scoped_%s = " - "new ScopedUtfChars(env, jstr);\n", - chainField.name.c_str()); - fprintf(out, " %s_vec.push_back(scoped_%s->c_str());\n", - chainField.name.c_str(), chainField.name.c_str()); - fprintf(out, " scoped_%s_vec.push_back(scoped_%s);\n", - chainField.name.c_str(), chainField.name.c_str()); - fprintf(out, " }\n"); - fprintf(out, " }\n"); - } - fprintf(out, "\n"); - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - isKeyValuePairAtom = true; - } - argIndex++; - } - // Emit this to quiet the unused parameter warning if there were no strings or attribution - // chains. - if (!hadStringOrChain && !isKeyValuePairAtom) { - fprintf(out, " (void)env;\n"); - } - if (isKeyValuePairAtom) { - write_key_value_map_jni(out); - } - - // stats_write call - argIndex = 1; - fprintf(out, "\n int ret = android::util::%s(code", - cpp_method_name.c_str()); - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - if (chainField.javaType == JAVA_TYPE_INT) { - fprintf(out, ", (const %s*)%s_array, %s_length", - cpp_type_name(chainField.javaType), - chainField.name.c_str(), chainField.name.c_str()); - } else if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, ", %s_vec", chainField.name.c_str()); - } - } - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, ", int32_t_map, int64_t_map, string_map, float_map"); - } else if (*arg == JAVA_TYPE_BYTE_ARRAY) { - fprintf(out, ", bytesField%d", argIndex); - } else { - const char* argName = - (*arg == JAVA_TYPE_STRING) ? "str" : "arg"; - fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex); - } - argIndex++; - } - fprintf(out, ");\n"); - fprintf(out, "\n"); - - // Clean up strings - argIndex = 1; - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - if (*arg == JAVA_TYPE_STRING) { - fprintf(out, " if (str%d != NULL) {\n", argIndex); - fprintf(out, " env->ReleaseStringUTFChars(arg%d, str%d);\n", - argIndex, argIndex); - fprintf(out, " }\n"); - } else if (*arg == JAVA_TYPE_BYTE_ARRAY) { - fprintf(out, " if (str%d != NULL) { \n", argIndex); - fprintf(out, - " env->ReleaseByteArrayElements(arg%d, " - "jbyte_array%d, 0);\n", - argIndex, argIndex); - fprintf(out, " }\n"); - } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (auto chainField : attributionDecl.fields) { - if (chainField.javaType == JAVA_TYPE_INT) { - fprintf(out, " env->ReleaseIntArrayElements(%s, %s_array, 0);\n", - chainField.name.c_str(), chainField.name.c_str()); - } else if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, " for (size_t i = 0; i < scoped_%s_vec.size(); ++i) {\n", - chainField.name.c_str()); - fprintf(out, " delete scoped_%s_vec[i];\n", chainField.name.c_str()); - fprintf(out, " }\n"); - } - } - } - argIndex++; - } - - fprintf(out, " return ret;\n"); - - fprintf(out, "}\n"); - fprintf(out, "\n"); - } - - - return 0; -} - -void write_jni_registration(FILE* out, const string& java_method_name, - const map<vector<java_type_t>, set<string>>& signatures_to_modules, - const AtomDecl &attributionDecl) { - for (auto signature_to_modules_it = signatures_to_modules.begin(); - signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { - vector<java_type_t> signature = signature_to_modules_it->first; - fprintf(out, " { \"%s\", \"%s\", (void*)%s },\n", - java_method_name.c_str(), - jni_function_signature(signature, attributionDecl).c_str(), - jni_function_name(java_method_name, signature).c_str()); - } -} -#endif // JNI helpers. - -static int -#if defined(STATS_SCHEMA_LEGACY) -write_stats_log_jni(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl) -#else -// Write empty JNI file that doesn't contain any JNI methods. -// TODO(b/145100015): remove this function and all JNI autogen code once StatsEvent migration is -// complete. -write_stats_log_jni(FILE* out) -#endif -{ - // Print prelude - fprintf(out, "// This file is autogenerated\n"); - fprintf(out, "\n"); - -#if defined(STATS_SCHEMA_LEGACY) - fprintf(out, "#include <statslog.h>\n"); - fprintf(out, "\n"); - fprintf(out, "#include <nativehelper/JNIHelp.h>\n"); - fprintf(out, "#include <nativehelper/ScopedUtfChars.h>\n"); - fprintf(out, "#include <utils/Vector.h>\n"); -#endif - fprintf(out, "#include \"core_jni_helpers.h\"\n"); - fprintf(out, "#include \"jni.h\"\n"); - fprintf(out, "\n"); -#if defined(STATS_SCHEMA_LEGACY) - fprintf(out, "#define UNUSED __attribute__((__unused__))\n"); - fprintf(out, "\n"); -#endif - - fprintf(out, "namespace android {\n"); - fprintf(out, "\n"); - -#if defined(STATS_SCHEMA_LEGACY) - write_stats_log_jni_method(out, "write", "stats_write", atoms.signatures_to_modules, attributionDecl); - write_stats_log_jni_method(out, "write_non_chained", "stats_write_non_chained", - atoms.non_chained_signatures_to_modules, attributionDecl); -#endif - - // Print registration function table - fprintf(out, "/*\n"); - fprintf(out, " * JNI registration.\n"); - fprintf(out, " */\n"); - fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n"); -#if defined(STATS_SCHEMA_LEGACY) - write_jni_registration(out, "write", atoms.signatures_to_modules, attributionDecl); - write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures_to_modules, - attributionDecl); -#endif - fprintf(out, "};\n"); - fprintf(out, "\n"); - - // Print registration function - fprintf(out, "int register_android_util_StatsLogInternal(JNIEnv* env) {\n"); - fprintf(out, " return RegisterMethodsOrDie(\n"); - fprintf(out, " env,\n"); - fprintf(out, " \"android/util/StatsLogInternal\",\n"); - fprintf(out, " gRegisterMethods, NELEM(gRegisterMethods));\n"); - fprintf(out, "}\n"); - - fprintf(out, "\n"); - fprintf(out, "} // namespace android\n"); - return 0; -} - static void print_usage() { @@ -498,7 +38,6 @@ print_usage() fprintf(stderr, " --atomsInfoHeader FILENAME the cpp file to output for statsd metadata\n"); fprintf(stderr, " --help this message\n"); fprintf(stderr, " --java FILENAME the java file to output\n"); - fprintf(stderr, " --jni FILENAME the jni file to output\n"); fprintf(stderr, " --module NAME optional, module name to generate outputs for\n"); fprintf(stderr, " --namespace COMMA,SEP,NAMESPACE required for cpp/header with module\n"); fprintf(stderr, " comma separated namespace of the files\n"); @@ -526,16 +65,15 @@ run(int argc, char const*const* argv) string cppFilename; string headerFilename; string javaFilename; - string jniFilename; string atomsInfoCppFilename; string atomsInfoHeaderFilename; + string javaPackage; + string javaClass; string moduleName = DEFAULT_MODULE_NAME; string cppNamespace = DEFAULT_CPP_NAMESPACE; string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT; string atomsInfoCppHeaderImport = DEFAULT_ATOMS_INFO_CPP_HEADER_IMPORT; - string javaPackage = DEFAULT_JAVA_PACKAGE; - string javaClass = DEFAULT_JAVA_CLASS; bool supportQ = false; bool supportWorkSource = false; bool compileQ = false; @@ -566,13 +104,6 @@ run(int argc, char const*const* argv) return 1; } javaFilename = argv[index]; - } else if (0 == strcmp("--jni", argv[index])) { - index++; - if (index >= argc) { - print_usage(); - return 1; - } - jniFilename = argv[index]; } else if (0 == strcmp("--module", argv[index])) { index++; if (index >= argc) { @@ -643,7 +174,6 @@ run(int argc, char const*const* argv) if (cppFilename.size() == 0 && headerFilename.size() == 0 && javaFilename.size() == 0 - && jniFilename.size() == 0 && atomsInfoHeaderFilename.size() == 0 && atomsInfoCppFilename.size() == 0) { print_usage(); @@ -738,27 +268,27 @@ run(int argc, char const*const* argv) // Write the .java file if (javaFilename.size() != 0) { - FILE* out = fopen(javaFilename.c_str(), "w"); - if (out == NULL) { - fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str()); + if (javaClass.size() == 0) { + fprintf(stderr, "Must supply --javaClass if supplying a Java filename"); return 1; } -#if defined(STATS_SCHEMA_LEGACY) - if (moduleName == DEFAULT_MODULE_NAME) { - errorCount = android::stats_log_api_gen::write_stats_log_java_q( - out, atoms, attributionDecl, supportWorkSource); - } else { - errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module( - out, atoms, attributionDecl, moduleName, javaClass, javaPackage, - supportWorkSource); + if (javaPackage.size() == 0) { + fprintf(stderr, "Must supply --javaPackage if supplying a Java filename"); + return 1; + } + if (moduleName.size() == 0) { + fprintf(stderr, "Must supply --module if supplying a Java filename"); + return 1; } -#else - if (moduleName == DEFAULT_MODULE_NAME) { - javaClass = "StatsLogInternal"; - javaPackage = "android.util"; + + FILE* out = fopen(javaFilename.c_str(), "w"); + if (out == NULL) { + fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str()); + return 1; } + if (compileQ) { errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module( out, atoms, attributionDecl, moduleName, javaClass, javaPackage, @@ -768,25 +298,6 @@ run(int argc, char const*const* argv) out, atoms, attributionDecl, moduleName, javaClass, javaPackage, supportQ, supportWorkSource); } -#endif - - fclose(out); - } - - // Write the jni file - if (jniFilename.size() != 0) { - FILE* out = fopen(jniFilename.c_str(), "w"); - if (out == NULL) { - fprintf(stderr, "Unable to open file for write: %s\n", jniFilename.c_str()); - return 1; - } - -#if defined(STATS_SCHEMA_LEGACY) - errorCount = android::stats_log_api_gen::write_stats_log_jni( - out, atoms, attributionDecl); -#else - errorCount = android::stats_log_api_gen::write_stats_log_jni(out); -#endif fclose(out); } diff --git a/tools/stats_log_api_gen/native_writer.cpp b/tools/stats_log_api_gen/native_writer.cpp index 285514df5ff3..da207d665e20 100644 --- a/tools/stats_log_api_gen/native_writer.cpp +++ b/tools/stats_log_api_gen/native_writer.cpp @@ -15,14 +15,11 @@ */ #include "native_writer.h" -#include "native_writer_q.h" #include "utils.h" namespace android { namespace stats_log_api_gen { -#if !defined(STATS_SCHEMA_LEGACY) - static int write_native_stats_write_methods(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl, const string& moduleName, const bool supportQ) { fprintf(out, "\n"); @@ -175,7 +172,6 @@ static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms& } } -#endif static void write_native_method_header( FILE* out, @@ -191,12 +187,10 @@ static void write_native_method_header( } vector<java_type_t> signature = signature_to_modules_it->first; -#if !defined(STATS_SCHEMA_LEGACY) // Key value pairs not supported in native. if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) { continue; } -#endif write_native_method_signature(out, methodName, signature, attributionDecl, ";"); } } @@ -209,33 +203,17 @@ int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributi fprintf(out, "\n"); fprintf(out, "#include <%s>\n", importHeader.c_str()); -#if defined(STATS_SCHEMA_LEGACY) - (void)supportQ; // Workaround for unused parameter error. - write_native_cpp_includes_q(out); -#else if (supportQ) { fprintf(out, "#include <StatsEventCompat.h>\n"); } else { fprintf(out, "#include <stats_event.h>\n"); } -#endif fprintf(out, "\n"); write_namespace(out, cppNamespace); -#if defined(STATS_SCHEMA_LEGACY) - write_native_stats_log_cpp_globals_q(out); - write_native_get_timestamp_ns_q(out); - write_native_try_stats_write_methods_q(out, atoms, attributionDecl, moduleName); - write_native_stats_write_methods_q(out, "int stats_write", atoms, attributionDecl, moduleName, - "try_stats_write"); - write_native_try_stats_write_non_chained_methods_q(out, atoms, attributionDecl, moduleName); - write_native_stats_write_non_chained_methods_q(out, "int stats_write_non_chained", atoms, - attributionDecl, moduleName, "try_stats_write_non_chained"); -#else write_native_stats_write_methods(out, atoms, attributionDecl, moduleName, supportQ); write_native_stats_write_non_chained_methods(out, atoms, attributionDecl, moduleName); -#endif // Print footer fprintf(out, "\n"); diff --git a/tools/stats_log_api_gen/native_writer_q.cpp b/tools/stats_log_api_gen/native_writer_q.cpp deleted file mode 100644 index 299873dad975..000000000000 --- a/tools/stats_log_api_gen/native_writer_q.cpp +++ /dev/null @@ -1,276 +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. - */ - -#include "native_writer_q.h" -#include "utils.h" - -namespace android { -namespace stats_log_api_gen { - -static void write_native_stats_write_body_q(FILE* out, const vector<java_type_t>& signature, - const AtomDecl& attributionDecl, const string& indent, const string& tryMethodName) { - fprintf(out, "%sint ret = 0;\n", indent.c_str()); - - fprintf(out, "%sfor(int retry = 0; retry < 2; ++retry) {\n", indent.c_str()); - fprintf(out, "%s ret = ", indent.c_str()); - write_native_method_call(out, tryMethodName, signature, attributionDecl); - fprintf(out, "%s if (ret >= 0) { break; }\n", indent.c_str()); - - fprintf(out, "%s {\n", indent.c_str()); - fprintf(out, "%s std::lock_guard<std::mutex> lock(mLogdRetryMutex);\n", indent.c_str()); - fprintf(out, "%s if ((get_elapsed_realtime_ns() - lastRetryTimestampNs) <= " - "kMinRetryIntervalNs) break;\n", indent.c_str()); - fprintf(out, "%s lastRetryTimestampNs = get_elapsed_realtime_ns();\n", - indent.c_str()); - fprintf(out, "%s }\n", indent.c_str()); - fprintf(out, "%s std::this_thread::sleep_for(std::chrono::milliseconds(10));\n", - indent.c_str()); - fprintf(out, "%s}\n", indent.c_str()); - fprintf(out, "%sif (ret < 0) {\n", indent.c_str()); - fprintf(out, "%s note_log_drop(ret, code);\n", indent.c_str()); - fprintf(out, "%s}\n", indent.c_str()); - fprintf(out, "%sreturn ret;\n", indent.c_str()); -} - -void write_native_cpp_includes_q(FILE* out) { - fprintf(out, "#include <mutex>\n"); - fprintf(out, "#include <chrono>\n"); - fprintf(out, "#include <thread>\n"); - fprintf(out, "#ifdef __ANDROID__\n"); - fprintf(out, "#include <cutils/properties.h>\n"); - fprintf(out, "#endif\n"); - fprintf(out, "#include <stats_event_list.h>\n"); - fprintf(out, "#include <log/log.h>\n"); - fprintf(out, "#include <time.h>\n"); -} - -void write_native_get_timestamp_ns_q(FILE* out) { - fprintf(out, "\n"); - fprintf(out, "static int64_t get_elapsed_realtime_ns() {\n"); - fprintf(out, " struct timespec t;\n"); - fprintf(out, " t.tv_sec = t.tv_nsec = 0;\n"); - fprintf(out, " clock_gettime(CLOCK_BOOTTIME, &t);\n"); - fprintf(out, " return (int64_t)t.tv_sec * 1000000000LL + t.tv_nsec;\n"); - fprintf(out, "}\n"); -} - -void write_native_stats_log_cpp_globals_q(FILE* out) { - fprintf(out, "// the single event tag id for all stats logs\n"); - fprintf(out, "const static int kStatsEventTag = 1937006964;\n"); - fprintf(out, "#ifdef __ANDROID__\n"); - fprintf(out, - "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n"); - fprintf(out, "#else\n"); - fprintf(out, "const static bool kStatsdEnabled = false;\n"); - fprintf(out, "#endif\n"); - - fprintf(out, "int64_t lastRetryTimestampNs = -1;\n"); - fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n"); - fprintf(out, "static std::mutex mLogdRetryMutex;\n"); -} - -void write_native_try_stats_write_methods_q(FILE* out, const Atoms& atoms, - const AtomDecl& attributionDecl, const string& moduleName) { - fprintf(out, "\n"); - for (auto signature_to_modules_it = atoms.signatures_to_modules.begin(); - signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) { - if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { - continue; - } - vector<java_type_t> signature = signature_to_modules_it->first; - - write_native_method_signature(out, "static int try_stats_write", signature, - attributionDecl, " {"); - - int argIndex = 1; - fprintf(out, " if (kStatsdEnabled) {\n"); - fprintf(out, " stats_event_list event(kStatsEventTag);\n"); - fprintf(out, " event << get_elapsed_realtime_ns();\n\n"); - fprintf(out, " event << code;\n\n"); - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { - for (const auto &chainField : attributionDecl.fields) { - if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, " if (%s_length != %s.size()) {\n", - attributionDecl.fields.front().name.c_str(), chainField.name.c_str()); - fprintf(out, " return -EINVAL;\n"); - fprintf(out, " }\n"); - } - } - fprintf(out, "\n event.begin();\n"); - fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n", - attributionDecl.fields.front().name.c_str()); - fprintf(out, " event.begin();\n"); - for (const auto &chainField : attributionDecl.fields) { - if (chainField.javaType == JAVA_TYPE_STRING) { - fprintf(out, " if (%s[i] != NULL) {\n", chainField.name.c_str()); - fprintf(out, " event << %s[i];\n", chainField.name.c_str()); - fprintf(out, " } else {\n"); - fprintf(out, " event << \"\";\n"); - fprintf(out, " }\n"); - } else { - fprintf(out, " event << %s[i];\n", chainField.name.c_str()); - } - } - fprintf(out, " event.end();\n"); - fprintf(out, " }\n"); - fprintf(out, " event.end();\n\n"); - } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { - fprintf(out, " event.begin();\n\n"); - fprintf(out, " for (const auto& it : arg%d_1) {\n", argIndex); - fprintf(out, " event.begin();\n"); - fprintf(out, " event << it.first;\n"); - fprintf(out, " event << it.second;\n"); - fprintf(out, " event.end();\n"); - fprintf(out, " }\n"); - - fprintf(out, " for (const auto& it : arg%d_2) {\n", argIndex); - fprintf(out, " event.begin();\n"); - fprintf(out, " event << it.first;\n"); - fprintf(out, " event << it.second;\n"); - fprintf(out, " event.end();\n"); - fprintf(out, " }\n"); - - fprintf(out, " for (const auto& it : arg%d_3) {\n", argIndex); - fprintf(out, " event.begin();\n"); - fprintf(out, " event << it.first;\n"); - fprintf(out, " event << it.second;\n"); - fprintf(out, " event.end();\n"); - fprintf(out, " }\n"); - - fprintf(out, " for (const auto& it : arg%d_4) {\n", argIndex); - fprintf(out, " event.begin();\n"); - fprintf(out, " event << it.first;\n"); - fprintf(out, " event << it.second;\n"); - fprintf(out, " event.end();\n"); - fprintf(out, " }\n"); - - fprintf(out, " event.end();\n\n"); - } else if (*arg == JAVA_TYPE_BYTE_ARRAY) { - fprintf(out, - " event.AppendCharArray(arg%d.arg, " - "arg%d.arg_length);\n", - argIndex, argIndex); - } else { - if (*arg == JAVA_TYPE_STRING) { - fprintf(out, " if (arg%d == NULL) {\n", argIndex); - fprintf(out, " arg%d = \"\";\n", argIndex); - fprintf(out, " }\n"); - } - fprintf(out, " event << arg%d;\n", argIndex); - } - argIndex++; - } - - fprintf(out, " return event.write(LOG_ID_STATS);\n"); - fprintf(out, " } else {\n"); - fprintf(out, " return 1;\n"); - fprintf(out, " }\n"); - fprintf(out, "}\n"); - fprintf(out, "\n"); - } - -} - -void write_native_stats_write_methods_q(FILE* out, const string& methodName, const Atoms& atoms, - const AtomDecl& attributionDecl, const string& moduleName, const string& tryMethodName) { - for (auto signature_to_modules_it = atoms.signatures_to_modules.begin(); - signature_to_modules_it != atoms.signatures_to_modules.end(); - signature_to_modules_it++) { - if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { - continue; - } - vector<java_type_t> signature = signature_to_modules_it->first; - - write_native_method_signature(out, methodName, signature, attributionDecl, " {"); - - write_native_stats_write_body_q(out, signature, attributionDecl, " ", tryMethodName); - fprintf(out, "}\n\n"); - } -} - -void write_native_stats_write_non_chained_methods_q(FILE* out, const string& methodName, - const Atoms& atoms, const AtomDecl& attributionDecl, const string& moduleName, - const string& tryMethodName) { - for (auto signature_it = atoms.non_chained_signatures_to_modules.begin(); - signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) { - if (!signature_needed_for_module(signature_it->second, moduleName)) { - continue; - } - vector<java_type_t> signature = signature_it->first; - - write_native_method_signature(out, methodName, signature, attributionDecl, " {"); - - write_native_stats_write_body_q(out, signature, attributionDecl, " ", tryMethodName); - fprintf(out, "}\n\n"); - } -} - -void write_native_try_stats_write_non_chained_methods_q(FILE* out, const Atoms& atoms, - const AtomDecl& attributionDecl, const string& moduleName) { - for (auto signature_it = atoms.non_chained_signatures_to_modules.begin(); - signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) { - if (!signature_needed_for_module(signature_it->second, moduleName)) { - continue; - } - vector<java_type_t> signature = signature_it->first; - - write_native_method_signature(out, "static int try_stats_write_non_chained", signature, - attributionDecl, " {"); - - int argIndex = 1; - fprintf(out, " if (kStatsdEnabled) {\n"); - fprintf(out, " stats_event_list event(kStatsEventTag);\n"); - fprintf(out, " event << get_elapsed_realtime_ns();\n\n"); - fprintf(out, " event << code;\n\n"); - for (vector<java_type_t>::const_iterator arg = signature.begin(); - arg != signature.end(); arg++) { - if (argIndex == 1) { - fprintf(out, " event.begin();\n\n"); - fprintf(out, " event.begin();\n"); - } - if (*arg == JAVA_TYPE_STRING) { - fprintf(out, " if (arg%d == NULL) {\n", argIndex); - fprintf(out, " arg%d = \"\";\n", argIndex); - fprintf(out, " }\n"); - } - if (*arg == JAVA_TYPE_BYTE_ARRAY) { - fprintf(out, - " event.AppendCharArray(arg%d.arg, " - "arg%d.arg_length);\n", - argIndex, argIndex); - } else { - fprintf(out, " event << arg%d;\n", argIndex); - } - if (argIndex == 2) { - fprintf(out, " event.end();\n\n"); - fprintf(out, " event.end();\n\n"); - } - argIndex++; - } - - fprintf(out, " return event.write(LOG_ID_STATS);\n"); - fprintf(out, " } else {\n"); - fprintf(out, " return 1;\n"); - fprintf(out, " }\n"); - fprintf(out, "}\n"); - fprintf(out, "\n"); - } -} - -} // namespace stats_log_api_gen -} // namespace android diff --git a/tools/stats_log_api_gen/native_writer_q.h b/tools/stats_log_api_gen/native_writer_q.h deleted file mode 100644 index a2ab1ae5d5e2..000000000000 --- a/tools/stats_log_api_gen/native_writer_q.h +++ /dev/null @@ -1,49 +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. - */ - -#pragma once - -#include "Collation.h" - -#include <stdio.h> -#include <string.h> - -namespace android { -namespace stats_log_api_gen { - -using namespace std; - -void write_native_cpp_includes_q(FILE* out); - -void write_native_stats_log_cpp_globals_q(FILE* out); - -void write_native_try_stats_write_methods_q(FILE* out, const Atoms& atoms, - const AtomDecl& attributionDecl, const string& moduleName); - -void write_native_stats_write_methods_q(FILE* out, const string& methodName, const Atoms& atoms, - const AtomDecl& attributionDecl, const string& moduleName, const string& tryMethodName); - -void write_native_try_stats_write_non_chained_methods_q(FILE* out, const Atoms& atoms, - const AtomDecl& attributionDecl, const string& moduleName); - -void write_native_stats_write_non_chained_methods_q(FILE* out, const string& methodName, - const Atoms& atoms, const AtomDecl& attributionDecl, const string& moduleName, - const string& tryMethodName); - -void write_native_get_timestamp_ns_q(FILE* out); - -} // namespace stats_log_api_gen -} // namespace android diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto index b892194410ae..eab622d77ef7 100644 --- a/tools/stats_log_api_gen/test.proto +++ b/tools/stats_log_api_gen/test.proto @@ -41,21 +41,20 @@ enum AnEnum { message AllTypesAtom { repeated android.os.statsd.AttributionNode attribution_chain = 1; - optional double double_field = 2; - optional float float_field = 3; - optional int64 int64_field = 4; - optional uint64 uint64_field = 5; - optional int32 int32_field = 6; - optional fixed64 fixed64_field = 7; - optional fixed32 fixed32_field = 8; - optional bool bool_field = 9; - optional string string_field = 10; - optional uint32 uint32_field = 11; - optional AnEnum enum_field = 12; - optional sfixed32 sfixed32_field = 13; - optional sfixed64 sfixed64_field = 14; - optional sint32 sint32_field = 15; - optional sint64 sint64_field = 16; + optional float float_field = 2; + optional int64 int64_field = 3; + optional uint64 uint64_field = 4; + optional int32 int32_field = 5; + optional fixed64 fixed64_field = 6; + optional fixed32 fixed32_field = 7; + optional bool bool_field = 8; + optional string string_field = 9; + optional uint32 uint32_field = 10; + optional AnEnum enum_field = 11; + optional sfixed32 sfixed32_field = 12; + optional sfixed64 sfixed64_field = 13; + optional sint32 sint32_field = 14; + optional sint64 sint64_field = 15; } message Event { @@ -70,6 +69,8 @@ message Event { message BadTypesAtom { optional IntAtom bad_int_atom = 1; optional bytes bad_bytes = 2; + repeated int32 repeated_field = 3; + optional double double_field = 4; } message BadTypesEvent { diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp index bcf18ae8bf19..a972e2342cad 100644 --- a/tools/stats_log_api_gen/test_collation.cpp +++ b/tools/stats_log_api_gen/test_collation.cpp @@ -98,7 +98,6 @@ TEST(CollationTest, CollateStats) { EXPECT_SET_CONTAINS_SIGNATURE( atoms.signatures_to_modules, JAVA_TYPE_ATTRIBUTION_CHAIN, // AttributionChain - JAVA_TYPE_DOUBLE, // double JAVA_TYPE_FLOAT, // float JAVA_TYPE_LONG, // int64 JAVA_TYPE_LONG, // uint64 @@ -157,13 +156,13 @@ TEST(CollationTest, NonMessageTypeFails) { } /** - * Test that atoms that have non-primitive types are rejected. + * Test that atoms that have non-primitive types or repeated fields are rejected. */ TEST(CollationTest, FailOnBadTypes) { Atoms atoms; int errorCount = collate_atoms(BadTypesEvent::descriptor(), &atoms); - EXPECT_EQ(2, errorCount); + EXPECT_EQ(4, errorCount); } /** diff --git a/tools/stats_log_api_gen/utils.cpp b/tools/stats_log_api_gen/utils.cpp index 8c4abe43a49b..cd6914b4fc06 100644 --- a/tools/stats_log_api_gen/utils.cpp +++ b/tools/stats_log_api_gen/utils.cpp @@ -286,9 +286,6 @@ void write_java_atom_codes(FILE* out, const Atoms& atoms, const string& moduleNa if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) { write_java_usage(out, "write_non_chained", constant, *non_chained_decl->second); } - if (moduleName == DEFAULT_MODULE_NAME) { - fprintf(out, " * @hide\n"); - } fprintf(out, " */\n"); fprintf(out, " public static final int %s = %d;\n", constant.c_str(), atom->code); } @@ -310,9 +307,6 @@ void write_java_enum_values(FILE* out, const Atoms& atoms, const string& moduleN field->name.c_str()); for (map<int, string>::const_iterator value = field->enumValues.begin(); value != field->enumValues.end(); value++) { - if (moduleName == DEFAULT_MODULE_NAME) { - fprintf(out, " /** @hide */\n"); - } fprintf(out, " public static final int %s__%s__%s = %d;\n", make_constant_name(atom->message).c_str(), make_constant_name(field->name).c_str(), @@ -357,9 +351,6 @@ int write_java_non_chained_methods( } // Print method signature. - if (DEFAULT_MODULE_NAME == moduleName) { - fprintf(out, " /** @hide */\n"); - } fprintf(out, " public static void write_non_chained(int code"); vector<java_type_t> signature = signature_to_modules_it->first; int argIndex = 1; @@ -434,9 +425,6 @@ int write_java_work_source_methods( fprintf(out, "\n"); // Method header (signature) - if (DEFAULT_MODULE_NAME == moduleName) { - fprintf(out, " /** @hide */\n"); - } fprintf(out, " public static void write(int code"); int argIndex = 1; for (vector<java_type_t>::const_iterator arg = signature.begin(); diff --git a/tools/stats_log_api_gen/utils.h b/tools/stats_log_api_gen/utils.h index cd602e53359a..715d42bc160a 100644 --- a/tools/stats_log_api_gen/utils.h +++ b/tools/stats_log_api_gen/utils.h @@ -34,8 +34,6 @@ const string DEFAULT_MODULE_NAME = "DEFAULT"; const string DEFAULT_CPP_NAMESPACE = "android,util"; const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h"; const string DEFAULT_ATOMS_INFO_CPP_HEADER_IMPORT = "atoms_info.h"; -const string DEFAULT_JAVA_PACKAGE = "android.util"; -const string DEFAULT_JAVA_CLASS = "StatsLogInternal"; const int JAVA_MODULE_REQUIRES_FLOAT = 0x01; const int JAVA_MODULE_REQUIRES_ATTRIBUTION = 0x02; |