diff options
52 files changed, 1599 insertions, 663 deletions
diff --git a/api/current.txt b/api/current.txt index ebd4c9b6b5f9..8bdafa9c2755 100755 --- a/api/current.txt +++ b/api/current.txt @@ -11313,6 +11313,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin"; field public static final java.lang.String FEATURE_EMBEDDED = "android.hardware.type.embedded"; field public static final java.lang.String FEATURE_ETHERNET = "android.hardware.ethernet"; + field public static final java.lang.String FEATURE_FACE = "android.hardware.face"; field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch"; field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct"; field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand"; @@ -11322,6 +11323,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors"; field public static final java.lang.String FEATURE_HOME_SCREEN = "android.software.home_screen"; field public static final java.lang.String FEATURE_INPUT_METHODS = "android.software.input_methods"; + field public static final java.lang.String FEATURE_IRIS = "android.hardware.iris"; field public static final java.lang.String FEATURE_LEANBACK = "android.software.leanback"; field public static final java.lang.String FEATURE_LEANBACK_ONLY = "android.software.leanback_only"; field public static final java.lang.String FEATURE_LIVE_TV = "android.software.live_tv"; @@ -13784,7 +13786,7 @@ package android.graphics { field public static final int YV12 = 842094169; // 0x32315659 } - public class Insets { + public final class Insets { method public static android.graphics.Insets of(int, int, int, int); method public static android.graphics.Insets of(android.graphics.Rect); field public static final android.graphics.Insets NONE; diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 3c9f7eee10b6..2ecfbe733bca 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -133,7 +133,7 @@ message Atom { } // Pulled events will start at field 10000. - // Next: 10024 + // Next: 10025 oneof pulled { WifiBytesTransfer wifi_bytes_transfer = 10000; WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001; @@ -159,6 +159,7 @@ message Atom { Temperature temperature = 10021; BinderCalls binder_calls = 10022; BinderCallsExceptions binder_calls_exceptions = 10023; + LooperStats looper_stats = 10024; } // DO NOT USE field numbers above 100,000 in AOSP. Field numbers above @@ -2203,3 +2204,50 @@ message BinderCallsExceptions { // Total number of exceptions. optional int64 exception_count = 2; } + +message LooperStats { + // Currently not collected and always set to 0. + optional int32 uid = 1 [(is_uid) = true]; + + // Fully qualified class name of the handler target class. + // + // This field does not contain PII. This is a system server class name. + optional string handler_class_name = 2; + + // The name of the thread that runs the Looper. + // + // This field does not contain PII. This is a system server thread name. + optional string looper_thread_name = 3; + + // The name of the dispatched message. + // + // This field does not contain PII. This is a system server constant or class + // name. + optional string message_name = 4; + + // Total number of successfully dispatched messages. + optional int64 message_count = 5; + + // Total number of messages that failed dispatching. + optional int64 exception_count = 6; + + // Total number of processed messages we have data recorded for. If we + // collected data for all the messages, message_count will be equal to + // recorded_message_count. + // + // If recorded_message_count is different than message_count, it means data + // collection has been sampled. All the fields below will be sampled in this + // case. + optional int64 recorded_message_count = 7; + + // Total latency of all processed messages. + // Average can be computed using recorded_total_latency_micros / + // recorded_message_count. + optional int64 recorded_total_latency_micros = 8; + + // Total CPU usage of all processed message. + // Average can be computed using recorded_total_cpu_micros / + // recorded_message_count. Total can be computed using + // recorded_total_cpu_micros / recorded_message_count * call_count. + optional int64 recorded_total_cpu_micros = 9; +} diff --git a/cmds/statsd/src/external/Perfetto.cpp b/cmds/statsd/src/external/Perfetto.cpp index e44351b39769..42cc543f18a8 100644 --- a/cmds/statsd/src/external/Perfetto.cpp +++ b/cmds/statsd/src/external/Perfetto.cpp @@ -105,9 +105,9 @@ bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config, readPipe.reset(); // Close the read end (owned by the child process). - // Using fopen() because fwrite() has the right logic to chunking write() + // Using fdopen() because fwrite() has the right logic to chunking write() // over a pipe (see __sfvwrite()). - FILE* writePipeStream = fdopen(writePipe.get(), "wb"); + FILE* writePipeStream = android::base::Fdopen(std::move(writePipe), "wb"); if (!writePipeStream) { ALOGE("fdopen() failed while calling the Perfetto client: %s", strerror(errno)); return false; diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index e6e84550cf5f..28718823bb32 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -183,7 +183,13 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { {{}, {}, 1 * NS_PER_SEC, - new StatsCompanionServicePuller(android::util::BINDER_CALLS_EXCEPTIONS)}} + new StatsCompanionServicePuller(android::util::BINDER_CALLS_EXCEPTIONS)}}, + // looper_stats + {android::util::LOOPER_STATS, + {{5, 6, 7, 8, 9}, + {2, 3, 4}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::LOOPER_STATS)}} }; StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) { diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 7d8ff4c3d0c8..5b0e85632b90 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2274,7 +2274,6 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device has biometric hardware to perform face authentication. - * @hide */ @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_FACE = "android.hardware.face"; @@ -2282,7 +2281,6 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device has biometric hardware to perform iris authentication. - * @hide */ @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_IRIS = "android.hardware.iris"; diff --git a/core/java/android/hardware/display/DisplayViewport.java b/core/java/android/hardware/display/DisplayViewport.java index b4955ea44288..496f34c0348a 100644 --- a/core/java/android/hardware/display/DisplayViewport.java +++ b/core/java/android/hardware/display/DisplayViewport.java @@ -30,6 +30,12 @@ import android.text.TextUtils; * @hide Only for use within the system server. */ public final class DisplayViewport { + + // Viewport constants defined in InputReader.h. + public static final int VIEWPORT_INTERNAL = 1; + public static final int VIEWPORT_EXTERNAL = 2; + public static final int VIEWPORT_VIRTUAL = 3; + // True if this viewport is valid. public boolean valid; diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index 3141be4e9e97..ae0855a684ed 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -300,6 +300,23 @@ public class UsbManager { public static final String EXTRA_PERMISSION_GRANTED = "permission"; /** + * Name of extra added to start systemui.usb.UsbPermissionActivity + * containing package name of the app which requests USB permission. + * + * @hide + */ + public static final String EXTRA_PACKAGE = "android.hardware.usb.extra.PACKAGE"; + + /** + * Name of extra added to start systemui.usb.UsbPermissionActivity + * containing the whether the app which requests USB permission can be set as default handler + * for USB device attach event or USB accessory attach event or not. + * + * @hide + */ + public static final String EXTRA_CAN_BE_DEFAULT = "android.hardware.usb.extra.CAN_BE_DEFAULT"; + + /** * Code for the charging usb function. Passed into {@link #setCurrentFunctions(long)} * {@hide} */ diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java index 684a8ee43c87..ded3a1983fb2 100644 --- a/core/java/android/os/Looper.java +++ b/core/java/android/os/Looper.java @@ -18,7 +18,6 @@ package android.os; import android.annotation.NonNull; import android.annotation.Nullable; -import android.os.LooperProto; import android.util.Log; import android.util.Printer; import android.util.Slog; @@ -70,6 +69,7 @@ public final class Looper { // sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); private static Looper sMainLooper; // guarded by Looper.class + private static Observer sObserver; final MessageQueue mQueue; final Thread mThread; @@ -131,6 +131,15 @@ public final class Looper { } /** + * Set the transaction observer for all Loopers in this process. + * + * @hide + */ + public static void setObserver(@Nullable Observer observer) { + sObserver = observer; + } + + /** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ @@ -169,6 +178,8 @@ public final class Looper { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } + // Make sure the observer won't change while processing a transaction. + final Observer observer = sObserver; final long traceTag = me.mTraceTag; long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs; @@ -189,9 +200,21 @@ public final class Looper { final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0; final long dispatchEnd; + Object token = null; + if (observer != null) { + token = observer.messageDispatchStarting(); + } try { msg.target.dispatchMessage(msg); + if (observer != null) { + observer.messageDispatched(token, msg); + } dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; + } catch (Exception exception) { + if (observer != null) { + observer.dispatchingThrewException(token, msg, exception); + } + throw exception; } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); @@ -397,4 +420,39 @@ public final class Looper { return "Looper (" + mThread.getName() + ", tid " + mThread.getId() + ") {" + Integer.toHexString(System.identityHashCode(this)) + "}"; } + + /** {@hide} */ + public interface Observer { + /** + * Called right before a message is dispatched. + * + * <p> The token type is not specified to allow the implementation to specify its own type. + * + * @return a token used for collecting telemetry when dispatching a single message. + * The token token must be passed back exactly once to either + * {@link Observer#messageDispatched} or {@link Observer#dispatchingThrewException} + * and must not be reused again. + * + */ + Object messageDispatchStarting(); + + /** + * Called when a message was processed by a Handler. + * + * @param token Token obtained by previously calling + * {@link Observer#messageDispatchStarting} on the same Observer instance. + * @param msg The message that was dispatched. + */ + void messageDispatched(Object token, Message msg); + + /** + * Called when an exception was thrown while processing a message. + * + * @param token Token obtained by previously calling + * {@link Observer#messageDispatchStarting} on the same Observer instance. + * @param msg The message that was dispatched and caused an exception. + * @param exception The exception that was thrown. + */ + void dispatchingThrewException(Object token, Message msg, Exception exception); + } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index a1cc67d661e3..71938d219ccc 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -13308,6 +13308,23 @@ public final class Settings { * @hide */ public static final String BINDER_CALLS_STATS = "binder_calls_stats"; + + /** + * Default user id to boot into. They map to user ids, for example, 10, 11, 12. + * + * @hide + */ + public static final String DEFAULT_USER_ID_TO_BOOT_INTO = "default_boot_into_user_id"; + + /** + * Persistent user id that is last logged in to. + * + * They map to user ids, for example, 10, 11, 12. + * + * @hide + */ + public static final String LAST_ACTIVE_USER_ID = "last_active_persistent_user_id"; + } /** diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index febdb83f0af3..4bd86a44a8ed 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -164,8 +164,7 @@ public abstract class WallpaperService extends Service { int mType; int mCurWidth; int mCurHeight; - int mWindowFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE - | WindowManager.LayoutParams.FLAG_SCALED; + int mWindowFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; int mWindowPrivateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS; int mCurWindowFlags = mWindowFlags; @@ -776,6 +775,7 @@ public abstract class WallpaperService extends Service { mDisplay.getDisplayInfo(displayInfo); mLayout.width = Math.max(displayInfo.logicalWidth, myWidth); mLayout.height = Math.max(displayInfo.logicalHeight, myHeight); + mWindowFlags |= WindowManager.LayoutParams.FLAG_SCALED; } mLayout.format = mFormat; @@ -785,8 +785,7 @@ public abstract class WallpaperService extends Service { | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_SCALED; + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; mCurWindowPrivateFlags = mWindowPrivateFlags; mLayout.privateFlags = mWindowPrivateFlags; diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index a7f14b6bf0c6..b5ade2a3b654 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -45,6 +45,7 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put("settings_systemui_theme", "true"); DEFAULT_FLAGS.put("settings_dynamic_homepage", "false"); DEFAULT_FLAGS.put("settings_mobile_network_v2", "false"); + DEFAULT_FLAGS.put("settings_data_usage_v2", "false"); DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "true"); } diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java new file mode 100644 index 000000000000..edf475f1dba3 --- /dev/null +++ b/core/java/com/android/internal/os/LooperStats.java @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import android.annotation.NonNull; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.SystemClock; +import android.util.SparseArray; + +import com.android.internal.annotations.GuardedBy; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ThreadLocalRandom; + +/** + * Collects aggregated telemetry data about Looper message dispatching. + * + * @hide Only for use within the system server. + */ +public class LooperStats implements Looper.Observer { + private static final int TOKEN_POOL_SIZE = 50; + private static final int DEFAULT_ENTRIES_SIZE_CAP = 2000; + private static final int DEFAULT_SAMPLING_INTERVAL = 100; + + @GuardedBy("mLock") + private final SparseArray<Entry> mEntries = new SparseArray<>(256); + private final Object mLock = new Object(); + private final Entry mOverflowEntry = new Entry("OVERFLOW"); + private final Entry mHashCollisionEntry = new Entry("HASH_COLLISION"); + private final ConcurrentLinkedQueue<DispatchSession> mSessionPool = + new ConcurrentLinkedQueue<>(); + private final int mSamplingInterval; + private final int mEntriesSizeCap; + + public LooperStats() { + this(DEFAULT_SAMPLING_INTERVAL, DEFAULT_ENTRIES_SIZE_CAP); + } + + public LooperStats(int samplingInterval, int entriesSizeCap) { + this.mSamplingInterval = samplingInterval; + this.mEntriesSizeCap = entriesSizeCap; + } + + @Override + public Object messageDispatchStarting() { + if (shouldCollectDetailedData()) { + DispatchSession session = mSessionPool.poll(); + session = session == null ? new DispatchSession() : session; + session.startTimeMicro = getElapsedRealtimeMicro(); + session.cpuStartMicro = getThreadTimeMicro(); + return session; + } + + return DispatchSession.NOT_SAMPLED; + } + + @Override + public void messageDispatched(Object token, Message msg) { + DispatchSession session = (DispatchSession) token; + Entry entry = getOrCreateEntry(msg); + synchronized (entry) { + entry.messageCount++; + if (session != DispatchSession.NOT_SAMPLED) { + entry.recordedMessageCount++; + long latency = getElapsedRealtimeMicro() - session.startTimeMicro; + long cpuUsage = getThreadTimeMicro() - session.cpuStartMicro; + entry.totalLatencyMicro += latency; + entry.maxLatencyMicro = Math.max(entry.maxLatencyMicro, latency); + entry.cpuUsageMicro += cpuUsage; + entry.maxCpuUsageMicro = Math.max(entry.maxCpuUsageMicro, cpuUsage); + } + } + + recycleSession(session); + } + + @Override + public void dispatchingThrewException(Object token, Message msg, Exception exception) { + DispatchSession session = (DispatchSession) token; + Entry entry = getOrCreateEntry(msg); + synchronized (entry) { + entry.exceptionCount++; + } + recycleSession(session); + } + + /** Returns an array of {@link ExportedEntry entries} with the aggregated statistics. */ + public List<ExportedEntry> getEntries() { + final ArrayList<ExportedEntry> entries; + synchronized (mLock) { + final int size = mEntries.size(); + entries = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + Entry entry = mEntries.valueAt(i); + synchronized (entry) { + entries.add(new ExportedEntry(entry)); + } + } + } + // Add the overflow and collision entries only if they have any data. + if (mOverflowEntry.messageCount > 0 || mOverflowEntry.exceptionCount > 0) { + synchronized (mOverflowEntry) { + entries.add(new ExportedEntry(mOverflowEntry)); + } + } + if (mHashCollisionEntry.messageCount > 0 || mHashCollisionEntry.exceptionCount > 0) { + synchronized (mHashCollisionEntry) { + entries.add(new ExportedEntry(mHashCollisionEntry)); + } + } + return entries; + } + + /** Removes all collected data. */ + public void reset() { + synchronized (mLock) { + mEntries.clear(); + } + synchronized (mHashCollisionEntry) { + mHashCollisionEntry.reset(); + } + synchronized (mOverflowEntry) { + mOverflowEntry.reset(); + } + } + + @NonNull + private Entry getOrCreateEntry(Message msg) { + final int id = Entry.idFor(msg); + Entry entry; + synchronized (mLock) { + entry = mEntries.get(id); + if (entry == null) { + if (mEntries.size() >= mEntriesSizeCap) { + // If over the size cap, track totals under a single entry. + return mOverflowEntry; + } + entry = new Entry(msg); + mEntries.put(id, entry); + } + } + + if (entry.handler.getClass() != msg.getTarget().getClass() + || entry.handler.getLooper().getThread() + != msg.getTarget().getLooper().getThread()) { + // If a hash collision happened, track totals under a single entry. + return mHashCollisionEntry; + } + return entry; + } + + private void recycleSession(DispatchSession session) { + if (session != DispatchSession.NOT_SAMPLED && mSessionPool.size() < TOKEN_POOL_SIZE) { + mSessionPool.add(session); + } + } + + protected long getThreadTimeMicro() { + return SystemClock.currentThreadTimeMicro(); + } + + protected long getElapsedRealtimeMicro() { + return SystemClock.elapsedRealtimeNanos() / 1000; + } + + protected boolean shouldCollectDetailedData() { + return ThreadLocalRandom.current().nextInt() % mSamplingInterval == 0; + } + + private static class DispatchSession { + static final DispatchSession NOT_SAMPLED = new DispatchSession(); + public long startTimeMicro; + public long cpuStartMicro; + } + + private static class Entry { + public final Handler handler; + public final String messageName; + public long messageCount; + public long recordedMessageCount; + public long exceptionCount; + public long totalLatencyMicro; + public long maxLatencyMicro; + public long cpuUsageMicro; + public long maxCpuUsageMicro; + + Entry(Message msg) { + handler = msg.getTarget(); + messageName = handler.getMessageName(msg); + } + + Entry(String specialEntryName) { + handler = null; + messageName = specialEntryName; + } + + void reset() { + messageCount = 0; + recordedMessageCount = 0; + exceptionCount = 0; + totalLatencyMicro = 0; + maxLatencyMicro = 0; + cpuUsageMicro = 0; + maxCpuUsageMicro = 0; + } + + static int idFor(Message msg) { + int result = 7; + result = 31 * result + msg.getTarget().getLooper().getThread().hashCode(); + result = 31 * result + msg.getTarget().getClass().hashCode(); + if (msg.getCallback() != null) { + return 31 * result + msg.getCallback().getClass().hashCode(); + } else { + return 31 * result + msg.what; + } + } + } + + /** Aggregated data of Looper message dispatching in the in the current process. */ + public static class ExportedEntry { + public final String handlerClassName; + public final String threadName; + public final String messageName; + public final long messageCount; + public final long recordedMessageCount; + public final long exceptionCount; + public final long totalLatencyMicros; + public final long maxLatencyMicros; + public final long cpuUsageMicros; + public final long maxCpuUsageMicros; + + ExportedEntry(Entry entry) { + if (entry.handler != null) { + this.handlerClassName = entry.handler.getClass().getName(); + this.threadName = entry.handler.getLooper().getThread().getName(); + } else { + // Overflow/collision entries do not have a handler set. + this.handlerClassName = ""; + this.threadName = ""; + } + this.messageName = entry.messageName; + this.messageCount = entry.messageCount; + this.recordedMessageCount = entry.recordedMessageCount; + this.exceptionCount = entry.exceptionCount; + this.totalLatencyMicros = entry.totalLatencyMicro; + this.maxLatencyMicros = entry.maxLatencyMicro; + this.cpuUsageMicros = entry.cpuUsageMicro; + this.maxCpuUsageMicros = entry.maxCpuUsageMicro; + } + } +} diff --git a/core/jni/android_hardware_display_DisplayViewport.cpp b/core/jni/android_hardware_display_DisplayViewport.cpp index 23c3877e1200..ab8e685d5441 100644 --- a/core/jni/android_hardware_display_DisplayViewport.cpp +++ b/core/jni/android_hardware_display_DisplayViewport.cpp @@ -61,7 +61,7 @@ status_t android_hardware_display_DisplayViewport_toNative(JNIEnv* env, jobject jstring uniqueId = jstring(env->GetObjectField(viewportObj, gDisplayViewportClassInfo.uniqueId)); if (uniqueId != nullptr) { - viewport->uniqueId.setTo(ScopedUtfChars(env, uniqueId).c_str()); + viewport->uniqueId = ScopedUtfChars(env, uniqueId).c_str(); } jobject logicalFrameObj = diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp index 494fad7900ef..a698d66965e4 100644 --- a/core/jni/android_view_InputDevice.cpp +++ b/core/jni/android_view_InputDevice.cpp @@ -37,13 +37,13 @@ static struct { } gInputDeviceClassInfo; jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& deviceInfo) { - ScopedLocalRef<jstring> nameObj(env, env->NewStringUTF(deviceInfo.getDisplayName().string())); + ScopedLocalRef<jstring> nameObj(env, env->NewStringUTF(deviceInfo.getDisplayName().c_str())); if (!nameObj.get()) { return NULL; } ScopedLocalRef<jstring> descriptorObj(env, - env->NewStringUTF(deviceInfo.getIdentifier().descriptor.string())); + env->NewStringUTF(deviceInfo.getIdentifier().descriptor.c_str())); if (!descriptorObj.get()) { return NULL; } diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 189a4aa4fe28..517cf4df15a1 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -192,6 +192,7 @@ public class SettingsBackupTest { Settings.Global.DEFAULT_DNS_SERVER, Settings.Global.DEFAULT_INSTALL_LOCATION, Settings.Global.DEFAULT_RESTRICT_BACKGROUND_DATA, + Settings.Global.DEFAULT_USER_ID_TO_BOOT_INTO, Settings.Global.DESK_DOCK_SOUND, Settings.Global.DESK_UNDOCK_SOUND, Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, @@ -273,6 +274,7 @@ public class SettingsBackupTest { Settings.Global.KEEP_PROFILE_IN_BACKGROUND, Settings.Global.LANG_ID_UPDATE_CONTENT_URL, Settings.Global.LANG_ID_UPDATE_METADATA_URL, + Settings.Global.LAST_ACTIVE_USER_ID, Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS, Settings.Global.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS, Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST, diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java new file mode 100644 index 000000000000..297202bf4d71 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.platform.test.annotations.Presubmit; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Comparator; +import java.util.List; + +@SmallTest +@RunWith(AndroidJUnit4.class) +@Presubmit +public final class LooperStatsTest { + private HandlerThread mThreadFirst; + private HandlerThread mThreadSecond; + private Handler mHandlerFirst; + private Handler mHandlerSecond; + private Handler mHandlerAnonymous; + + @Before + public void setUp() { + // The tests are all single-threaded. HandlerThreads are created to allow creating Handlers + // and to test Thread name collection. + mThreadFirst = new HandlerThread("TestThread1"); + mThreadSecond = new HandlerThread("TestThread2"); + mThreadFirst.start(); + mThreadSecond.start(); + + mHandlerFirst = new TestHandlerFirst(mThreadFirst.getLooper()); + mHandlerSecond = new TestHandlerSecond(mThreadSecond.getLooper()); + mHandlerAnonymous = new Handler(mThreadFirst.getLooper()) { + /* To create an anonymous subclass. */ + }; + } + + @After + public void tearDown() { + mThreadFirst.quit(); + mThreadSecond.quit(); + } + + @Test + public void testSingleMessageDispatched() { + TestableLooperStats looperStats = new TestableLooperStats(1, 100); + + Object token = looperStats.messageDispatchStarting(); + looperStats.tickRealtime(100); + looperStats.tickThreadTime(10); + looperStats.messageDispatched(token, mHandlerFirst.obtainMessage(1000)); + + List<LooperStats.ExportedEntry> entries = looperStats.getEntries(); + assertThat(entries).hasSize(1); + LooperStats.ExportedEntry entry = entries.get(0); + assertThat(entry.threadName).isEqualTo("TestThread1"); + assertThat(entry.handlerClassName).isEqualTo( + "com.android.internal.os.LooperStatsTest$TestHandlerFirst"); + assertThat(entry.messageName).isEqualTo("0x3e8" /* 1000 in hex */); + assertThat(entry.messageCount).isEqualTo(1); + assertThat(entry.recordedMessageCount).isEqualTo(1); + assertThat(entry.exceptionCount).isEqualTo(0); + assertThat(entry.totalLatencyMicros).isEqualTo(100); + assertThat(entry.maxLatencyMicros).isEqualTo(100); + assertThat(entry.cpuUsageMicros).isEqualTo(10); + assertThat(entry.maxCpuUsageMicros).isEqualTo(10); + } + + @Test + public void testThrewException() { + TestableLooperStats looperStats = new TestableLooperStats(1, 100); + + Object token = looperStats.messageDispatchStarting(); + looperStats.tickRealtime(100); + looperStats.tickThreadTime(10); + looperStats.dispatchingThrewException(token, mHandlerFirst.obtainMessage(7), + new ArithmeticException()); + + List<LooperStats.ExportedEntry> entries = looperStats.getEntries(); + assertThat(entries).hasSize(1); + LooperStats.ExportedEntry entry = entries.get(0); + assertThat(entry.threadName).isEqualTo("TestThread1"); + assertThat(entry.handlerClassName).isEqualTo( + "com.android.internal.os.LooperStatsTest$TestHandlerFirst"); + assertThat(entry.messageName).isEqualTo("0x7" /* 7 in hex */); + assertThat(entry.messageCount).isEqualTo(0); + assertThat(entry.recordedMessageCount).isEqualTo(0); + assertThat(entry.exceptionCount).isEqualTo(1); + assertThat(entry.totalLatencyMicros).isEqualTo(0); + assertThat(entry.maxLatencyMicros).isEqualTo(0); + assertThat(entry.cpuUsageMicros).isEqualTo(0); + assertThat(entry.maxCpuUsageMicros).isEqualTo(0); + } + + @Test + public void testMultipleMessagesDispatched() { + TestableLooperStats looperStats = new TestableLooperStats(2, 100); + + // Contributes to entry2. + Object token1 = looperStats.messageDispatchStarting(); + looperStats.tickRealtime(100); + looperStats.tickThreadTime(10); + looperStats.messageDispatched(token1, mHandlerFirst.obtainMessage(1000)); + + // Contributes to entry2. + Object token2 = looperStats.messageDispatchStarting(); + looperStats.tickRealtime(50); + looperStats.tickThreadTime(20); + looperStats.messageDispatched(token2, mHandlerFirst.obtainMessage(1000)); + + // Contributes to entry3. + Object token3 = looperStats.messageDispatchStarting(); + looperStats.tickRealtime(10); + looperStats.tickThreadTime(10); + looperStats.messageDispatched(token3, mHandlerSecond.obtainMessage().setCallback(() -> { + })); + + // Contributes to entry1. + Object token4 = looperStats.messageDispatchStarting(); + looperStats.tickRealtime(100); + looperStats.tickThreadTime(100); + looperStats.messageDispatched(token4, mHandlerAnonymous.obtainMessage(1)); + + List<LooperStats.ExportedEntry> entries = looperStats.getEntries(); + assertThat(entries).hasSize(3); + entries.sort(Comparator.comparing(e -> e.handlerClassName)); + + // Captures data for token4 call. + LooperStats.ExportedEntry entry1 = entries.get(0); + assertThat(entry1.threadName).isEqualTo("TestThread1"); + assertThat(entry1.handlerClassName).isEqualTo("com.android.internal.os.LooperStatsTest$1"); + assertThat(entry1.messageName).isEqualTo("0x1" /* 1 in hex */); + assertThat(entry1.messageCount).isEqualTo(1); + assertThat(entry1.recordedMessageCount).isEqualTo(0); + assertThat(entry1.exceptionCount).isEqualTo(0); + assertThat(entry1.totalLatencyMicros).isEqualTo(0); + assertThat(entry1.maxLatencyMicros).isEqualTo(0); + assertThat(entry1.cpuUsageMicros).isEqualTo(0); + assertThat(entry1.maxCpuUsageMicros).isEqualTo(0); + + // Captures data for token1 and token2 calls. + LooperStats.ExportedEntry entry2 = entries.get(1); + assertThat(entry2.threadName).isEqualTo("TestThread1"); + assertThat(entry2.handlerClassName).isEqualTo( + "com.android.internal.os.LooperStatsTest$TestHandlerFirst"); + assertThat(entry2.messageName).isEqualTo("0x3e8" /* 1000 in hex */); + assertThat(entry2.messageCount).isEqualTo(2); + assertThat(entry2.recordedMessageCount).isEqualTo(1); + assertThat(entry2.exceptionCount).isEqualTo(0); + assertThat(entry2.totalLatencyMicros).isEqualTo(100); + assertThat(entry2.maxLatencyMicros).isEqualTo(100); + assertThat(entry2.cpuUsageMicros).isEqualTo(10); + assertThat(entry2.maxCpuUsageMicros).isEqualTo(10); + + // Captures data for token3 call. + LooperStats.ExportedEntry entry3 = entries.get(2); + assertThat(entry3.threadName).isEqualTo("TestThread2"); + assertThat(entry3.handlerClassName).isEqualTo( + "com.android.internal.os.LooperStatsTest$TestHandlerSecond"); + assertThat(entry3.messageName).startsWith( + "com.android.internal.os.-$$Lambda$LooperStatsTest$"); + assertThat(entry3.messageCount).isEqualTo(1); + assertThat(entry3.recordedMessageCount).isEqualTo(1); + assertThat(entry3.exceptionCount).isEqualTo(0); + assertThat(entry3.totalLatencyMicros).isEqualTo(10); + assertThat(entry3.maxLatencyMicros).isEqualTo(10); + assertThat(entry3.cpuUsageMicros).isEqualTo(10); + assertThat(entry3.maxCpuUsageMicros).isEqualTo(10); + } + + @Test + public void testMessagesOverSizeCap() { + TestableLooperStats looperStats = new TestableLooperStats(2, 1 /* sizeCap */); + + Object token1 = looperStats.messageDispatchStarting(); + looperStats.tickRealtime(100); + looperStats.tickThreadTime(10); + looperStats.messageDispatched(token1, mHandlerFirst.obtainMessage(1000)); + + Object token2 = looperStats.messageDispatchStarting(); + looperStats.tickRealtime(50); + looperStats.tickThreadTime(20); + looperStats.messageDispatched(token2, mHandlerFirst.obtainMessage(1001)); + + Object token3 = looperStats.messageDispatchStarting(); + looperStats.tickRealtime(10); + looperStats.tickThreadTime(10); + looperStats.messageDispatched(token3, mHandlerFirst.obtainMessage(1002)); + + Object token4 = looperStats.messageDispatchStarting(); + looperStats.tickRealtime(10); + looperStats.tickThreadTime(10); + looperStats.messageDispatched(token4, mHandlerSecond.obtainMessage(1003)); + + List<LooperStats.ExportedEntry> entries = looperStats.getEntries(); + assertThat(entries).hasSize(2); + entries.sort(Comparator.comparing(e -> e.handlerClassName)); + + LooperStats.ExportedEntry entry1 = entries.get(0); + assertThat(entry1.threadName).isEqualTo(""); + assertThat(entry1.handlerClassName).isEqualTo(""); + assertThat(entry1.messageName).isEqualTo("OVERFLOW"); + assertThat(entry1.messageCount).isEqualTo(3); + assertThat(entry1.recordedMessageCount).isEqualTo(1); + assertThat(entry1.exceptionCount).isEqualTo(0); + assertThat(entry1.totalLatencyMicros).isEqualTo(10); + assertThat(entry1.maxLatencyMicros).isEqualTo(10); + assertThat(entry1.cpuUsageMicros).isEqualTo(10); + assertThat(entry1.maxCpuUsageMicros).isEqualTo(10); + + LooperStats.ExportedEntry entry2 = entries.get(1); + assertThat(entry2.threadName).isEqualTo("TestThread1"); + assertThat(entry2.handlerClassName).isEqualTo( + "com.android.internal.os.LooperStatsTest$TestHandlerFirst"); + } + + @Test + public void testInvalidTokensCauseException() { + TestableLooperStats looperStats = new TestableLooperStats(1, 100); + assertThrows(ClassCastException.class, + () -> looperStats.dispatchingThrewException(new Object(), + mHandlerFirst.obtainMessage(), + new ArithmeticException())); + assertThrows(ClassCastException.class, + () -> looperStats.messageDispatched(new Object(), mHandlerFirst.obtainMessage())); + assertThrows(ClassCastException.class, + () -> looperStats.messageDispatched(123, mHandlerFirst.obtainMessage())); + assertThrows(ClassCastException.class, + () -> looperStats.messageDispatched(mHandlerFirst.obtainMessage(), + mHandlerFirst.obtainMessage())); + + assertThat(looperStats.getEntries()).hasSize(0); + } + + @Test + public void testTracksMultipleHandlerInstancesIfSameClass() { + TestableLooperStats looperStats = new TestableLooperStats(1, 100); + Handler handlerFirstAnother = new TestHandlerFirst(mHandlerFirst.getLooper()); + + Object token1 = looperStats.messageDispatchStarting(); + looperStats.messageDispatched(token1, mHandlerFirst.obtainMessage(1000)); + + Object token2 = looperStats.messageDispatchStarting(); + looperStats.messageDispatched(token2, handlerFirstAnother.obtainMessage(1000)); + + assertThat(looperStats.getEntries()).hasSize(1); + assertThat(looperStats.getEntries().get(0).messageCount).isEqualTo(2); + } + + private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) { + try { + r.run(); + Assert.fail("Expected " + exceptionClass + " to be thrown."); + } catch (Exception exception) { + assertThat(exception).isInstanceOf(exceptionClass); + } + } + + private static final class TestableLooperStats extends LooperStats { + private static final long INITIAL_MICROS = 10001000123L; + private int mCount; + private long mRealtimeMicros; + private long mThreadTimeMicros; + private int mSamplingInterval; + + TestableLooperStats(int samplingInterval, int sizeCap) { + super(samplingInterval, sizeCap); + this.mSamplingInterval = samplingInterval; + } + + void tickRealtime(long micros) { + mRealtimeMicros += micros; + } + + void tickThreadTime(long micros) { + mThreadTimeMicros += micros; + } + + @Override + protected long getElapsedRealtimeMicro() { + return INITIAL_MICROS + mRealtimeMicros; + } + + @Override + protected long getThreadTimeMicro() { + return INITIAL_MICROS + mThreadTimeMicros; + } + + @Override + protected boolean shouldCollectDetailedData() { + return mCount++ % mSamplingInterval == 0; + } + } + + private static final class TestHandlerFirst extends Handler { + TestHandlerFirst(Looper looper) { + super(looper); + } + } + + private static final class TestHandlerSecond extends Handler { + TestHandlerSecond(Looper looper) { + super(looper); + } + } +} diff --git a/graphics/java/android/graphics/Insets.java b/graphics/java/android/graphics/Insets.java index 5a78530852c7..c3449dd4fb47 100644 --- a/graphics/java/android/graphics/Insets.java +++ b/graphics/java/android/graphics/Insets.java @@ -16,6 +16,9 @@ package android.graphics; +import android.annotation.NonNull; +import android.annotation.Nullable; + /** * An Insets instance holds four integer offsets which describe changes to the four * edges of a Rectangle. By convention, positive values move edges towards the @@ -24,7 +27,7 @@ package android.graphics; * Insets are immutable so may be treated as values. * */ -public class Insets { +public final class Insets { public static final Insets NONE = new Insets(0, 0, 0, 0); public final int left; @@ -51,7 +54,7 @@ public class Insets { * * @return Insets instance with the appropriate values */ - public static Insets of(int left, int top, int right, int bottom) { + public static @NonNull Insets of(int left, int top, int right, int bottom) { if (left == 0 && top == 0 && right == 0 && bottom == 0) { return NONE; } @@ -65,7 +68,7 @@ public class Insets { * * @return an Insets instance with the appropriate values */ - public static Insets of(Rect r) { + public static @NonNull Insets of(@Nullable Rect r) { return (r == null) ? NONE : of(r.left, r.top, r.right, r.bottom); } diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 67682a06cb6a..c5a6ec590d30 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -36,9 +36,8 @@ cc_library_shared { cflags: [ "-Wall", + "-Wextra", "-Werror", - "-Wunused", - "-Wunreachable-code", ], } diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h index 4794f3da824c..eb3469e0b3f0 100644 --- a/libs/input/PointerController.h +++ b/libs/input/PointerController.h @@ -28,7 +28,6 @@ #include <utils/BitSet.h> #include <utils/RefBase.h> #include <utils/Looper.h> -#include <utils/String8.h> #include <gui/DisplayEventReceiver.h> namespace android { diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp index 173cd507d943..eb2bc98ec9e9 100644 --- a/libs/input/SpriteController.cpp +++ b/libs/input/SpriteController.cpp @@ -23,14 +23,10 @@ #include <utils/String8.h> #include <gui/Surface.h> -// ToDo: Fix code to be warning free -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" #include <SkBitmap.h> #include <SkCanvas.h> #include <SkColor.h> #include <SkPaint.h> -#pragma GCC diagnostic pop #include <android/native_window.h> diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java index 663b1f5e4789..240a19279739 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java @@ -675,6 +675,7 @@ public class ApplicationsState { if (!mResumed) { mResumed = true; mSessionsChanged = true; + doPauseLocked(); doResumeIfNeededLocked(); } } diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 19492a08e7a2..11bd392b7d52 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -79,13 +79,6 @@ <!-- Show camera affordance on Keyguard --> <bool name="config_keyguardShowCameraAffordance">false</bool> - <!-- Whether we should use SRC drawing mode when drawing the scrim behind. If this flag is set, - we change the canvas opacity so libhwui doesn't call glClear on our surface, and then we - draw the scrim with SRC to overwrite the whole buffer, which saves us a layer of overdraw. - However, SRC performs poorly on some devices, where it is more efficient to - glClear + SRC_OVER, in which case this flag should be disabled. --> - <bool name="config_status_bar_scrim_behind_use_src">true</bool> - <!-- The length of the vibration when the notification pops open. --> <integer name="one_finger_pop_duration_ms">10</integer> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index d051f07e44a8..26eadb5bfa2d 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -361,7 +361,7 @@ <dimen name="qs_quick_layout_width">-1px</dimen> <dimen name="qs_quick_tile_padding">12dp</dimen> <dimen name="qs_header_gear_translation">16dp</dimen> - <dimen name="qs_header_tile_margin_horizontal">0dp</dimen> + <dimen name="qs_header_tile_margin_horizontal">4dp</dimen> <dimen name="qs_page_indicator_width">16dp</dimen> <dimen name="qs_page_indicator_height">8dp</dimen> <dimen name="qs_tile_icon_size">24dp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java index eaa4c6de0202..3bc434280c51 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java @@ -53,11 +53,8 @@ public class ScrimView extends View implements ConfigurationController.Configura private static final String TAG = "ScrimView"; private final ColorExtractor.GradientColors mColors; private int mDensity; - private boolean mDrawAsSrc; private float mViewAlpha = 1.0f; private ValueAnimator mAlphaAnimator; - private Rect mExcludedRect = new Rect(); - private boolean mHasExcludedArea; private Drawable mDrawable; private PorterDuffColorFilter mColorFilter; private int mTintColor; @@ -137,59 +134,8 @@ public class ScrimView extends View implements ConfigurationController.Configura @Override protected void onDraw(Canvas canvas) { - if (mDrawAsSrc || mDrawable.getAlpha() > 0) { - if (!mHasExcludedArea) { - mDrawable.draw(canvas); - } else { - if (mExcludedRect.top > 0) { - canvas.save(); - canvas.clipRect(0, 0, getWidth(), mExcludedRect.top); - mDrawable.draw(canvas); - canvas.restore(); - } - if (mExcludedRect.left > 0) { - canvas.save(); - canvas.clipRect(0, mExcludedRect.top, mExcludedRect.left, - mExcludedRect.bottom); - mDrawable.draw(canvas); - canvas.restore(); - } - if (mExcludedRect.right < getWidth()) { - canvas.save(); - canvas.clipRect(mExcludedRect.right, mExcludedRect.top, getWidth(), - mExcludedRect.bottom); - mDrawable.draw(canvas); - canvas.restore(); - } - if (mExcludedRect.bottom < getHeight()) { - canvas.save(); - canvas.clipRect(0, mExcludedRect.bottom, getWidth(), getHeight()); - mDrawable.draw(canvas); - canvas.restore(); - } - // We also need to draw the rounded corners of the background - canvas.save(); - canvas.clipRect(mExcludedRect.left, mExcludedRect.top, - mExcludedRect.left + mCornerRadius, mExcludedRect.top + mCornerRadius); - mDrawable.draw(canvas); - canvas.restore(); - canvas.save(); - canvas.clipRect(mExcludedRect.right - mCornerRadius, mExcludedRect.top, - mExcludedRect.right, mExcludedRect.top + mCornerRadius); - mDrawable.draw(canvas); - canvas.restore(); - canvas.save(); - canvas.clipRect(mExcludedRect.left, mExcludedRect.bottom - mCornerRadius, - mExcludedRect.left + mCornerRadius, mExcludedRect.bottom); - mDrawable.draw(canvas); - canvas.restore(); - canvas.save(); - canvas.clipRect(mExcludedRect.right - mCornerRadius, - mExcludedRect.bottom - mCornerRadius, - mExcludedRect.right, mExcludedRect.bottom); - mDrawable.draw(canvas); - canvas.restore(); - } + if (mDrawable.getAlpha() > 0) { + mDrawable.draw(canvas); } } @@ -198,7 +144,6 @@ public class ScrimView extends View implements ConfigurationController.Configura mDrawable.setCallback(this); mDrawable.setBounds(getLeft(), getTop(), getRight(), getBottom()); mDrawable.setAlpha((int) (255 * mViewAlpha)); - setDrawAsSrc(mDrawAsSrc); updateScreenSize(); invalidate(); } @@ -211,12 +156,6 @@ public class ScrimView extends View implements ConfigurationController.Configura } } - public void setDrawAsSrc(boolean asSrc) { - mDrawAsSrc = asSrc; - PorterDuff.Mode mode = asSrc ? PorterDuff.Mode.SRC : PorterDuff.Mode.SRC_OVER; - mDrawable.setXfermode(new PorterDuffXfermode(mode)); - } - @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); @@ -328,22 +267,6 @@ public class ScrimView extends View implements ConfigurationController.Configura return mViewAlpha; } - public void setExcludedArea(Rect area) { - if (area == null) { - mHasExcludedArea = false; - invalidate(); - return; - } - - int left = Math.max(area.left, 0); - int top = Math.max(area.top, 0); - int right = Math.min(area.right, getWidth()); - int bottom = Math.min(area.bottom, getHeight()); - mExcludedRect.set(left, top, right, bottom); - mHasExcludedArea = left < right && top < bottom; - invalidate(); - } - public void setChangeRunnable(Runnable changeRunnable) { mChangeRunnable = changeRunnable; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 4f554b656b26..1883aa7e7845 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -394,9 +394,6 @@ public class NotificationStackScrollLayout extends ViewGroup }; private PorterDuffXfermode mSrcMode = new PorterDuffXfermode(PorterDuff.Mode.SRC); private boolean mPulsing; - private boolean mDrawBackgroundAsSrc; - private boolean mFadingOut; - private boolean mParentNotFullyVisible; private boolean mGroupExpandedForMeasure; private boolean mScrollable; private View mForcedScroll; @@ -789,21 +786,6 @@ public class NotificationStackScrollLayout extends ViewGroup R.dimen.heads_up_status_bar_padding); } - public void setDrawBackgroundAsSrc(boolean asSrc) { - mDrawBackgroundAsSrc = asSrc; - updateSrcDrawing(); - } - - private void updateSrcDrawing() { - if (!mShouldDrawNotificationBackground) { - return; - } - - mBackgroundPaint.setXfermode(mDrawBackgroundAsSrc && !mFadingOut && !mParentNotFullyVisible - ? mSrcMode : null); - invalidate(); - } - private void notifyHeightChangeListener(ExpandableView view) { notifyHeightChangeListener(view, false /* needsAnimation */); } @@ -1128,7 +1110,6 @@ public class NotificationStackScrollLayout extends ViewGroup && !mHeadsUpAnimatingAway; if (mIsClipped != clipped) { mIsClipped = clipped; - updateFadingState(); } if (animatingClipping) { @@ -2447,7 +2428,7 @@ public class NotificationStackScrollLayout extends ViewGroup startBackgroundAnimation(); } else { mCurrentBounds.set(mBackgroundBounds); - applyCurrentBackgroundBounds(); + invalidate(); } } else { abortBackgroundAnimators(); @@ -2575,25 +2556,11 @@ public class NotificationStackScrollLayout extends ViewGroup private void setBackgroundTop(int top) { mCurrentBounds.top = top; - applyCurrentBackgroundBounds(); + invalidate(); } public void setBackgroundBottom(int bottom) { mCurrentBounds.bottom = bottom; - applyCurrentBackgroundBounds(); - } - - private void applyCurrentBackgroundBounds() { - // If the background of the notification is not being drawn, then there is no need to - // exclude an area in the scrim. Rather, the scrim's color should serve as the background. - if (!mShouldDrawNotificationBackground) { - return; - } - - final boolean awake = mInterpolatedDarkAmount != 0 || mAmbientState.isDark(); - mScrimController.setExcludedBackgroundArea( - mFadingOut || mParentNotFullyVisible || awake || mIsClipped ? null - : mCurrentBounds); invalidate(); } @@ -4176,7 +4143,6 @@ public class NotificationStackScrollLayout extends ViewGroup updateBackground(); } requestChildrenUpdate(); - applyCurrentBackgroundBounds(); updateWillNotDraw(); notifyHeightChangeListener(mShelf); } @@ -4650,35 +4616,6 @@ public class NotificationStackScrollLayout extends ViewGroup } } - public void setFadingOut(boolean fadingOut) { - if (fadingOut != mFadingOut) { - mFadingOut = fadingOut; - updateFadingState(); - } - } - - public void setParentNotFullyVisible(boolean parentNotFullyVisible) { - if (mScrimController == null) { - // we're not set up yet. - return; - } - if (parentNotFullyVisible != mParentNotFullyVisible) { - mParentNotFullyVisible = parentNotFullyVisible; - updateFadingState(); - } - } - - private void updateFadingState() { - applyCurrentBackgroundBounds(); - updateSrcDrawing(); - } - - @Override - public void setAlpha(@FloatRange(from = 0.0, to = 1.0) float alpha) { - super.setAlpha(alpha); - setFadingOut(alpha != 1.0f); - } - public void setQsExpanded(boolean qsExpanded) { mQsExpanded = qsExpanded; updateAlgorithmLayoutMinHeight(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 33ddfde845a5..e5e5d4038c37 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -2668,32 +2668,6 @@ public class NotificationPanelView extends PanelView implements setLaunchingAffordance(false); } - @Override - public void setAlpha(float alpha) { - super.setAlpha(alpha); - updateFullyVisibleState(false /* forceNotFullyVisible */); - } - - /** - * Must be called before starting a ViewPropertyAnimator alpha animation because those - * do NOT call setAlpha and therefore don't properly update the fullyVisibleState. - */ - public void notifyStartFading() { - updateFullyVisibleState(true /* forceNotFullyVisible */); - } - - @Override - public void setVisibility(int visibility) { - super.setVisibility(visibility); - updateFullyVisibleState(false /* forceNotFullyVisible */); - } - - private void updateFullyVisibleState(boolean forceNotFullyVisible) { - mNotificationStackScroller.setParentNotFullyVisible(forceNotFullyVisible - || getAlpha() != 1.0f - || getVisibility() != VISIBLE); - } - /** * Set whether we are currently launching an affordance. This is currently only set when * launched via a camera gesture. @@ -2992,10 +2966,6 @@ public class NotificationPanelView extends PanelView implements mNotificationStackScroller.setActivatedChild(o); } - public void setParentNotFullyVisible(boolean parent) { - mNotificationStackScroller.setParentNotFullyVisible(parent); - } - public void runAfterAnimationFinished(Runnable r) { mNotificationStackScroller.runAfterAnimationFinished(r); } @@ -3020,8 +2990,4 @@ public class NotificationPanelView extends PanelView implements mNotificationStackScroller.setScrimController(scrimController); updateShowEmptyShadeView(); } - - public void setDrawBackgroundAsSrc(boolean asSrc) { - mNotificationStackScroller.setDrawBackgroundAsSrc(asSrc); - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 0c361ce26e34..e3a7b75554d3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -685,10 +685,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo return scrim.getTag(TAG_KEY_ANIM) != null; } - public void setDrawBehindAsSrc(boolean asSrc) { - mScrimBehind.setDrawAsSrc(asSrc); - } - @VisibleForTesting void setOnAnimationFinished(Runnable onAnimationFinished) { mOnAnimationFinished = onAnimationFinished; @@ -800,10 +796,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo return Handler.getMain(); } - public void setExcludedBackgroundArea(Rect area) { - mScrimBehind.setExcludedArea(area); - } - public int getBackgroundColor() { int color = mLockColors.getMainColor(); return Color.argb((int) (mScrimBehind.getViewAlpha() * Color.alpha(color)), diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 9beaa10d6bd0..7ec4db21b694 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -328,14 +328,6 @@ public class StatusBar extends SystemUI implements DemoMode, /** If true, the lockscreen will show a distinct wallpaper */ private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true; - /** - * Never let the alpha become zero for surfaces that draw with SRC - otherwise the RenderNode - * won't draw anything and uninitialized memory will show through - * if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in - * libhwui. - */ - private static final float SRC_MIN_ALPHA = 0.002f; - static { boolean onlyCoreApps; try { @@ -485,7 +477,6 @@ public class StatusBar extends SystemUI implements DemoMode, protected boolean mDozing; private boolean mDozingRequested; - protected boolean mScrimSrcModeEnabled; protected BackDropView mBackdrop; protected ImageView mBackdropFront, mBackdropBack; @@ -652,7 +643,6 @@ public class StatusBar extends SystemUI implements DemoMode, mVibrateOnOpening = mContext.getResources().getBoolean( R.bool.config_vibrateOnIconAnimation); mVibratorHelper = Dependency.get(VibratorHelper.class); - mScrimSrcModeEnabled = res.getBoolean(R.bool.config_status_bar_scrim_behind_use_src); DateTimeView.setReceiverHandler(Dependency.get(Dependency.TIME_TICK_HANDLER)); putComponent(StatusBar.class, this); @@ -948,15 +938,6 @@ public class StatusBar extends SystemUI implements DemoMode, } }, DozeParameters.getInstance(mContext), mContext.getSystemService(AlarmManager.class)); - if (mScrimSrcModeEnabled) { - Runnable runnable = () -> { - boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE; - mScrimController.setDrawBehindAsSrc(asSrc); - mNotificationPanel.setDrawBackgroundAsSrc(asSrc); - }; - mBackdrop.setOnVisibilityChangedRunnable(runnable); - runnable.run(); - } mNotificationPanel.initDependencies(this, mGroupManager, mNotificationShelf, mHeadsUpManager, mNotificationIconAreaController, mScrimController); mDozeScrimController = new DozeScrimController(mScrimController, context, @@ -1483,7 +1464,7 @@ public class StatusBar extends SystemUI implements DemoMode, if (mBackdrop.getVisibility() != View.VISIBLE) { mBackdrop.setVisibility(View.VISIBLE); if (allowEnterAnimation) { - mBackdrop.setAlpha(SRC_MIN_ALPHA); + mBackdrop.setAlpha(0); mBackdrop.animate().alpha(1f); } else { mBackdrop.animate().cancel(); @@ -1501,9 +1482,6 @@ public class StatusBar extends SystemUI implements DemoMode, mBackdropBack.getDrawable().getConstantState() .newDrawable(mBackdropFront.getResources()).mutate(); mBackdropFront.setImageDrawable(drawable); - if (mScrimSrcModeEnabled) { - mBackdropFront.getDrawable().mutate().setXfermode(mSrcOverXferMode); - } mBackdropFront.setAlpha(1f); mBackdropFront.setVisibility(View.VISIBLE); } else { @@ -1518,9 +1496,6 @@ public class StatusBar extends SystemUI implements DemoMode, } else { mBackdropBack.setImageDrawable(artworkDrawable); } - if (mScrimSrcModeEnabled) { - mBackdropBack.getDrawable().mutate().setXfermode(mSrcXferMode); - } if (mBackdropFront.getVisibility() == View.VISIBLE) { if (DEBUG_MEDIA) { @@ -1553,7 +1528,7 @@ public class StatusBar extends SystemUI implements DemoMode, } else { mStatusBarWindowController.setBackdropShowing(false); mBackdrop.animate() - .alpha(SRC_MIN_ALPHA) + .alpha(0) .setInterpolator(Interpolators.ACCELERATE_DECELERATE) .setDuration(300) .setStartDelay(0) @@ -1765,10 +1740,6 @@ public class StatusBar extends SystemUI implements DemoMode, return mMediaManager.getMediaNotificationKey(); } - public boolean isScrimSrcModeEnabled() { - return mScrimSrcModeEnabled; - } - /** * To be called when there's a state change in StatusBarKeyguardViewManager. */ @@ -3410,7 +3381,6 @@ public class StatusBar extends SystemUI implements DemoMode, updateScrimController(); updateMediaMetaData(false, true); mNotificationPanel.setAlpha(1); - mNotificationPanel.setParentNotFullyVisible(true); mNotificationPanel.animate() .alpha(0) .setStartDelay(FADE_KEYGUARD_START_DELAY) @@ -3432,7 +3402,6 @@ public class StatusBar extends SystemUI implements DemoMode, * fading. */ public void fadeKeyguardWhilePulsing() { - mNotificationPanel.notifyStartFading(); mNotificationPanel.animate() .alpha(0f) .setStartDelay(0) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index 98f1a3693e06..45b32c7abae0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -227,20 +227,7 @@ public class StatusBarWindowView extends FrameLayout { @Override protected void onAttachedToWindow () { super.onAttachedToWindow(); - - // We need to ensure that our window doesn't suffer from overdraw which would normally - // occur if our window is translucent. Since we are drawing the whole window anyway with - // the scrim, we don't need the window to be cleared in the beginning. - if (mService.isScrimSrcModeEnabled()) { - IBinder windowToken = getWindowToken(); - WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams(); - lp.token = windowToken; - setLayoutParams(lp); - WindowManagerGlobal.getInstance().changeCanvasOpacity(windowToken, true); - setWillNotDraw(false); - } else { - setWillNotDraw(!DEBUG); - } + setWillNotDraw(!DEBUG); } @Override @@ -394,26 +381,6 @@ public class StatusBarWindowView extends FrameLayout { @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); - if (mService.isScrimSrcModeEnabled()) { - // We need to ensure that our window is always drawn fully even when we have paddings, - // since we simulate it to be opaque. - int paddedBottom = getHeight() - getPaddingBottom(); - int paddedRight = getWidth() - getPaddingRight(); - if (getPaddingTop() != 0) { - canvas.drawRect(0, 0, getWidth(), getPaddingTop(), mTransparentSrcPaint); - } - if (getPaddingBottom() != 0) { - canvas.drawRect(0, paddedBottom, getWidth(), getHeight(), mTransparentSrcPaint); - } - if (getPaddingLeft() != 0) { - canvas.drawRect(0, getPaddingTop(), getPaddingLeft(), paddedBottom, - mTransparentSrcPaint); - } - if (getPaddingRight() != 0) { - canvas.drawRect(paddedRight, getPaddingTop(), getWidth(), paddedBottom, - mTransparentSrcPaint); - } - } if (DEBUG) { Paint pt = new Paint(); pt.setColor(0x80FFFF00); diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java index 238407a9a6f1..a46f018af816 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java @@ -16,17 +16,13 @@ package com.android.systemui.usb; -import android.annotation.NonNull; import android.app.AlertDialog; import android.app.PendingIntent; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.res.XmlResourceParser; import android.hardware.usb.IUsbManager; import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbDevice; @@ -45,13 +41,8 @@ import android.widget.TextView; import com.android.internal.app.AlertActivity; import com.android.internal.app.AlertController; -import com.android.internal.util.XmlUtils; -import android.hardware.usb.AccessoryFilter; -import android.hardware.usb.DeviceFilter; import com.android.systemui.R; -import org.xmlpull.v1.XmlPullParser; - public class UsbPermissionActivity extends AlertActivity implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener { @@ -71,12 +62,13 @@ public class UsbPermissionActivity extends AlertActivity public void onCreate(Bundle icicle) { super.onCreate(icicle); - Intent intent = getIntent(); + Intent intent = getIntent(); mDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); mPendingIntent = (PendingIntent)intent.getParcelableExtra(Intent.EXTRA_INTENT); mUid = intent.getIntExtra(Intent.EXTRA_UID, -1); - mPackageName = intent.getStringExtra("package"); + mPackageName = intent.getStringExtra(UsbManager.EXTRA_PACKAGE); + boolean canBeDefault = intent.getBooleanExtra(UsbManager.EXTRA_CAN_BE_DEFAULT, false); PackageManager packageManager = getPackageManager(); ApplicationInfo aInfo; @@ -105,121 +97,27 @@ public class UsbPermissionActivity extends AlertActivity ap.mPositiveButtonListener = this; ap.mNegativeButtonListener = this; - try { - PackageInfo packageInfo = packageManager.getPackageInfo(mPackageName, - PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA); - - if ((mDevice != null && canBeDefault(mDevice, packageInfo)) - || (mAccessory != null && canBeDefault(mAccessory, packageInfo))) { - // add "open when" checkbox - LayoutInflater inflater = (LayoutInflater) getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null); - mAlwaysUse = (CheckBox) ap.mView.findViewById(com.android.internal.R.id.alwaysUse); - if (mDevice == null) { - mAlwaysUse.setText(getString(R.string.always_use_accessory, appName, - mAccessory.getDescription())); - } else { - mAlwaysUse.setText(getString(R.string.always_use_device, appName, - mDevice.getProductName())); - } - mAlwaysUse.setOnCheckedChangeListener(this); - - mClearDefaultHint = (TextView)ap.mView.findViewById( - com.android.internal.R.id.clearDefaultHint); - mClearDefaultHint.setVisibility(View.GONE); + if (canBeDefault && (mDevice != null || mAccessory != null)) { + // add "open when" checkbox + LayoutInflater inflater = (LayoutInflater) getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null); + mAlwaysUse = (CheckBox) ap.mView.findViewById(com.android.internal.R.id.alwaysUse); + if (mDevice == null) { + mAlwaysUse.setText(getString(R.string.always_use_accessory, appName, + mAccessory.getDescription())); + } else { + mAlwaysUse.setText(getString(R.string.always_use_device, appName, + mDevice.getProductName())); } - } catch (PackageManager.NameNotFoundException e) { - // ignore - } - - setupAlert(); - - } - - /** - * Can the app be the default for the USB device. I.e. can the app be launched by default if - * the device is plugged in. - * - * @param device The device the app would be default for - * @param packageInfo The package info of the app - * - * @return {@code true} iff the app can be default - */ - private boolean canBeDefault(@NonNull UsbDevice device, @NonNull PackageInfo packageInfo) { - ActivityInfo[] activities = packageInfo.activities; - if (activities != null) { - int numActivities = activities.length; - for (int i = 0; i < numActivities; i++) { - ActivityInfo activityInfo = activities[i]; + mAlwaysUse.setOnCheckedChangeListener(this); - try (XmlResourceParser parser = activityInfo.loadXmlMetaData(getPackageManager(), - UsbManager.ACTION_USB_DEVICE_ATTACHED)) { - if (parser == null) { - continue; - } - - XmlUtils.nextElement(parser); - while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { - if ("usb-device".equals(parser.getName())) { - DeviceFilter filter = DeviceFilter.read(parser); - if (filter.matches(device)) { - return true; - } - } - - XmlUtils.nextElement(parser); - } - } catch (Exception e) { - Log.w(TAG, "Unable to load component info " + activityInfo.toString(), e); - } - } - } - - return false; - } - - /** - * Can the app be the default for the USB accessory. I.e. can the app be launched by default if - * the accessory is plugged in. - * - * @param accessory The accessory the app would be default for - * @param packageInfo The package info of the app - * - * @return {@code true} iff the app can be default - */ - private boolean canBeDefault(@NonNull UsbAccessory accessory, - @NonNull PackageInfo packageInfo) { - ActivityInfo[] activities = packageInfo.activities; - if (activities != null) { - int numActivities = activities.length; - for (int i = 0; i < numActivities; i++) { - ActivityInfo activityInfo = activities[i]; - - try (XmlResourceParser parser = activityInfo.loadXmlMetaData(getPackageManager(), - UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) { - if (parser == null) { - continue; - } - - XmlUtils.nextElement(parser); - while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { - if ("usb-accessory".equals(parser.getName())) { - AccessoryFilter filter = AccessoryFilter.read(parser); - if (filter.matches(accessory)) { - return true; - } - } - - XmlUtils.nextElement(parser); - } - } catch (Exception e) { - Log.w(TAG, "Unable to load component info " + activityInfo.toString(), e); - } - } + mClearDefaultHint = (TextView)ap.mView.findViewById( + com.android.internal.R.id.clearDefaultHint); + mClearDefaultHint.setVisibility(View.GONE); } - return false; + setupAlert(); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java index 42dad114b6b6..c2611e410fad 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java @@ -92,15 +92,6 @@ public class ScrimViewTest extends LeakCheckedTest { } @Test - public void testOnDraw_ExcludeRectDrawable() { - mView.setExcludedArea(new Rect(10, 10, 20, 20)); - Canvas canvas = mock(Canvas.class); - mView.onDraw(canvas); - // One time for each rect side - verify(canvas, times(8)).clipRect(anyInt(), anyInt(), anyInt(), anyInt()); - } - - @Test public void setTint_set() { int tint = Color.BLUE; mView.setTint(tint); diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index 4d3468e21e75..44dddd14d83d 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -4386,12 +4386,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private static final class LocalServiceImpl extends InputMethodManagerInternal { @NonNull private final InputMethodManagerService mService; - @NonNull - private final Handler mHandler; LocalServiceImpl(@NonNull InputMethodManagerService service) { mService = service; - mHandler = service.mHandler; } @Override @@ -4411,19 +4408,19 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @Override public void setInteractive(boolean interactive) { // Do everything in handler so as not to block the caller. - mHandler.sendMessage(mHandler.obtainMessage(MSG_SET_INTERACTIVE, - interactive ? 1 : 0, 0)); + mService.mHandler.obtainMessage(MSG_SET_INTERACTIVE, interactive ? 1 : 0, 0) + .sendToTarget(); } @Override public void hideCurrentInputMethod() { - mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD); - mHandler.sendEmptyMessage(MSG_HIDE_CURRENT_INPUT_METHOD); + mService.mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD); + mService.mHandler.sendEmptyMessage(MSG_HIDE_CURRENT_INPUT_METHOD); } @Override public void startVrInputMethodNoCheck(@Nullable ComponentName componentName) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_START_VR_INPUT, componentName)); + mService.mHandler.obtainMessage(MSG_START_VR_INPUT, componentName).sendToTarget(); } } diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java new file mode 100644 index 000000000000..237e169a989f --- /dev/null +++ b/services/core/java/com/android/server/LooperStatsService.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import android.content.Context; +import android.os.Binder; +import android.os.Looper; +import android.os.ResultReceiver; +import android.os.ShellCallback; +import android.os.ShellCommand; + +import com.android.internal.os.LooperStats; +import com.android.internal.util.DumpUtils; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +/** + * @hide Only for use within the system server. + */ +public class LooperStatsService extends Binder { + private static final String TAG = "LooperStatsService"; + private static final String LOOPER_STATS_SERVICE_NAME = "looper_stats"; + + private final Context mContext; + private final LooperStats mStats; + private boolean mEnabled = false; + + private LooperStatsService(Context context, LooperStats stats) { + this.mContext = context; + this.mStats = stats; + } + + @Override + public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, + String[] args, ShellCallback callback, ResultReceiver resultReceiver) { + (new LooperShellCommand()).exec(this, in, out, err, args, callback, resultReceiver); + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; + List<LooperStats.ExportedEntry> entries = mStats.getEntries(); + entries.sort(Comparator + .comparing((LooperStats.ExportedEntry entry) -> entry.threadName) + .thenComparing(entry -> entry.handlerClassName) + .thenComparing(entry -> entry.messageName)); + String header = String.join(",", Arrays.asList( + "thread_name", + "handler_class", + "message_name", + "message_count", + "recorded_message_count", + "total_latency_micros", + "max_latency_micros", + "total_cpu_micros", + "max_cpu_micros", + "exception_count")); + pw.println(header); + for (LooperStats.ExportedEntry entry : entries) { + pw.printf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", entry.threadName, entry.handlerClassName, + entry.messageName, entry.messageCount, entry.recordedMessageCount, + entry.totalLatencyMicros, entry.maxLatencyMicros, entry.cpuUsageMicros, + entry.maxCpuUsageMicros, entry.exceptionCount); + } + } + + private void setEnabled(boolean enabled) { + if (mEnabled != enabled) { + mEnabled = enabled; + mStats.reset(); + Looper.setObserver(enabled ? mStats : null); + } + } + + /** + * Manages the lifecycle of LooperStatsService within System Server. + */ + public static class Lifecycle extends SystemService { + public Lifecycle(Context context) { + super(context); + } + + @Override + public void onStart() { + LooperStats stats = new LooperStats(); + publishLocalService(LooperStats.class, stats); + // TODO: publish LooperStatsService as a binder service when the SE Policy is changed. + } + } + + private class LooperShellCommand extends ShellCommand { + @Override + public int onCommand(String cmd) { + if ("enable".equals(cmd)) { + setEnabled(true); + return 0; + } else if ("disable".equals(cmd)) { + setEnabled(false); + return 0; + } else if ("reset".equals(cmd)) { + mStats.reset(); + return 0; + } else { + return handleDefaultCommands(cmd); + } + } + + @Override + public void onHelp() { + final PrintWriter pw = getOutPrintWriter(); + pw.println(LOOPER_STATS_SERVICE_NAME + " commands:"); + pw.println(" enable: Enable collecting stats"); + pw.println(" disable: Disable collecting stats"); + pw.println(" reset: Reset stats"); + } + } +} diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 9df9ba600f2a..2750dc13b408 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -16,6 +16,9 @@ package com.android.server.input; +import static android.hardware.display.DisplayViewport.VIEWPORT_INTERNAL; +import static android.hardware.display.DisplayViewport.VIEWPORT_EXTERNAL; + import android.annotation.NonNull; import android.os.LocaleList; import android.os.ShellCallback; @@ -292,11 +295,6 @@ public class InputManagerService extends IInputManager.Stub /** Switch code: Camera lens cover. When set the lens is covered. */ public static final int SW_CAMERA_LENS_COVER = 0x09; - // Viewport constants defined in InputReader.h. - public static final int VIEWPORT_DEFAULT = 1; - public static final int VIEWPORT_EXTERNAL = 2; - public static final int VIEWPORT_VIRTUAL = 3; - public static final int SW_LID_BIT = 1 << SW_LID; public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE; public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE; @@ -362,7 +360,7 @@ public class InputManagerService extends IInputManager.Stub updateAccessibilityLargePointerFromSettings(); } - // TODO(BT) Pass in paramter for bluetooth system + // TODO(BT) Pass in parameter for bluetooth system public void systemRunning() { if (DEBUG) { Slog.d(TAG, "System ready."); @@ -417,7 +415,7 @@ public class InputManagerService extends IInputManager.Stub DisplayViewport externalTouchViewport, List<DisplayViewport> virtualTouchViewports) { if (defaultViewport.valid) { - setDisplayViewport(VIEWPORT_DEFAULT, defaultViewport); + setDisplayViewport(VIEWPORT_INTERNAL, defaultViewport); } if (externalTouchViewport.valid) { diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index a54811b1a069..31cf9e346195 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -69,7 +69,6 @@ import android.os.WorkSource.WorkChain; import android.provider.Settings; import android.provider.Telephony.Carriers; import android.telephony.CarrierConfigManager; -import android.telephony.ServiceState; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyManager; @@ -1577,6 +1576,8 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt mSingleShot = false; native_stop(); mLastFixTime = 0; + // native_stop() may reset the position mode in hardware. + mLastPositionMode = null; // reset SV count to zero updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE); diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 91d4717ac23a..bdf12cad9cc1 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -334,9 +334,6 @@ public final class PowerManagerService extends SystemService // True if boot completed occurred. We keep the screen on until this happens. private boolean mBootCompleted; - // Runnables that should be triggered on boot completed - private Runnable[] mBootCompletedRunnables; - // True if auto-suspend mode is enabled. // Refer to autosuspend.h. private boolean mHalAutoSuspendModeEnabled; @@ -732,14 +729,6 @@ public final class PowerManagerService extends SystemService userActivityNoUpdateLocked( now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID); updatePowerStateLocked(); - - if (!ArrayUtils.isEmpty(mBootCompletedRunnables)) { - Slog.d(TAG, "Posting " + mBootCompletedRunnables.length + " delayed runnables"); - for (Runnable r : mBootCompletedRunnables) { - BackgroundThread.getHandler().post(r); - } - } - mBootCompletedRunnables = null; } } } @@ -954,16 +943,6 @@ public final class PowerManagerService extends SystemService mDirty |= DIRTY_SETTINGS; } - private void postAfterBootCompleted(Runnable r) { - if (mBootCompleted) { - BackgroundThread.getHandler().post(r); - } else { - Slog.d(TAG, "Delaying runnable until system is booted"); - mBootCompletedRunnables = ArrayUtils.appendElement(Runnable.class, - mBootCompletedRunnables, r); - } - } - private void handleSettingsChangedLocked() { updateSettingsLocked(); updatePowerStateLocked(); diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 41c0be63a5bb..b922e40a5d38 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -70,6 +70,7 @@ import com.android.internal.os.KernelUidCpuFreqTimeReader; import com.android.internal.os.KernelUidCpuTimeReader; import com.android.internal.os.KernelWakelockReader; import com.android.internal.os.KernelWakelockStats; +import com.android.internal.os.LooperStats; import com.android.internal.os.PowerProfile; import com.android.internal.util.DumpUtils; import com.android.server.BinderCallsStatsService; @@ -938,6 +939,29 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } + private void pullLooperStats(int tagId, List<StatsLogEventWrapper> pulledData) { + LooperStats looperStats = LocalServices.getService(LooperStats.class); + if (looperStats == null) { + return; + } + + List<LooperStats.ExportedEntry> entries = looperStats.getEntries(); + long elapsedNanos = SystemClock.elapsedRealtimeNanos(); + for (LooperStats.ExportedEntry entry : entries) { + StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 9 /* fields */); + e.writeLong(0); // uid collection not implemented yet + e.writeString(entry.handlerClassName); + e.writeString(entry.threadName); + e.writeString(entry.messageName); + e.writeLong(entry.messageCount); + e.writeLong(entry.exceptionCount); + e.writeLong(entry.recordedMessageCount); + e.writeLong(entry.totalLatencyMicros); + e.writeLong(entry.cpuUsageMicros); + pulledData.add(e); + } + } + /** * Pulls various data. */ @@ -1028,6 +1052,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pullBinderCallsStatsExceptions(tagId, ret); break; } + case StatsLog.LOOPER_STATS: { + pullLooperStats(tagId, ret); + break; + } default: Slog.w(TAG, "No such tagId data as " + tagId); return null; diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 32fa9bf97930..9490ae2a894a 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1426,7 +1426,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo config.densityDpi = displayInfo.logicalDensityDpi; config.colorMode = - (displayInfo.isHdr() + ((displayInfo.isHdr() && mService.hasHdrSupport()) ? Configuration.COLOR_MODE_HDR_YES : Configuration.COLOR_MODE_HDR_NO) | (displayInfo.isWideColorGamut() && mService.hasWideColorGamutSupport() diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index e80a47eef2d5..2a381aca8a2a 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -734,8 +734,9 @@ public class WindowManagerService extends IWindowManager.Stub final DisplayManagerInternal mDisplayManagerInternal; final DisplayManager mDisplayManager; - // Indicates whether this device supports wide color gamut rendering + // Indicates whether this device supports wide color gamut / HDR rendering private boolean mHasWideColorGamutSupport; + private boolean mHasHdrSupport; // Who is holding the screen on. private Session mHoldingScreenOn; @@ -4504,6 +4505,7 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.systemReady(); mTaskSnapshotController.systemReady(); mHasWideColorGamutSupport = queryWideColorGamutSupport(); + mHasHdrSupport = queryHdrSupport(); } private static boolean queryWideColorGamutSupport() { @@ -4519,6 +4521,19 @@ public class WindowManagerService extends IWindowManager.Stub return false; } + private static boolean queryHdrSupport() { + try { + ISurfaceFlingerConfigs surfaceFlinger = ISurfaceFlingerConfigs.getService(); + OptionalBool hasHdr = surfaceFlinger.hasHDRDisplay(); + if (hasHdr != null) { + return hasHdr.value; + } + } catch (RemoteException e) { + // Ignore, we're in big trouble if we can't talk to SurfaceFlinger's config store + } + return false; + } + // ------------------------------------------------------------- // Async Handler // ------------------------------------------------------------- @@ -7499,6 +7514,10 @@ public class WindowManagerService extends IWindowManager.Stub SystemProperties.getInt("persist.sys.sf.native_mode", 0) != 1; } + boolean hasHdrSupport() { + return mHasHdrSupport && hasWideColorGamutSupport(); + } + void updateNonSystemOverlayWindowsVisibilityIfNeeded(WindowState win, boolean surfaceShown) { if (!win.hideNonSystemOverlayWindowsWhenVisible() && !mHidingNonSystemOverlayWindows.contains(win)) { diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 52f2d674f993..b467d61c355d 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -230,11 +230,11 @@ public: virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId); virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices); virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const InputDeviceIdentifier& identifier); - virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier); + virtual std::string getDeviceAlias(const InputDeviceIdentifier& identifier); virtual TouchAffineTransformation getTouchAffineTransformation(JNIEnv *env, jfloatArray matrixArr); virtual TouchAffineTransformation getTouchAffineTransformation( - const String8& inputDeviceDescriptor, int32_t surfaceRotation); + const std::string& inputDeviceDescriptor, int32_t surfaceRotation); /* --- InputDispatcherPolicyInterface implementation --- */ @@ -480,7 +480,7 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon for (jsize i = 0; i < length; i++) { jstring item = jstring(env->GetObjectArrayElement(excludedDeviceNames, i)); const char* deviceNameChars = env->GetStringUTFChars(item, NULL); - outConfig->excludedDeviceNames.add(String8(deviceNameChars)); + outConfig->excludedDeviceNames.push_back(deviceNameChars); env->ReleaseStringUTFChars(item, deviceNameChars); env->DeleteLocalRef(item); } @@ -606,7 +606,7 @@ sp<KeyCharacterMap> NativeInputManager::getKeyboardLayoutOverlay( JNIEnv* env = jniEnv(); sp<KeyCharacterMap> result; - ScopedLocalRef<jstring> descriptor(env, env->NewStringUTF(identifier.descriptor.string())); + ScopedLocalRef<jstring> descriptor(env, env->NewStringUTF(identifier.descriptor.c_str())); ScopedLocalRef<jobject> identifierObj(env, env->NewObject(gInputDeviceIdentifierInfo.clazz, gInputDeviceIdentifierInfo.constructor, descriptor.get(), identifier.vendor, identifier.product)); @@ -620,24 +620,24 @@ sp<KeyCharacterMap> NativeInputManager::getKeyboardLayoutOverlay( ScopedUtfChars filenameChars(env, filenameObj.get()); ScopedUtfChars contentsChars(env, contentsObj.get()); - KeyCharacterMap::loadContents(String8(filenameChars.c_str()), - String8(contentsChars.c_str()), KeyCharacterMap::FORMAT_OVERLAY, &result); + KeyCharacterMap::loadContents(filenameChars.c_str(), + contentsChars.c_str(), KeyCharacterMap::FORMAT_OVERLAY, &result); } checkAndClearExceptionFromCallback(env, "getKeyboardLayoutOverlay"); return result; } -String8 NativeInputManager::getDeviceAlias(const InputDeviceIdentifier& identifier) { +std::string NativeInputManager::getDeviceAlias(const InputDeviceIdentifier& identifier) { ATRACE_CALL(); JNIEnv* env = jniEnv(); - ScopedLocalRef<jstring> uniqueIdObj(env, env->NewStringUTF(identifier.uniqueId.string())); + ScopedLocalRef<jstring> uniqueIdObj(env, env->NewStringUTF(identifier.uniqueId.c_str())); ScopedLocalRef<jstring> aliasObj(env, jstring(env->CallObjectMethod(mServiceObj, gServiceClassInfo.getDeviceAlias, uniqueIdObj.get()))); - String8 result; + std::string result; if (aliasObj.get()) { ScopedUtfChars aliasChars(env, aliasObj.get()); - result.setTo(aliasChars.c_str()); + result = aliasChars.c_str(); } checkAndClearExceptionFromCallback(env, "getDeviceAlias"); return result; @@ -932,10 +932,10 @@ TouchAffineTransformation NativeInputManager::getTouchAffineTransformation( } TouchAffineTransformation NativeInputManager::getTouchAffineTransformation( - const String8& inputDeviceDescriptor, int32_t surfaceRotation) { + const std::string& inputDeviceDescriptor, int32_t surfaceRotation) { JNIEnv* env = jniEnv(); - ScopedLocalRef<jstring> descriptorObj(env, env->NewStringUTF(inputDeviceDescriptor.string())); + ScopedLocalRef<jstring> descriptorObj(env, env->NewStringUTF(inputDeviceDescriptor.c_str())); jobject cal = env->CallObjectMethod(mServiceObj, gServiceClassInfo.getTouchCalibrationForInputDevice, descriptorObj.get(), @@ -1281,7 +1281,7 @@ static void nativeSetDisplayViewport(JNIEnv* env, jclass /* clazz */, jlong ptr, v.deviceWidth = deviceWidth; v.deviceHeight = deviceHeight; if (uniqueId != nullptr) { - v.uniqueId.setTo(ScopedUtfChars(env, uniqueId).c_str()); + v.uniqueId = ScopedUtfChars(env, uniqueId).c_str(); } im->setDisplayViewport(viewportType, v); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index ecc13b295539..6431344f218b 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -747,6 +747,11 @@ public final class SystemServer { traceBeginAndSlog("StartBinderCallsStatsService"); mSystemServiceManager.startService(BinderCallsStatsService.LifeCycle.class); traceEnd(); + + // Tracks time spent in handling messages in handlers. + traceBeginAndSlog("StartLooperStatsService"); + mSystemServiceManager.startService(LooperStatsService.Lifecycle.class); + traceEnd(); } /** diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java index 2f1c5169362a..4874bcef1606 100644 --- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java +++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java @@ -44,6 +44,10 @@ public final class UsbAlsaManager { private static final String TAG = UsbAlsaManager.class.getSimpleName(); private static final boolean DEBUG = false; + // Flag to turn on/off multi-peripheral select mode + // Set to true to have single-device-only mode + private static final boolean mIsSingleMode = true; + private static final String ALSA_DIRECTORY = "/dev/snd/"; private final Context mContext; @@ -84,10 +88,11 @@ public final class UsbAlsaManager { */ private synchronized void selectAlsaDevice(UsbAlsaDevice alsaDevice) { if (DEBUG) { - Slog.d(TAG, "selectAlsaDevice " + alsaDevice); + Slog.d(TAG, "selectAlsaDevice() " + alsaDevice); } - if (mSelectedDevice != null) { + // This must be where an existing USB audio device is deselected.... (I think) + if (mIsSingleMode && mSelectedDevice != null) { deselectAlsaDevice(); } @@ -104,9 +109,15 @@ public final class UsbAlsaManager { mSelectedDevice = alsaDevice; alsaDevice.start(); + if (DEBUG) { + Slog.d(TAG, "selectAlsaDevice() - done."); + } } private synchronized void deselectAlsaDevice() { + if (DEBUG) { + Slog.d(TAG, "deselectAlsaDevice() mSelectedDevice " + mSelectedDevice); + } if (mSelectedDevice != null) { mSelectedDevice.stop(); mSelectedDevice = null; @@ -133,7 +144,7 @@ public final class UsbAlsaManager { /* package */ UsbAlsaDevice selectDefaultDevice() { if (DEBUG) { - Slog.d(TAG, "UsbAudioManager.selectDefaultDevice()"); + Slog.d(TAG, "selectDefaultDevice()"); } if (mAlsaDevices.size() > 0) { @@ -230,6 +241,8 @@ public final class UsbAlsaManager { } } + logDevices("deviceAdded()"); + if (DEBUG) { Slog.d(TAG, "deviceAdded() - done"); } @@ -254,6 +267,9 @@ public final class UsbAlsaManager { Slog.i(TAG, "USB MIDI Device Removed: " + usbMidiDevice); IoUtils.closeQuietly(usbMidiDevice); } + + logDevices("usbDeviceRemoved()"); + } /* package */ void setPeripheralMidiState(boolean enabled, int card, int device) { @@ -296,6 +312,7 @@ public final class UsbAlsaManager { /** * Dump the USB alsa state. */ + // invoked with "adb shell dumpsys usb" public void dump(DualDumpOutputStream dump, String idName, long id) { long token = dump.start(idName, id); @@ -314,29 +331,26 @@ public final class UsbAlsaManager { dump.end(token); } -/* public void logDevicesList(String title) { - if (DEBUG) { - for (HashMap.Entry<UsbDevice,UsbAlsaDevice> entry : mAudioDevices.entrySet()) { - Slog.i(TAG, "UsbDevice-------------------"); - Slog.i(TAG, "" + (entry != null ? entry.getKey() : "[none]")); - Slog.i(TAG, "UsbAlsaDevice--------------"); - Slog.i(TAG, "" + entry.getValue()); - } - } + if (DEBUG) { + Slog.i(TAG, title + "----------------"); + for (UsbAlsaDevice alsaDevice : mAlsaDevices) { + Slog.i(TAG, " -->"); + Slog.i(TAG, "" + alsaDevice); + Slog.i(TAG, " <--"); + } + Slog.i(TAG, "----------------"); + } } -*/ // This logs a more terse (and more readable) version of the devices list -/* public void logDevices(String title) { - if (DEBUG) { - Slog.i(TAG, title); - for (HashMap.Entry<UsbDevice,UsbAlsaDevice> entry : mAudioDevices.entrySet()) { - Slog.i(TAG, entry.getValue().toShortString()); - } - } + if (DEBUG) { + Slog.i(TAG, title + "----------------"); + for (UsbAlsaDevice alsaDevice : mAlsaDevices) { + Slog.i(TAG, alsaDevice.toShortString()); + } + Slog.i(TAG, "----------------"); + } } -*/ - } diff --git a/services/usb/java/com/android/server/usb/UsbHandlerManager.java b/services/usb/java/com/android/server/usb/UsbHandlerManager.java new file mode 100644 index 000000000000..1730d8f22950 --- /dev/null +++ b/services/usb/java/com/android/server/usb/UsbHandlerManager.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.usb; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ResolveInfo; +import android.hardware.usb.UsbAccessory; +import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbManager; +import android.os.UserHandle; +import android.util.Slog; + +import java.util.ArrayList; + +/** + * UsbResolveActivityManager creates UI dialogs for user to pick or confirm handler for + * usb attach event. + * + * @hide + */ +class UsbHandlerManager { + private static final String LOG_TAG = UsbHandlerManager.class.getSimpleName(); + + private final Context mContext; + + UsbHandlerManager(@NonNull Context context) { + mContext = context; + } + + /** + * Shows dialog to user to allow them to optionally visit that URL for more + * information or software downloads if the attached USB accessory has a valid + * URL associated with it. + * + * @param accessory The accessory to confirm in the UI dialog + * @param user The user to start the UI dialog + */ + void showUsbAccessoryUriActivity(@NonNull UsbAccessory accessory, + @NonNull UserHandle user) { + String uri = accessory.getUri(); + if (uri != null && uri.length() > 0) { + // display URI to user + Intent dialogIntent = createDialogIntent(); + dialogIntent.setClassName("com.android.systemui", + "com.android.systemui.usb.UsbAccessoryUriActivity"); + dialogIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); + dialogIntent.putExtra("uri", uri); + try { + mContext.startActivityAsUser(dialogIntent, user); + } catch (ActivityNotFoundException e) { + Slog.e(LOG_TAG, "unable to start UsbAccessoryUriActivity"); + } + } + } + + /** + * Shows dialog to user to confirm the package to start when the USB device + * or accessory is attached and there is only one package claims to handle this + * USB device or accessory. + * + * @param rInfo The ResolveInfo of the package to confirm in the UI dialog + * @param device The USB device to confirm + * @param accessory The USB accessory to confirm + */ + void confirmUsbHandler(@NonNull ResolveInfo rInfo, @Nullable UsbDevice device, + @Nullable UsbAccessory accessory) { + Intent resolverIntent = createDialogIntent(); + // start UsbConfirmActivity if there is only one choice + resolverIntent.setClassName("com.android.systemui", + "com.android.systemui.usb.UsbConfirmActivity"); + resolverIntent.putExtra("rinfo", rInfo); + UserHandle user = + UserHandle.getUserHandleForUid(rInfo.activityInfo.applicationInfo.uid); + + if (device != null) { + resolverIntent.putExtra(UsbManager.EXTRA_DEVICE, device); + } else { + resolverIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); + } + + try { + mContext.startActivityAsUser(resolverIntent, user); + } catch (ActivityNotFoundException e) { + Slog.e(LOG_TAG, "unable to start activity " + resolverIntent, e); + } + } + + /** + * Shows dialog to user to select the package to start when the USB device + * or accessory is attached and there are more than one package claim to handle this + * USB device or accessory. + * + * @param matches The available resolutions of the intent + * @param user The user to start UI dialog + * @param intent The intent to start the UI dialog + */ + void selectUsbHandler(@NonNull ArrayList<ResolveInfo> matches, + @NonNull UserHandle user, @NonNull Intent intent) { + Intent resolverIntent = createDialogIntent(); + resolverIntent.setClassName("com.android.systemui", + "com.android.systemui.usb.UsbResolverActivity"); + resolverIntent.putParcelableArrayListExtra("rlist", matches); + resolverIntent.putExtra(Intent.EXTRA_INTENT, intent); + + try { + mContext.startActivityAsUser(resolverIntent, user); + } catch (ActivityNotFoundException e) { + Slog.e(LOG_TAG, "unable to start activity " + resolverIntent, e); + } + } + + private Intent createDialogIntent() { + Intent intent = new Intent(); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + return intent; + } +} diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java index 67ad0907181b..589bcdc14871 100644 --- a/services/usb/java/com/android/server/usb/UsbHostManager.java +++ b/services/usb/java/com/android/server/usb/UsbHostManager.java @@ -408,11 +408,15 @@ public class UsbHostManager { /* Called from JNI in monitorUsbHostBus to report USB device removal */ @SuppressWarnings("unused") private void usbDeviceRemoved(String deviceAddress) { + if (DEBUG) { + Slog.d(TAG, "usbDeviceRemoved(" + deviceAddress + ") end"); + } + synchronized (mLock) { UsbDevice device = mDevices.remove(deviceAddress); if (device != null) { Slog.d(TAG, "Removed device at " + deviceAddress + ": " + device.getProductName()); - mUsbAlsaManager.usbDeviceRemoved(deviceAddress/*device*/); + mUsbAlsaManager.usbDeviceRemoved(deviceAddress); mSettingsManager.usbDeviceRemoved(device); getCurrentUserSettings().usbDeviceRemoved(device); diff --git a/services/usb/java/com/android/server/usb/UsbPermissionManager.java b/services/usb/java/com/android/server/usb/UsbPermissionManager.java new file mode 100644 index 000000000000..2c9ee36107e8 --- /dev/null +++ b/services/usb/java/com/android/server/usb/UsbPermissionManager.java @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.usb; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.PendingIntent; +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.hardware.usb.UsbAccessory; +import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbManager; +import android.os.Binder; +import android.os.Process; +import android.os.UserHandle; +import android.service.usb.UsbSettingsAccessoryPermissionProto; +import android.service.usb.UsbSettingsDevicePermissionProto; +import android.service.usb.UsbUserSettingsManagerProto; +import android.util.Slog; +import android.util.SparseBooleanArray; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.dump.DualDumpOutputStream; + +import java.util.HashMap; + +/** + * UsbPermissionManager manages usb device or accessory access permissions. + * + * @hide + */ +class UsbPermissionManager { + private static final String LOG_TAG = UsbPermissionManager.class.getSimpleName(); + + @GuardedBy("mLock") + /** Temporary mapping USB device name to list of UIDs with permissions for the device*/ + private final HashMap<String, SparseBooleanArray> mDevicePermissionMap = + new HashMap<>(); + @GuardedBy("mLock") + /** Temporary mapping UsbAccessory to list of UIDs with permissions for the accessory*/ + private final HashMap<UsbAccessory, SparseBooleanArray> mAccessoryPermissionMap = + new HashMap<>(); + + private final UserHandle mUser; + private final boolean mDisablePermissionDialogs; + + private final Object mLock = new Object(); + + UsbPermissionManager(@NonNull Context context, @NonNull UserHandle user) { + mUser = user; + mDisablePermissionDialogs = context.getResources().getBoolean( + com.android.internal.R.bool.config_disableUsbPermissionDialogs); + } + + /** + * Removes access permissions of all packages for the USB accessory. + * + * @param accessory to remove permissions for + */ + void removeAccessoryPermissions(@NonNull UsbAccessory accessory) { + synchronized (mLock) { + mAccessoryPermissionMap.remove(accessory); + } + } + + /** + * Removes access permissions of all packages for the USB device. + * + * @param device to remove permissions for + */ + void removeDevicePermissions(@NonNull UsbDevice device) { + synchronized (mLock) { + mDevicePermissionMap.remove(device.getDeviceName()); + } + } + + /** + * Grants permission for USB device without showing system dialog for package with uid. + * + * @param device to grant permission for + * @param uid to grant permission for + */ + void grantDevicePermission(@NonNull UsbDevice device, int uid) { + synchronized (mLock) { + String deviceName = device.getDeviceName(); + SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName); + if (uidList == null) { + uidList = new SparseBooleanArray(1); + mDevicePermissionMap.put(deviceName, uidList); + } + uidList.put(uid, true); + } + } + + /** + * Grants permission for USB accessory without showing system dialog for package with uid. + * + * @param accessory to grant permission for + * @param uid to grant permission for + */ + void grantAccessoryPermission(@NonNull UsbAccessory accessory, int uid) { + synchronized (mLock) { + SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory); + if (uidList == null) { + uidList = new SparseBooleanArray(1); + mAccessoryPermissionMap.put(accessory, uidList); + } + uidList.put(uid, true); + } + } + + /** + * Returns true if package with uid has permission to access the device. + * + * @param device to check permission for + * @param uid to check permission for + * @return {@code true} if package with uid has permission + */ + boolean hasPermission(@NonNull UsbDevice device, int uid) { + synchronized (mLock) { + if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) { + return true; + } + SparseBooleanArray uidList = mDevicePermissionMap.get(device.getDeviceName()); + if (uidList == null) { + return false; + } + return uidList.get(uid); + } + } + + /** + * Returns true if caller has permission to access the accessory. + * + * @param accessory to check permission for + * @return {@code true} if caller has permssion + */ + boolean hasPermission(@NonNull UsbAccessory accessory) { + synchronized (mLock) { + int uid = Binder.getCallingUid(); + if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) { + return true; + } + SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory); + if (uidList == null) { + return false; + } + return uidList.get(uid); + } + } + + /** + * Creates UI dialog to request permission for the given package to access the device + * or accessory. + * + * @param device The USB device attached + * @param accessory The USB accessory attached + * @param canBeDefault Whether the calling pacakge can set as default handler + * of the USB device or accessory + * @param packageName The package name of the calling package + * @param uid The uid of the calling package + * @param userContext The context to start the UI dialog + * @param pi PendingIntent for returning result + */ + void requestPermissionDialog(@Nullable UsbDevice device, + @Nullable UsbAccessory accessory, + boolean canBeDefault, + @NonNull String packageName, + int uid, + @NonNull Context userContext, + @NonNull PendingIntent pi) { + long identity = Binder.clearCallingIdentity(); + Intent intent = new Intent(); + if (device != null) { + intent.putExtra(UsbManager.EXTRA_DEVICE, device); + } else { + intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); + } + intent.putExtra(Intent.EXTRA_INTENT, pi); + intent.putExtra(Intent.EXTRA_UID, uid); + intent.putExtra(UsbManager.EXTRA_CAN_BE_DEFAULT, canBeDefault); + intent.putExtra(UsbManager.EXTRA_PACKAGE, packageName); + intent.setClassName("com.android.systemui", + "com.android.systemui.usb.UsbPermissionActivity"); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + try { + userContext.startActivityAsUser(intent, mUser); + } catch (ActivityNotFoundException e) { + Slog.e(LOG_TAG, "unable to start UsbPermissionActivity"); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + void dump(@NonNull DualDumpOutputStream dump) { + synchronized (mLock) { + for (String deviceName : mDevicePermissionMap.keySet()) { + long devicePermissionToken = dump.start("device_permissions", + UsbUserSettingsManagerProto.DEVICE_PERMISSIONS); + + dump.write("device_name", UsbSettingsDevicePermissionProto.DEVICE_NAME, deviceName); + + SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName); + int count = uidList.size(); + for (int i = 0; i < count; i++) { + dump.write("uids", UsbSettingsDevicePermissionProto.UIDS, uidList.keyAt(i)); + } + + dump.end(devicePermissionToken); + } + + for (UsbAccessory accessory : mAccessoryPermissionMap.keySet()) { + long accessoryPermissionToken = dump.start("accessory_permissions", + UsbUserSettingsManagerProto.ACCESSORY_PERMISSIONS); + + dump.write("accessory_description", + UsbSettingsAccessoryPermissionProto.ACCESSORY_DESCRIPTION, + accessory.getDescription()); + + SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory); + int count = uidList.size(); + for (int i = 0; i < count; i++) { + dump.write("uids", UsbSettingsAccessoryPermissionProto.UIDS, uidList.keyAt(i)); + } + + dump.end(accessoryPermissionToken); + } + } + } +} diff --git a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java index 7a906d0b7aaf..1ab1f7e43906 100644 --- a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java +++ b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java @@ -193,6 +193,8 @@ class UsbProfileGroupSettingsManager { MyPackageMonitor mPackageMonitor = new MyPackageMonitor(); + private final UsbHandlerManager mUsbHandlerManager; + private final MtpNotificationManager mMtpNotificationManager; /** @@ -201,9 +203,11 @@ class UsbProfileGroupSettingsManager { * @param context The context of the service * @param user The parent profile * @param settingsManager The settings manager of the service + * @param usbResolveActivityManager The resovle activity manager of the service */ UsbProfileGroupSettingsManager(@NonNull Context context, @NonNull UserHandle user, - @NonNull UsbSettingsManager settingsManager) { + @NonNull UsbSettingsManager settingsManager, + @NonNull UsbHandlerManager usbResolveActivityManager) { if (DEBUG) Slog.v(TAG, "Creating settings for " + user); Context parentUserContext; @@ -238,6 +242,8 @@ class UsbProfileGroupSettingsManager { parentUserContext, device -> resolveActivity(createDeviceAttachedIntent(device), device, false /* showMtpNotification */)); + + mUsbHandlerManager = usbResolveActivityManager; } /** @@ -830,23 +836,8 @@ class UsbProfileGroupSettingsManager { // don't show the resolver activity if there are no choices available if (matches.size() == 0) { if (accessory != null) { - String uri = accessory.getUri(); - if (uri != null && uri.length() > 0) { - // display URI to user - Intent dialogIntent = new Intent(); - dialogIntent.setClassName("com.android.systemui", - "com.android.systemui.usb.UsbAccessoryUriActivity"); - dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - dialogIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); - dialogIntent.putExtra("uri", uri); - try { - mContext.startActivityAsUser(dialogIntent, mParentUser); - } catch (ActivityNotFoundException e) { - Slog.e(TAG, "unable to start UsbAccessoryUriActivity"); - } - } + mUsbHandlerManager.showUsbAccessoryUriActivity(accessory, mParentUser); } - // do nothing return; } @@ -875,37 +866,10 @@ class UsbProfileGroupSettingsManager { Slog.e(TAG, "startActivity failed", e); } } else { - Intent resolverIntent = new Intent(); - resolverIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - UserHandle user; - if (matches.size() == 1) { - ResolveInfo rInfo = matches.get(0); - - // start UsbConfirmActivity if there is only one choice - resolverIntent.setClassName("com.android.systemui", - "com.android.systemui.usb.UsbConfirmActivity"); - resolverIntent.putExtra("rinfo", rInfo); - user = UserHandle.getUserHandleForUid(rInfo.activityInfo.applicationInfo.uid); - - if (device != null) { - resolverIntent.putExtra(UsbManager.EXTRA_DEVICE, device); - } else { - resolverIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); - } + mUsbHandlerManager.confirmUsbHandler(matches.get(0), device, accessory); } else { - user = mParentUser; - - // start UsbResolverActivity so user can choose an activity - resolverIntent.setClassName("com.android.systemui", - "com.android.systemui.usb.UsbResolverActivity"); - resolverIntent.putParcelableArrayListExtra("rlist", matches); - resolverIntent.putExtra(Intent.EXTRA_INTENT, intent); - } - try { - mContext.startActivityAsUser(resolverIntent, user); - } catch (ActivityNotFoundException e) { - Slog.e(TAG, "unable to start activity " + resolverIntent, e); + mUsbHandlerManager.selectUsbHandler(matches, mParentUser, intent); } } } diff --git a/services/usb/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java index 9221825b2d87..27566f04c280 100644 --- a/services/usb/java/com/android/server/usb/UsbSettingsManager.java +++ b/services/usb/java/com/android/server/usb/UsbSettingsManager.java @@ -57,10 +57,12 @@ class UsbSettingsManager { private final SparseArray<UsbProfileGroupSettingsManager> mSettingsByProfileGroup = new SparseArray<>(); private UserManager mUserManager; + private UsbHandlerManager mUsbHandlerManager; public UsbSettingsManager(@NonNull Context context) { mContext = context; mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); + mUsbHandlerManager = new UsbHandlerManager(context); } /** @@ -74,7 +76,8 @@ class UsbSettingsManager { synchronized (mSettingsByUser) { UsbUserSettingsManager settings = mSettingsByUser.get(userId); if (settings == null) { - settings = new UsbUserSettingsManager(mContext, new UserHandle(userId)); + settings = new UsbUserSettingsManager(mContext, UserHandle.of(userId), + new UsbPermissionManager(mContext, UserHandle.of(userId))); mSettingsByUser.put(userId, settings); } return settings; @@ -102,7 +105,8 @@ class UsbSettingsManager { UsbProfileGroupSettingsManager settings = mSettingsByProfileGroup.get( parentUser.getIdentifier()); if (settings == null) { - settings = new UsbProfileGroupSettingsManager(mContext, parentUser, this); + settings = new UsbProfileGroupSettingsManager(mContext, parentUser, this, + mUsbHandlerManager); mSettingsByProfileGroup.put(parentUser.getIdentifier(), settings); } return settings; diff --git a/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java b/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java index 24a2d72415ed..fe93399c2d60 100644 --- a/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java +++ b/services/usb/java/com/android/server/usb/UsbUserSettingsManager.java @@ -21,15 +21,18 @@ import static com.android.server.usb.UsbProfileGroupSettingsManager.getAccessory import static com.android.server.usb.UsbProfileGroupSettingsManager.getDeviceFilters; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.PendingIntent; -import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; +import android.content.res.XmlResourceParser; import android.hardware.usb.AccessoryFilter; import android.hardware.usb.DeviceFilter; import android.hardware.usb.UsbAccessory; @@ -38,42 +41,34 @@ import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbInterface; import android.hardware.usb.UsbManager; import android.os.Binder; -import android.os.Process; import android.os.UserHandle; import android.service.usb.UsbAccessoryAttachedActivities; import android.service.usb.UsbDeviceAttachedActivities; -import android.service.usb.UsbSettingsAccessoryPermissionProto; -import android.service.usb.UsbSettingsDevicePermissionProto; import android.service.usb.UsbUserSettingsManagerProto; import android.util.Slog; -import android.util.SparseBooleanArray; +import com.android.internal.util.XmlUtils; import com.android.internal.util.dump.DualDumpOutputStream; +import org.xmlpull.v1.XmlPullParser; + import java.util.ArrayList; -import java.util.HashMap; import java.util.List; class UsbUserSettingsManager { - private static final String TAG = "UsbUserSettingsManager"; + private static final String TAG = UsbUserSettingsManager.class.getSimpleName(); private static final boolean DEBUG = false; private final UserHandle mUser; - private final boolean mDisablePermissionDialogs; private final Context mUserContext; private final PackageManager mPackageManager; - - // Temporary mapping USB device name to list of UIDs with permissions for the device - private final HashMap<String, SparseBooleanArray> mDevicePermissionMap = - new HashMap<>(); - // Temporary mapping UsbAccessory to list of UIDs with permissions for the accessory - private final HashMap<UsbAccessory, SparseBooleanArray> mAccessoryPermissionMap = - new HashMap<>(); + private final UsbPermissionManager mUsbPermissionManager; private final Object mLock = new Object(); - public UsbUserSettingsManager(Context context, UserHandle user) { + UsbUserSettingsManager(Context context, UserHandle user, + @NonNull UsbPermissionManager usbPermissionManager) { if (DEBUG) Slog.v(TAG, "Creating settings for " + user); try { @@ -85,9 +80,7 @@ class UsbUserSettingsManager { mPackageManager = mUserContext.getPackageManager(); mUser = user; - - mDisablePermissionDialogs = context.getResources().getBoolean( - com.android.internal.R.bool.config_disableUsbPermissionDialogs); + mUsbPermissionManager = usbPermissionManager; } /** @@ -96,9 +89,7 @@ class UsbUserSettingsManager { * @param device The device the permissions are for */ void removeDevicePermissions(@NonNull UsbDevice device) { - synchronized (mLock) { - mDevicePermissionMap.remove(device.getDeviceName()); - } + mUsbPermissionManager.removeDevicePermissions(device); } /** @@ -107,9 +98,7 @@ class UsbUserSettingsManager { * @param accessory The accessory the permissions are for */ void removeAccessoryPermissions(@NonNull UsbAccessory accessory) { - synchronized (mLock) { - mAccessoryPermissionMap.remove(accessory); - } + mUsbPermissionManager.removeAccessoryPermissions(accessory); } /** @@ -170,35 +159,17 @@ class UsbUserSettingsManager { } public boolean hasPermission(UsbDevice device, String packageName, int uid) { - synchronized (mLock) { - if (isCameraDevicePresent(device)) { - if (!isCameraPermissionGranted(packageName, uid)) { - return false; - } - } - if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) { - return true; - } - SparseBooleanArray uidList = mDevicePermissionMap.get(device.getDeviceName()); - if (uidList == null) { + if (isCameraDevicePresent(device)) { + if (!isCameraPermissionGranted(packageName, uid)) { return false; } - return uidList.get(uid); } + + return mUsbPermissionManager.hasPermission(device, uid); } public boolean hasPermission(UsbAccessory accessory) { - synchronized (mLock) { - int uid = Binder.getCallingUid(); - if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) { - return true; - } - SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory); - if (uidList == null) { - return false; - } - return uidList.get(uid); - } + return mUsbPermissionManager.hasPermission(accessory); } public void checkPermission(UsbDevice device, String packageName, int uid) { @@ -213,7 +184,11 @@ class UsbUserSettingsManager { } } - private void requestPermissionDialog(Intent intent, String packageName, PendingIntent pi) { + private void requestPermissionDialog(@Nullable UsbDevice device, + @Nullable UsbAccessory accessory, + boolean canBeDefault, + String packageName, + PendingIntent pi) { final int uid = Binder.getCallingUid(); // compare uid with packageName to foil apps pretending to be someone else @@ -227,27 +202,15 @@ class UsbUserSettingsManager { throw new IllegalArgumentException("package " + packageName + " not found"); } - long identity = Binder.clearCallingIdentity(); - intent.setClassName("com.android.systemui", - "com.android.systemui.usb.UsbPermissionActivity"); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.putExtra(Intent.EXTRA_INTENT, pi); - intent.putExtra("package", packageName); - intent.putExtra(Intent.EXTRA_UID, uid); - try { - mUserContext.startActivityAsUser(intent, mUser); - } catch (ActivityNotFoundException e) { - Slog.e(TAG, "unable to start UsbPermissionActivity"); - } finally { - Binder.restoreCallingIdentity(identity); - } + mUsbPermissionManager.requestPermissionDialog(device, + accessory, canBeDefault, packageName, uid, mUserContext, pi); } public void requestPermission(UsbDevice device, String packageName, PendingIntent pi, int uid) { - Intent intent = new Intent(); + Intent intent = new Intent(); // respond immediately if permission has already been granted - if (hasPermission(device, packageName, uid)) { + if (hasPermission(device, packageName, uid)) { intent.putExtra(UsbManager.EXTRA_DEVICE, device); intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true); try { @@ -270,16 +233,13 @@ class UsbUserSettingsManager { } } - // start UsbPermissionActivity so user can choose an activity - intent.putExtra(UsbManager.EXTRA_DEVICE, device); - requestPermissionDialog(intent, packageName, pi); + requestPermissionDialog(device, null, canBeDefault(device, packageName), packageName, pi); } public void requestPermission(UsbAccessory accessory, String packageName, PendingIntent pi) { - Intent intent = new Intent(); - // respond immediately if permission has already been granted if (hasPermission(accessory)) { + Intent intent = new Intent(); intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true); try { @@ -290,31 +250,16 @@ class UsbUserSettingsManager { return; } - intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); - requestPermissionDialog(intent, packageName, pi); + requestPermissionDialog(null, accessory, + canBeDefault(accessory, packageName), packageName, pi); } public void grantDevicePermission(UsbDevice device, int uid) { - synchronized (mLock) { - String deviceName = device.getDeviceName(); - SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName); - if (uidList == null) { - uidList = new SparseBooleanArray(1); - mDevicePermissionMap.put(deviceName, uidList); - } - uidList.put(uid, true); - } + mUsbPermissionManager.grantDevicePermission(device, uid); } public void grantAccessoryPermission(UsbAccessory accessory, int uid) { - synchronized (mLock) { - SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory); - if (uidList == null) { - uidList = new SparseBooleanArray(1); - mAccessoryPermissionMap.put(accessory, uidList); - } - uidList.put(uid, true); - } + mUsbPermissionManager.grantAccessoryPermission(accessory, uid); } /** @@ -329,42 +274,108 @@ class UsbUserSettingsManager { mUser.getIdentifier()); } - public void dump(@NonNull DualDumpOutputStream dump, @NonNull String idName, long id) { - long token = dump.start(idName, id); + /** + * Can the app be the default for the USB device. I.e. can the app be launched by default if + * the device is plugged in. + * + * @param device The device the app would be default for + * @param packageName The package name of the app + * + * @return {@code true} if the app can be default + */ + private boolean canBeDefault(@NonNull UsbDevice device, String packageName) { + ActivityInfo[] activities = getPackageActivities(packageName); + if (activities != null) { + int numActivities = activities.length; + for (int i = 0; i < numActivities; i++) { + ActivityInfo activityInfo = activities[i]; + + try (XmlResourceParser parser = activityInfo.loadXmlMetaData(mPackageManager, + UsbManager.ACTION_USB_DEVICE_ATTACHED)) { + if (parser == null) { + continue; + } - synchronized (mLock) { - dump.write("user_id", UsbUserSettingsManagerProto.USER_ID, mUser.getIdentifier()); + XmlUtils.nextElement(parser); + while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { + if ("usb-device".equals(parser.getName())) { + DeviceFilter filter = DeviceFilter.read(parser); + if (filter.matches(device)) { + return true; + } + } - for (String deviceName : mDevicePermissionMap.keySet()) { - long devicePermissionToken = dump.start("device_permissions", - UsbUserSettingsManagerProto.DEVICE_PERMISSIONS); + XmlUtils.nextElement(parser); + } + } catch (Exception e) { + Slog.w(TAG, "Unable to load component info " + activityInfo.toString(), e); + } + } + } - dump.write("device_name", UsbSettingsDevicePermissionProto.DEVICE_NAME, deviceName); + return false; + } - SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName); - int count = uidList.size(); - for (int i = 0; i < count; i++) { - dump.write("uids", UsbSettingsDevicePermissionProto.UIDS, uidList.keyAt(i)); - } + /** + * Can the app be the default for the USB accessory. I.e. can the app be launched by default if + * the accessory is plugged in. + * + * @param accessory The accessory the app would be default for + * @param packageName The package name of the app + * + * @return {@code true} if the app can be default + */ + private boolean canBeDefault(@NonNull UsbAccessory accessory, String packageName) { + ActivityInfo[] activities = getPackageActivities(packageName); + if (activities != null) { + int numActivities = activities.length; + for (int i = 0; i < numActivities; i++) { + ActivityInfo activityInfo = activities[i]; + + try (XmlResourceParser parser = activityInfo.loadXmlMetaData(mPackageManager, + UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) { + if (parser == null) { + continue; + } - dump.end(devicePermissionToken); - } - for (UsbAccessory accessory : mAccessoryPermissionMap.keySet()) { - long accessoryPermissionToken = dump.start("accessory_permissions", - UsbUserSettingsManagerProto.ACCESSORY_PERMISSIONS); - - dump.write("accessory_description", - UsbSettingsAccessoryPermissionProto.ACCESSORY_DESCRIPTION, - accessory.getDescription()); - - SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory); - int count = uidList.size(); - for (int i = 0; i < count; i++) { - dump.write("uids", UsbSettingsAccessoryPermissionProto.UIDS, uidList.keyAt(i)); - } + XmlUtils.nextElement(parser); + while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { + if ("usb-accessory".equals(parser.getName())) { + AccessoryFilter filter = AccessoryFilter.read(parser); + if (filter.matches(accessory)) { + return true; + } + } - dump.end(accessoryPermissionToken); + XmlUtils.nextElement(parser); + } + } catch (Exception e) { + Slog.w(TAG, "Unable to load component info " + activityInfo.toString(), e); + } } + } + + return false; + } + + private ActivityInfo[] getPackageActivities(String packageName) { + try { + PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, + PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA); + return packageInfo.activities; + } catch (PackageManager.NameNotFoundException e) { + // ignore + } + return null; + } + + public void dump(@NonNull DualDumpOutputStream dump, @NonNull String idName, long id) { + long token = dump.start(idName, id); + + synchronized (mLock) { + dump.write("user_id", UsbUserSettingsManagerProto.USER_ID, mUser.getIdentifier()); + + mUsbPermissionManager.dump(dump); List<ResolveInfo> deviceAttachedActivities = queryIntentActivities( new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED)); diff --git a/tools/validatekeymaps/Android.bp b/tools/validatekeymaps/Android.bp index 6fb278c83f0a..819e75ba1fed 100644 --- a/tools/validatekeymaps/Android.bp +++ b/tools/validatekeymaps/Android.bp @@ -15,6 +15,7 @@ cc_binary_host { ], static_libs: [ + "libbase", "libinput", "libutils", "libcutils", diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp index bbfcba6272b2..f31f771004bd 100644 --- a/tools/validatekeymaps/Main.cpp +++ b/tools/validatekeymaps/Main.cpp @@ -18,7 +18,6 @@ #include <input/KeyLayoutMap.h> #include <input/VirtualKeyMap.h> #include <utils/PropertyMap.h> -#include <utils/String8.h> #include <stdarg.h> #include <stdio.h> @@ -98,7 +97,7 @@ static bool validateFile(const char* filename) { case FILETYPE_KEYLAYOUT: { sp<KeyLayoutMap> map; - status_t status = KeyLayoutMap::load(String8(filename), &map); + status_t status = KeyLayoutMap::load(filename, &map); if (status) { error("Error %d parsing key layout file.\n\n", status); return false; @@ -108,7 +107,7 @@ static bool validateFile(const char* filename) { case FILETYPE_KEYCHARACTERMAP: { sp<KeyCharacterMap> map; - status_t status = KeyCharacterMap::load(String8(filename), + status_t status = KeyCharacterMap::load(filename, KeyCharacterMap::FORMAT_ANY, &map); if (status) { error("Error %d parsing key character map file.\n\n", status); @@ -130,7 +129,7 @@ static bool validateFile(const char* filename) { case FILETYPE_VIRTUALKEYDEFINITION: { VirtualKeyMap* map; - status_t status = VirtualKeyMap::load(String8(filename), &map); + status_t status = VirtualKeyMap::load(filename, &map); if (status) { error("Error %d parsing virtual key definition file.\n\n", status); return false; diff --git a/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java index 7c99c497c54b..14263830660f 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java @@ -48,7 +48,7 @@ public class WifiAwareAgentNetworkSpecifier extends NetworkSpecifier implements private MessageDigest mDigester; public WifiAwareAgentNetworkSpecifier() { - // do nothing, already initialized to empty + initialize(); } public WifiAwareAgentNetworkSpecifier(WifiAwareNetworkSpecifier ns) { diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java index 0515e0637e03..657e5a70b53d 100644 --- a/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java +++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java @@ -18,6 +18,7 @@ package android.net.wifi.aware; import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import android.os.Parcel; import android.support.test.filters.SmallTest; @@ -60,6 +61,13 @@ public class WifiAwareAgentNetworkSpecifierTest { WifiAwareAgentNetworkSpecifier.CREATOR.createFromParcel(parcelR); assertEquals(dut, rereadDut); + + // Ensure that individual network specifiers are satisfied by both the original & marshaled + // |WifiAwareNetworkAgentSpecifier instances. + for (WifiAwareNetworkSpecifier ns : nsSet) { + assertTrue(dut.satisfiesAwareNetworkSpecifier(ns)); + assertTrue(rereadDut.satisfiesAwareNetworkSpecifier(ns)); + } } /** |