Merge "Add a new flag for enable_resizing_metrics." into main
diff --git a/cmds/screencap/Android.bp b/cmds/screencap/Android.bp
index c009c1f..16026ec 100644
--- a/cmds/screencap/Android.bp
+++ b/cmds/screencap/Android.bp
@@ -17,6 +17,7 @@
"libutils",
"libbinder",
"libjnigraphics",
+ "libhwui",
"libui",
"libgui",
],
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 01b20f4..12de82a 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -15,36 +15,28 @@
*/
#include <android/bitmap.h>
+#include <android/graphics/bitmap.h>
#include <android/gui/DisplayCaptureArgs.h>
#include <binder/ProcessState.h>
#include <errno.h>
-#include <unistd.h>
-#include <stdio.h>
#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-
-#include <linux/fb.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/wait.h>
-
-#include <android/bitmap.h>
-
-#include <binder/ProcessState.h>
-
#include <ftl/concat.h>
#include <ftl/optional.h>
+#include <getopt.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SyncScreenCaptureListener.h>
-
+#include <linux/fb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <system/graphics.h>
#include <ui/GraphicTypes.h>
#include <ui/PixelFormat.h>
-#include <system/graphics.h>
-
using namespace android;
#define COLORSPACE_UNKNOWN 0
@@ -85,11 +77,12 @@
};
}
-static const struct option LONG_OPTIONS[] = {
- {"png", no_argument, nullptr, 'p'},
- {"help", no_argument, nullptr, 'h'},
- {"hint-for-seamless", no_argument, nullptr, LongOpts::HintForSeamless},
- {0, 0, 0, 0}};
+static const struct option LONG_OPTIONS[] = {{"png", no_argument, nullptr, 'p'},
+ {"jpeg", no_argument, nullptr, 'j'},
+ {"help", no_argument, nullptr, 'h'},
+ {"hint-for-seamless", no_argument, nullptr,
+ LongOpts::HintForSeamless},
+ {0, 0, 0, 0}};
static int32_t flinger2bitmapFormat(PixelFormat f)
{
@@ -170,10 +163,11 @@
return 0;
}
-status_t saveImage(const char* fn, bool png, const ScreenCaptureResults& captureResults) {
+status_t saveImage(const char* fn, std::optional<AndroidBitmapCompressFormat> format,
+ const ScreenCaptureResults& captureResults) {
void* base = nullptr;
ui::Dataspace dataspace = captureResults.capturedDataspace;
- sp<GraphicBuffer> buffer = captureResults.buffer;
+ const sp<GraphicBuffer>& buffer = captureResults.buffer;
status_t result = buffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);
@@ -188,22 +182,48 @@
return 1;
}
+ void* gainmapBase = nullptr;
+ sp<GraphicBuffer> gainmap = captureResults.optionalGainMap;
+
+ if (gainmap) {
+ result = gainmap->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &gainmapBase);
+ if (gainmapBase == nullptr || result != NO_ERROR) {
+ fprintf(stderr, "Failed to capture gainmap with error code (%d)\n", result);
+ gainmapBase = nullptr;
+ // Fall-through: just don't attempt to write the gainmap
+ }
+ }
+
int fd = -1;
if (fn == nullptr) {
fd = dup(STDOUT_FILENO);
if (fd == -1) {
fprintf(stderr, "Error writing to stdout. (%s)\n", strerror(errno));
+ if (gainmapBase) {
+ gainmap->unlock();
+ }
+
+ if (base) {
+ buffer->unlock();
+ }
return 1;
}
} else {
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
if (fd == -1) {
fprintf(stderr, "Error opening file: %s (%s)\n", fn, strerror(errno));
+ if (gainmapBase) {
+ gainmap->unlock();
+ }
+
+ if (base) {
+ buffer->unlock();
+ }
return 1;
}
}
- if (png) {
+ if (format) {
AndroidBitmapInfo info;
info.format = flinger2bitmapFormat(buffer->getPixelFormat());
info.flags = ANDROID_BITMAP_FLAGS_ALPHA_PREMUL;
@@ -211,16 +231,31 @@
info.height = buffer->getHeight();
info.stride = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat());
- int result = AndroidBitmap_compress(&info, static_cast<int32_t>(dataspace), base,
- ANDROID_BITMAP_COMPRESS_FORMAT_PNG, 100, &fd,
+ int result;
+
+ if (gainmapBase) {
+ result = ABitmap_compressWithGainmap(&info, static_cast<ADataSpace>(dataspace), base,
+ gainmapBase, captureResults.hdrSdrRatio, *format,
+ 100, &fd,
+ [](void* fdPtr, const void* data,
+ size_t size) -> bool {
+ int bytesWritten =
+ write(*static_cast<int*>(fdPtr), data,
+ size);
+ return bytesWritten == size;
+ });
+ } else {
+ result = AndroidBitmap_compress(&info, static_cast<int32_t>(dataspace), base, *format,
+ 100, &fd,
[](void* fdPtr, const void* data, size_t size) -> bool {
int bytesWritten = write(*static_cast<int*>(fdPtr),
data, size);
return bytesWritten == size;
});
+ }
if (result != ANDROID_BITMAP_RESULT_SUCCESS) {
- fprintf(stderr, "Failed to compress PNG (error code: %d)\n", result);
+ fprintf(stderr, "Failed to compress (error code: %d)\n", result);
}
if (fn != NULL) {
@@ -245,6 +280,14 @@
}
close(fd);
+ if (gainmapBase) {
+ gainmap->unlock();
+ }
+
+ if (base) {
+ buffer->unlock();
+ }
+
return 0;
}
@@ -262,13 +305,17 @@
gui::CaptureArgs captureArgs;
const char* pname = argv[0];
bool png = false;
+ bool jpeg = false;
bool all = false;
int c;
- while ((c = getopt_long(argc, argv, "aphd:", LONG_OPTIONS, nullptr)) != -1) {
+ while ((c = getopt_long(argc, argv, "apjhd:", LONG_OPTIONS, nullptr)) != -1) {
switch (c) {
case 'p':
png = true;
break;
+ case 'j':
+ jpeg = true;
+ break;
case 'd': {
errno = 0;
char* end = nullptr;
@@ -325,6 +372,14 @@
baseName = filename.substr(0, filename.size()-4);
suffix = ".png";
png = true;
+ } else if (filename.ends_with(".jpeg")) {
+ baseName = filename.substr(0, filename.size() - 5);
+ suffix = ".jpeg";
+ jpeg = true;
+ } else if (filename.ends_with(".jpg")) {
+ baseName = filename.substr(0, filename.size() - 4);
+ suffix = ".jpg";
+ jpeg = true;
} else {
baseName = filename;
}
@@ -350,6 +405,20 @@
}
}
+ if (png && jpeg) {
+ fprintf(stderr, "Ambiguous file type");
+ return 1;
+ }
+
+ std::optional<AndroidBitmapCompressFormat> format = std::nullopt;
+
+ if (png) {
+ format = ANDROID_BITMAP_COMPRESS_FORMAT_PNG;
+ } else if (jpeg) {
+ format = ANDROID_BITMAP_COMPRESS_FORMAT_JPEG;
+ captureArgs.attachGainmap = true;
+ }
+
// setThreadPoolMaxThreadCount(0) actually tells the kernel it's
// not allowed to spawn any additional threads, but we still spawn
// a binder thread from userspace when we call startThreadPool().
@@ -385,7 +454,7 @@
if (!filename.empty()) {
fn = filename.c_str();
}
- if (const status_t saveImageStatus = saveImage(fn, png, result) != 0) {
+ if (const status_t saveImageStatus = saveImage(fn, format, result) != 0) {
fprintf(stderr, "Saving image failed.\n");
return saveImageStatus;
}
diff --git a/core/java/android/os/SystemVibratorManager.java b/core/java/android/os/SystemVibratorManager.java
index 58ab5b6..cfbf528 100644
--- a/core/java/android/os/SystemVibratorManager.java
+++ b/core/java/android/os/SystemVibratorManager.java
@@ -138,11 +138,14 @@
Log.w(TAG, "Failed to vibrate; no vibrator manager service.");
return;
}
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason=" + reason);
try {
mService.vibrate(uid, mContext.getDeviceId(), opPkg, effect, attributes, reason,
mToken);
} catch (RemoteException e) {
Log.w(TAG, "Failed to vibrate.", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -152,11 +155,14 @@
Log.w(TAG, "Failed to perform haptic feedback; no vibrator manager service.");
return;
}
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "performHapticFeedback, reason=" + reason);
try {
mService.performHapticFeedback(mUid, mContext.getDeviceId(), mPackageName, constant,
reason, flags, privFlags);
} catch (RemoteException e) {
Log.w(TAG, "Failed to perform haptic feedback.", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -168,11 +174,15 @@
+ " no vibrator manager service.");
return;
}
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR,
+ "performHapticFeedbackForInputDevice, reason=" + reason);
try {
mService.performHapticFeedbackForInputDevice(mUid, mContext.getDeviceId(), mPackageName,
constant, inputDeviceId, inputSource, reason, flags, privFlags);
} catch (RemoteException e) {
Log.w(TAG, "Failed to perform haptic feedback for input device.", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
diff --git a/libs/hwui/apex/android_bitmap.cpp b/libs/hwui/apex/android_bitmap.cpp
index c80a9b4..000f109 100644
--- a/libs/hwui/apex/android_bitmap.cpp
+++ b/libs/hwui/apex/android_bitmap.cpp
@@ -14,21 +14,21 @@
* limitations under the License.
*/
-#include <log/log.h>
-
-#include "android/graphics/bitmap.h"
-#include "TypeCast.h"
-#include "GraphicsJNI.h"
-
+#include <Gainmap.h>
#include <GraphicsJNI.h>
-#include <hwui/Bitmap.h>
#include <SkBitmap.h>
#include <SkColorSpace.h>
#include <SkImageInfo.h>
#include <SkRefCnt.h>
#include <SkStream.h>
+#include <hwui/Bitmap.h>
+#include <log/log.h>
#include <utils/Color.h>
+#include "GraphicsJNI.h"
+#include "TypeCast.h"
+#include "android/graphics/bitmap.h"
+
using namespace android;
ABitmap* ABitmap_acquireBitmapFromJava(JNIEnv* env, jobject bitmapObj) {
@@ -215,6 +215,14 @@
int ABitmap_compress(const AndroidBitmapInfo* info, ADataSpace dataSpace, const void* pixels,
AndroidBitmapCompressFormat inFormat, int32_t quality, void* userContext,
AndroidBitmap_CompressWriteFunc fn) {
+ return ABitmap_compressWithGainmap(info, dataSpace, pixels, nullptr, -1.f, inFormat, quality,
+ userContext, fn);
+}
+
+int ABitmap_compressWithGainmap(const AndroidBitmapInfo* info, ADataSpace dataSpace,
+ const void* pixels, const void* gainmapPixels, float hdrSdrRatio,
+ AndroidBitmapCompressFormat inFormat, int32_t quality,
+ void* userContext, AndroidBitmap_CompressWriteFunc fn) {
Bitmap::JavaCompressFormat format;
switch (inFormat) {
case ANDROID_BITMAP_COMPRESS_FORMAT_JPEG:
@@ -275,7 +283,7 @@
// besides ADATASPACE_UNKNOWN as an error?
cs = nullptr;
} else {
- cs = uirenderer::DataSpaceToColorSpace((android_dataspace) dataSpace);
+ cs = uirenderer::DataSpaceToColorSpace((android_dataspace)dataSpace);
// DataSpaceToColorSpace treats UNKNOWN as SRGB, but compress forces the
// client to specify SRGB if that is what they want.
if (!cs || dataSpace == ADATASPACE_UNKNOWN) {
@@ -292,16 +300,70 @@
auto imageInfo =
SkImageInfo::Make(info->width, info->height, colorType, alphaType, std::move(cs));
- SkBitmap bitmap;
- // We are not going to modify the pixels, but installPixels expects them to
- // not be const, since for all it knows we might want to draw to the SkBitmap.
- if (!bitmap.installPixels(imageInfo, const_cast<void*>(pixels), info->stride)) {
- return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
+
+ // Validate the image info
+ {
+ SkBitmap tempBitmap;
+ if (!tempBitmap.installPixels(imageInfo, const_cast<void*>(pixels), info->stride)) {
+ return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
+ }
+ }
+
+ SkPixelRef pixelRef =
+ SkPixelRef(info->width, info->height, const_cast<void*>(pixels), info->stride);
+
+ auto bitmap = Bitmap::createFrom(imageInfo, pixelRef);
+
+ if (gainmapPixels) {
+ auto gainmap = sp<uirenderer::Gainmap>::make();
+ gainmap->info.fGainmapRatioMin = {
+ 1.f,
+ 1.f,
+ 1.f,
+ 1.f,
+ };
+ gainmap->info.fGainmapRatioMax = {
+ hdrSdrRatio,
+ hdrSdrRatio,
+ hdrSdrRatio,
+ 1.f,
+ };
+ gainmap->info.fGainmapGamma = {
+ 1.f,
+ 1.f,
+ 1.f,
+ 1.f,
+ };
+
+ static constexpr auto kDefaultEpsilon = 1.f / 64.f;
+ gainmap->info.fEpsilonSdr = {
+ kDefaultEpsilon,
+ kDefaultEpsilon,
+ kDefaultEpsilon,
+ 1.f,
+ };
+ gainmap->info.fEpsilonHdr = {
+ kDefaultEpsilon,
+ kDefaultEpsilon,
+ kDefaultEpsilon,
+ 1.f,
+ };
+ gainmap->info.fDisplayRatioSdr = 1.f;
+ gainmap->info.fDisplayRatioHdr = hdrSdrRatio;
+
+ SkPixelRef gainmapPixelRef = SkPixelRef(info->width, info->height,
+ const_cast<void*>(gainmapPixels), info->stride);
+ auto gainmapBitmap = Bitmap::createFrom(imageInfo, gainmapPixelRef);
+ gainmap->bitmap = std::move(gainmapBitmap);
+ bitmap->setGainmap(std::move(gainmap));
}
CompressWriter stream(userContext, fn);
- return Bitmap::compress(bitmap, format, quality, &stream) ? ANDROID_BITMAP_RESULT_SUCCESS
- : ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
+
+ return bitmap->compress(format, quality, &stream)
+
+ ? ANDROID_BITMAP_RESULT_SUCCESS
+ : ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
}
AHardwareBuffer* ABitmap_getHardwareBuffer(ABitmap* bitmapHandle) {
diff --git a/libs/hwui/apex/include/android/graphics/bitmap.h b/libs/hwui/apex/include/android/graphics/bitmap.h
index 8c4b439d..6f65e9e 100644
--- a/libs/hwui/apex/include/android/graphics/bitmap.h
+++ b/libs/hwui/apex/include/android/graphics/bitmap.h
@@ -65,6 +65,13 @@
ANDROID_API int ABitmap_compress(const AndroidBitmapInfo* info, ADataSpace dataSpace, const void* pixels,
AndroidBitmapCompressFormat format, int32_t quality, void* userContext,
AndroidBitmap_CompressWriteFunc);
+// If gainmapPixels is null, then no gainmap is encoded, and hdrSdrRatio is
+// unused
+ANDROID_API int ABitmap_compressWithGainmap(const AndroidBitmapInfo* info, ADataSpace dataSpace,
+ const void* pixels, const void* gainmapPixels,
+ float hdrSdrRatio, AndroidBitmapCompressFormat format,
+ int32_t quality, void* userContext,
+ AndroidBitmap_CompressWriteFunc);
/**
* Retrieve the native object associated with a HARDWARE Bitmap.
*
diff --git a/libs/hwui/libhwui.map.txt b/libs/hwui/libhwui.map.txt
index d03ceb4..2414299 100644
--- a/libs/hwui/libhwui.map.txt
+++ b/libs/hwui/libhwui.map.txt
@@ -13,6 +13,7 @@
ABitmapConfig_getFormatFromConfig;
ABitmapConfig_getConfigFromFormat;
ABitmap_compress;
+ ABitmap_compressWithGainmap;
ABitmap_getHardwareBuffer;
ACanvas_isSupportedPixelFormat;
ACanvas_getNativeHandleFromJava;
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
index 7b2a284..11406fa 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java
@@ -241,10 +241,6 @@
formattedTime);
}
}
- // TODO: b/333527800 - For TYPE_SCHEDULE_TIME rules we could do the same; however
- // according to the snoozing discussions the mode may or may not end at the scheduled
- // time if manually activated. When we resolve that point, we could calculate end time
- // for these modes as well.
return getTriggerDescription();
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index a4dc8fc..557257d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -72,7 +72,7 @@
override fun matches(key: ElementKey, content: ContentKey) = true
}
-private object TransitionDuration {
+object TransitionDuration {
const val BETWEEN_HUB_AND_EDIT_MODE_MS = 1000
const val EDIT_MODE_TO_HUB_CONTENT_MS = 167
const val EDIT_MODE_TO_HUB_GRID_DELAY_MS = 167
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index efe0f2e..f4d1242 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -108,6 +108,8 @@
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
@@ -179,6 +181,7 @@
import com.android.systemui.communal.widgets.WidgetConfigurator
import com.android.systemui.res.R
import com.android.systemui.statusbar.phone.SystemUIDialogFactory
+import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class)
@@ -1155,6 +1158,15 @@
val selectedIndex =
selectedKey?.let { key -> contentListState.list.indexOfFirst { it.key == key } }
+ val interactionSource = remember { MutableInteractionSource() }
+ val focusRequester = remember { FocusRequester() }
+ if (viewModel.isEditMode && selected) {
+ LaunchedEffect(Unit) {
+ delay(TransitionDuration.BETWEEN_HUB_AND_EDIT_MODE_MS.toLong())
+ focusRequester.requestFocus()
+ }
+ }
+
val isSelected = selectedKey == model.key
val selectableModifier =
@@ -1162,7 +1174,7 @@
Modifier.selectable(
selected = isSelected,
onClick = { viewModel.setSelectedKey(model.key) },
- interactionSource = remember { MutableInteractionSource() },
+ interactionSource = interactionSource,
indication = null,
)
} else {
@@ -1172,6 +1184,8 @@
Box(
modifier =
modifier
+ .focusRequester(focusRequester)
+ .focusable(interactionSource = interactionSource)
.then(selectableModifier)
.thenIf(!viewModel.isEditMode && !model.inQuietMode) {
Modifier.pointerInput(Unit) {
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
index 4251b81..d596589 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
@@ -53,6 +53,7 @@
import android.text.TextUtils;
import android.util.Log;
import android.view.Window;
+import android.view.WindowManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
@@ -308,6 +309,9 @@
private void setUpDialog(AlertDialog dialog) {
SystemUIDialog.registerDismissListener(dialog);
SystemUIDialog.applyFlags(dialog, /* showWhenLocked= */ false);
+
+ final Window w = dialog.getWindow();
+ w.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
SystemUIDialog.setDialogSize(dialog);
dialog.setOnCancelListener(this::onDialogDismissedOrCancelled);
@@ -315,7 +319,6 @@
dialog.create();
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true);
- final Window w = dialog.getWindow();
w.addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
}
diff --git a/services/core/java/com/android/server/cpu/CpuInfoReader.java b/services/core/java/com/android/server/cpu/CpuInfoReader.java
index 984ad1d..a68451a 100644
--- a/services/core/java/com/android/server/cpu/CpuInfoReader.java
+++ b/services/core/java/com/android/server/cpu/CpuInfoReader.java
@@ -40,6 +40,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -80,13 +81,14 @@
/** package **/ @interface CpusetCategory{}
// TODO(b/242722241): Protect updatable variables with a local lock.
- private final File mCpusetDir;
private final long mMinReadIntervalMillis;
private final SparseIntArray mCpusetCategoriesByCpus = new SparseIntArray();
private final SparseArray<File> mCpuFreqPolicyDirsById = new SparseArray<>();
private final SparseArray<StaticPolicyInfo> mStaticPolicyInfoById = new SparseArray<>();
private final SparseArray<LongSparseLongArray> mTimeInStateByPolicyId = new SparseArray<>();
+ private final AtomicBoolean mShouldReadCpusetCategories;
+ private File mCpusetDir;
private File mCpuFreqDir;
private File mProcStatFile;
private SparseArray<CpuUsageStats> mCumulativeCpuUsageStats = new SparseArray<>();
@@ -106,10 +108,13 @@
mCpuFreqDir = cpuFreqDir;
mProcStatFile = procStatFile;
mMinReadIntervalMillis = minReadIntervalMillis;
+ mShouldReadCpusetCategories = new AtomicBoolean(true);
}
/**
* Initializes CpuInfoReader and returns a boolean to indicate whether the reader is enabled.
+ *
+ * <p>Returns {@code true} on success. Otherwise, returns {@code false}.
*/
public boolean init() {
if (mCpuFreqPolicyDirsById.size() > 0) {
@@ -139,8 +144,7 @@
Slogf.e(TAG, "Missing proc stat file at %s", mProcStatFile.getAbsolutePath());
return false;
}
- readCpusetCategories();
- if (mCpusetCategoriesByCpus.size() == 0) {
+ if (!readCpusetCategories()) {
Slogf.e(TAG, "Failed to read cpuset information from %s", mCpusetDir.getAbsolutePath());
return false;
}
@@ -163,10 +167,19 @@
return true;
}
+ public void stopPeriodicCpusetReading() {
+ mShouldReadCpusetCategories.set(false);
+ if (!readCpusetCategories()) {
+ Slogf.e(TAG, "Failed to read cpuset information from %s",
+ mCpusetDir.getAbsolutePath());
+ mIsEnabled = false;
+ }
+ }
+
/**
* Reads CPU information from proc and sys fs files exposed by the Kernel.
*
- * @return SparseArray keyed by CPU core ID; {@code null} on error or when disabled.
+ * <p>Returns SparseArray keyed by CPU core ID; {@code null} on error or when disabled.
*/
@Nullable
public SparseArray<CpuInfo> readCpuInfos() {
@@ -183,6 +196,12 @@
}
mLastReadUptimeMillis = uptimeMillis;
mLastReadCpuInfos = null;
+ if (mShouldReadCpusetCategories.get() && !readCpusetCategories()) {
+ Slogf.e(TAG, "Failed to read cpuset information from %s",
+ mCpusetDir.getAbsolutePath());
+ mIsEnabled = false;
+ return null;
+ }
SparseArray<CpuUsageStats> cpuUsageStatsByCpus = readLatestCpuUsageStats();
if (cpuUsageStatsByCpus == null || cpuUsageStatsByCpus.size() == 0) {
Slogf.e(TAG, "Failed to read latest CPU usage stats");
@@ -324,7 +343,7 @@
/**
* Sets the CPU frequency for testing.
*
- * <p>Return {@code true} on success. Otherwise, returns {@code false}.
+ * <p>Returns {@code true} on success. Otherwise, returns {@code false}.
*/
@VisibleForTesting
boolean setCpuFreqDir(File cpuFreqDir) {
@@ -354,7 +373,7 @@
/**
* Sets the proc stat file for testing.
*
- * <p>Return true on success. Otherwise, returns false.
+ * <p>Returns {@code true} on success. Otherwise, returns {@code false}.
*/
@VisibleForTesting
boolean setProcStatFile(File procStatFile) {
@@ -366,6 +385,21 @@
return true;
}
+ /**
+ * Set the cpuset directory for testing.
+ *
+ * <p>Returns {@code true} on success. Otherwise, returns {@code false}.
+ */
+ @VisibleForTesting
+ boolean setCpusetDir(File cpusetDir) {
+ if (!cpusetDir.exists() && !cpusetDir.isDirectory()) {
+ Slogf.e(TAG, "Missing or invalid cpuset directory at %s", cpusetDir.getAbsolutePath());
+ return false;
+ }
+ mCpusetDir = cpusetDir;
+ return true;
+ }
+
private void populateCpuFreqPolicyDirsById(File[] policyDirs) {
mCpuFreqPolicyDirsById.clear();
for (int i = 0; i < policyDirs.length; i++) {
@@ -381,12 +415,27 @@
}
}
- private void readCpusetCategories() {
+ /**
+ * Reads cpuset categories by CPU.
+ *
+ * <p>The cpusets are read from the cpuset category specific directories
+ * under the /dev/cpuset directory. The cpuset categories are subject to change at any point
+ * during system bootup, as determined by the init rules specified within the init.rc files.
+ * Therefore, it's necessary to read the cpuset categories each time before accessing CPU usage
+ * statistics until the system boot completes. Once the boot is complete, the latest changes to
+ * the cpuset categories will take a few seconds to propagate. Thus, on boot complete,
+ * the periodic reading is stopped with a delay of
+ * {@link CpuMonitorService#STOP_PERIODIC_CPUSET_READING_DELAY_MILLISECONDS}.
+ *
+ * <p>Returns {@code true} on success. Otherwise, returns {@code false}.
+ */
+ private boolean readCpusetCategories() {
File[] cpusetDirs = mCpusetDir.listFiles(File::isDirectory);
if (cpusetDirs == null) {
Slogf.e(TAG, "Missing cpuset directories at %s", mCpusetDir.getAbsolutePath());
- return;
+ return false;
}
+ mCpusetCategoriesByCpus.clear();
for (int i = 0; i < cpusetDirs.length; i++) {
File dir = cpusetDirs[i];
@CpusetCategory int cpusetCategory;
@@ -418,6 +467,7 @@
}
}
}
+ return mCpusetCategoriesByCpus.size() > 0;
}
private void readStaticPolicyInfo() {
diff --git a/services/core/java/com/android/server/cpu/CpuMonitorService.java b/services/core/java/com/android/server/cpu/CpuMonitorService.java
index 7ea2c1b..88ff7e4 100644
--- a/services/core/java/com/android/server/cpu/CpuMonitorService.java
+++ b/services/core/java/com/android/server/cpu/CpuMonitorService.java
@@ -22,6 +22,7 @@
import static com.android.server.cpu.CpuAvailabilityMonitoringConfig.CPUSET_BACKGROUND;
import static com.android.server.cpu.CpuInfoReader.FLAG_CPUSET_CATEGORY_BACKGROUND;
import static com.android.server.cpu.CpuInfoReader.FLAG_CPUSET_CATEGORY_TOP_APP;
+import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
import android.annotation.Nullable;
import android.content.Context;
@@ -82,6 +83,15 @@
// frequently. Should this duration be increased as well when this happens?
private static final long LATEST_AVAILABILITY_DURATION_MILLISECONDS =
TimeUnit.SECONDS.toMillis(30);
+ /**
+ * Delay to stop the periodic cpuset reading after boot complete.
+ *
+ * Device specific implementations can update cpuset on boot complete. This may take
+ * a few seconds to propagate. So, wait for a few minutes before stopping the periodic cpuset
+ * reading.
+ */
+ private static final long STOP_PERIODIC_CPUSET_READING_DELAY_MILLISECONDS =
+ TimeUnit.MINUTES.toMillis(2);
private final Context mContext;
private final HandlerThread mHandlerThread;
@@ -90,6 +100,7 @@
private final long mNormalMonitoringIntervalMillis;
private final long mDebugMonitoringIntervalMillis;
private final long mLatestAvailabilityDurationMillis;
+ private final long mStopPeriodicCpusetReadingDelayMillis;
private final Object mLock = new Object();
@GuardedBy("mLock")
private final SparseArrayMap<CpuMonitorInternal.CpuAvailabilityCallback,
@@ -153,13 +164,15 @@
this(context, new CpuInfoReader(), new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, /* allowIo= */ true),
Build.IS_USERDEBUG || Build.IS_ENG, NORMAL_MONITORING_INTERVAL_MILLISECONDS,
- DEBUG_MONITORING_INTERVAL_MILLISECONDS, LATEST_AVAILABILITY_DURATION_MILLISECONDS);
+ DEBUG_MONITORING_INTERVAL_MILLISECONDS, LATEST_AVAILABILITY_DURATION_MILLISECONDS,
+ STOP_PERIODIC_CPUSET_READING_DELAY_MILLISECONDS);
}
@VisibleForTesting
CpuMonitorService(Context context, CpuInfoReader cpuInfoReader, HandlerThread handlerThread,
boolean shouldDebugMonitor, long normalMonitoringIntervalMillis,
- long debugMonitoringIntervalMillis, long latestAvailabilityDurationMillis) {
+ long debugMonitoringIntervalMillis, long latestAvailabilityDurationMillis,
+ long stopPeriodicCpusetReadingDelayMillis) {
super(context);
mContext = context;
mHandlerThread = handlerThread;
@@ -167,6 +180,7 @@
mNormalMonitoringIntervalMillis = normalMonitoringIntervalMillis;
mDebugMonitoringIntervalMillis = debugMonitoringIntervalMillis;
mLatestAvailabilityDurationMillis = latestAvailabilityDurationMillis;
+ mStopPeriodicCpusetReadingDelayMillis = stopPeriodicCpusetReadingDelayMillis;
mCpuInfoReader = cpuInfoReader;
mCpusetInfosByCpuset = new SparseArray<>(2);
mCpusetInfosByCpuset.append(CPUSET_ALL, new CpusetInfo(CPUSET_ALL));
@@ -200,6 +214,16 @@
}
}
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase != PHASE_BOOT_COMPLETED) {
+ return;
+ }
+ Slogf.i(TAG, "Stopping periodic cpuset reading on boot complete");
+ mHandler.postDelayed(() -> mCpuInfoReader.stopPeriodicCpusetReading(),
+ mStopPeriodicCpusetReadingDelayMillis);
+ }
+
@VisibleForTesting
long getCurrentMonitoringIntervalMillis() {
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java b/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java
index 2ed6f44..67c3621 100644
--- a/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java
+++ b/services/core/java/com/android/server/input/debug/TouchpadVisualizationView.java
@@ -39,35 +39,43 @@
TouchpadHardwareState mLatestHardwareState = new TouchpadHardwareState(0, 0, 0, 0,
new TouchpadFingerState[]{});
- private final Paint mOvalPaint;
+ private final Paint mOvalStrokePaint;
+ private final Paint mOvalFillPaint;
+ private final RectF mTempOvalRect = new RectF();
public TouchpadVisualizationView(Context context,
TouchpadHardwareProperties touchpadHardwareProperties) {
super(context);
mTouchpadHardwareProperties = touchpadHardwareProperties;
mScaleFactor = 1;
- mOvalPaint = new Paint();
- mOvalPaint.setAntiAlias(true);
- mOvalPaint.setARGB(255, 0, 0, 0);
- mOvalPaint.setStyle(Paint.Style.STROKE);
+ mOvalStrokePaint = new Paint();
+ mOvalStrokePaint.setAntiAlias(true);
+ mOvalStrokePaint.setARGB(255, 0, 0, 0);
+ mOvalStrokePaint.setStyle(Paint.Style.STROKE);
+ mOvalFillPaint = new Paint();
+ mOvalFillPaint.setAntiAlias(true);
+ mOvalFillPaint.setARGB(255, 0, 0, 0);
}
- private final RectF mOvalRect = new RectF();
-
- private void drawOval(Canvas canvas, float x, float y, float major, float minor, float angle,
- Paint paint) {
+ private void drawOval(Canvas canvas, float x, float y, float major, float minor, float angle) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.rotate(angle, x, y);
- mOvalRect.left = x - minor / 2;
- mOvalRect.right = x + minor / 2;
- mOvalRect.top = y - major / 2;
- mOvalRect.bottom = y + major / 2;
- canvas.drawOval(mOvalRect, paint);
+ mTempOvalRect.left = x - minor / 2;
+ mTempOvalRect.right = x + minor / 2;
+ mTempOvalRect.top = y - major / 2;
+ mTempOvalRect.bottom = y + major / 2;
+ canvas.drawOval(mTempOvalRect, mOvalStrokePaint);
+ canvas.drawOval(mTempOvalRect, mOvalFillPaint);
canvas.restore();
}
@Override
protected void onDraw(Canvas canvas) {
+ float maximumPressure = 0;
+ for (TouchpadFingerState touchpadFingerState : mLatestHardwareState.getFingerStates()) {
+ maximumPressure = Math.max(maximumPressure, touchpadFingerState.getPressure());
+ }
+
for (TouchpadFingerState touchpadFingerState : mLatestHardwareState.getFingerStates()) {
float newX = translateRange(mTouchpadHardwareProperties.getLeft(),
mTouchpadHardwareProperties.getRight(), 0, getWidth(),
@@ -88,7 +96,11 @@
float newTouchMajor = touchpadFingerState.getTouchMajor() * mScaleFactor / resY;
float newTouchMinor = touchpadFingerState.getTouchMinor() * mScaleFactor / resX;
- drawOval(canvas, newX, newY, newTouchMajor, newTouchMinor, newAngle, mOvalPaint);
+ float pressureToOpacity = translateRange(0, maximumPressure, 0, 255,
+ touchpadFingerState.getPressure());
+ mOvalFillPaint.setAlpha((int) pressureToOpacity);
+
+ drawOval(canvas, newX, newY, newTouchMajor, newTouchMinor, newAngle);
}
}
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java b/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java
index 195e91c..49825f1 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java
@@ -64,13 +64,36 @@
String targetPkg, int targetUserId);
/**
- * Same as {@link #checkGrantUriPermissionFromIntent(Intent, int, String, int)}, but with an
- * extra parameter {@code requireContentUriPermissionFromCaller}, which is the value from {@link
- * android.R.attr#requireContentUriPermissionFromCaller} attribute.
+ * Same as {@link #checkGrantUriPermissionFromIntent(Intent, int, String, int)}, but with:
+ * - {@code requireContentUriPermissionFromCaller}, which is the value from {@link
+ * android.R.attr#requireContentUriPermissionFromCaller} attribute.
+ * - {@code requestHashCode}, which is required to differentiate activity launches for logging
+ * ContentOrFileUriEventReported message.
*/
NeededUriGrants checkGrantUriPermissionFromIntent(Intent intent, int callingUid,
String targetPkg, int targetUserId,
- @RequiredContentUriPermission int requireContentUriPermissionFromCaller);
+ @RequiredContentUriPermission int requireContentUriPermissionFromCaller,
+ int requestHashCode);
+
+ /**
+ * Notify that an activity launch request has been completed and perform the following actions:
+ * - If the activity launch was unsuccessful, then clean up all the collected the content URIs
+ * that were passed during that launch.
+ * - If the activity launch was successful, then log cog content URIs that were passed during
+ * that launch. Specifically:
+ * - The caller didn't have read permission to them.
+ * - The activity's {@link android.R.attr#requireContentUriPermissionFromCaller} was set to
+ * "none".
+ *
+ * <p>Note that:
+ * - The API has to be called after
+ * {@link #checkGrantUriPermissionFromIntent(Intent, int, String, int, int, int)} was called.
+ * - The API is not idempotent, i.e. content URIs may be logged only once because the API clears
+ * the content URIs after logging.
+ */
+ void notifyActivityLaunchRequestCompleted(int requestHashCode, boolean isSuccessfulLaunch,
+ String intentAction, int callingUid, String callingActivityName, int calleeUid,
+ String calleeActivityName, boolean isStartActivityForResult);
/**
* Extend a previously calculated set of permissions grants to the given
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index a581b08..3479b6c 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -24,6 +24,7 @@
import static android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION;
import static android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
import static android.content.pm.ActivityInfo.CONTENT_URI_PERMISSION_NONE;
+import static android.content.pm.ActivityInfo.CONTENT_URI_PERMISSION_READ;
import static android.content.pm.ActivityInfo.CONTENT_URI_PERMISSION_READ_OR_WRITE;
import static android.content.pm.ActivityInfo.isRequiredContentUriPermissionRead;
import static android.content.pm.ActivityInfo.isRequiredContentUriPermissionWrite;
@@ -39,6 +40,8 @@
import static android.os.Process.myUid;
import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
+import static com.android.internal.util.FrameworkStatsLog.CONTENT_OR_FILE_URI_EVENT_REPORTED;
+import static com.android.internal.util.FrameworkStatsLog.CONTENT_OR_FILE_URI_EVENT_REPORTED__EVENT_TYPE__CONTENT_URI_WITHOUT_CALLER_READ_PERMISSION;
import static com.android.server.uri.UriGrantsManagerService.H.PERSIST_URI_GRANTS_MSG;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -78,6 +81,7 @@
import android.provider.Downloads;
import android.text.format.DateUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
@@ -86,6 +90,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.Preconditions;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
@@ -153,6 +158,22 @@
private final SparseArray<ArrayMap<GrantUri, UriPermission>>
mGrantedUriPermissions = new SparseArray<>();
+ /**
+ * Global map of activity launches to sets of passed content URIs. Specifically:
+ * - The caller didn't have read permission to them.
+ * - The callee activity's {@link android.R.attr#requireContentUriPermissionFromCaller} was set
+ * to "none".
+ *
+ * <p>This map is used for logging the ContentOrFileUriEventReported message.
+ *
+ * <p>The launch id is the ActivityStarter.Request#hashCode and has to be received from
+ * ActivityStarter to {@link #checkGrantUriPermissionFromIntentUnlocked(int, String, Intent,
+ * int, NeededUriGrants, int, Integer, Integer)}.
+ */
+ @GuardedBy("mLaunchToContentUrisWithoutCallerReadPermission")
+ private final SparseArray<ArraySet<Uri>> mLaunchToContentUrisWithoutCallerReadPermission =
+ new SparseArray<>();
+
private UriGrantsManagerService() {
this(SystemServiceManager.ensureSystemDir(), "uri-grants");
}
@@ -613,7 +634,8 @@
/** Like checkGrantUriPermission, but takes an Intent. */
private NeededUriGrants checkGrantUriPermissionFromIntentUnlocked(int callingUid,
String targetPkg, Intent intent, int mode, NeededUriGrants needed, int targetUserId,
- @RequiredContentUriPermission Integer requireContentUriPermissionFromCaller) {
+ @RequiredContentUriPermission Integer requireContentUriPermissionFromCaller,
+ Integer requestHashCode) {
if (DEBUG) Slog.v(TAG,
"Checking URI perm to data=" + (intent != null ? intent.getData() : null)
+ " clip=" + (intent != null ? intent.getClipData() : null)
@@ -635,8 +657,9 @@
}
if (android.security.Flags.contentUriPermissionApis()) {
- enforceRequireContentUriPermissionFromCallerOnIntentExtraStream(intent, contentUserHint,
- mode, callingUid, requireContentUriPermissionFromCaller);
+ enforceRequireContentUriPermissionFromCallerOnIntentExtraStreamUnlocked(intent,
+ contentUserHint, mode, callingUid, requireContentUriPermissionFromCaller,
+ requestHashCode);
}
Uri data = intent.getData();
@@ -660,8 +683,9 @@
if (data != null) {
GrantUri grantUri = GrantUri.resolve(contentUserHint, data, mode);
if (android.security.Flags.contentUriPermissionApis()) {
- enforceRequireContentUriPermissionFromCaller(requireContentUriPermissionFromCaller,
- grantUri, callingUid);
+ enforceRequireContentUriPermissionFromCallerUnlocked(
+ requireContentUriPermissionFromCaller, grantUri, callingUid,
+ requestHashCode);
}
targetUid = checkGrantUriPermissionUnlocked(callingUid, targetPkg, grantUri, mode,
targetUid);
@@ -678,8 +702,9 @@
if (uri != null) {
GrantUri grantUri = GrantUri.resolve(contentUserHint, uri, mode);
if (android.security.Flags.contentUriPermissionApis()) {
- enforceRequireContentUriPermissionFromCaller(
- requireContentUriPermissionFromCaller, grantUri, callingUid);
+ enforceRequireContentUriPermissionFromCallerUnlocked(
+ requireContentUriPermissionFromCaller, grantUri, callingUid,
+ requestHashCode);
}
targetUid = checkGrantUriPermissionUnlocked(callingUid, targetPkg,
grantUri, mode, targetUid);
@@ -694,7 +719,7 @@
if (clipIntent != null) {
NeededUriGrants newNeeded = checkGrantUriPermissionFromIntentUnlocked(
callingUid, targetPkg, clipIntent, mode, needed, targetUserId,
- requireContentUriPermissionFromCaller);
+ requireContentUriPermissionFromCaller, requestHashCode);
if (newNeeded != null) {
needed = newNeeded;
}
@@ -706,17 +731,32 @@
return needed;
}
- private void enforceRequireContentUriPermissionFromCaller(
+ private void enforceRequireContentUriPermissionFromCallerUnlocked(
@RequiredContentUriPermission Integer requireContentUriPermissionFromCaller,
- GrantUri grantUri, int uid) {
- // Ignore if requireContentUriPermissionFromCaller hasn't been set or the URI is a
+ GrantUri grantUri, int callingUid, Integer requestHashCode) {
+ // Exit early if requireContentUriPermissionFromCaller hasn't been set or the URI is a
// non-content URI.
if (requireContentUriPermissionFromCaller == null
|| requireContentUriPermissionFromCaller == CONTENT_URI_PERMISSION_NONE
|| !ContentResolver.SCHEME_CONTENT.equals(grantUri.uri.getScheme())) {
+ tryAddingContentUriWithoutCallerReadPermissionWhenAttributeIsNoneUnlocked(
+ requireContentUriPermissionFromCaller, grantUri, callingUid, requestHashCode);
return;
}
+ final boolean hasPermission = hasRequireContentUriPermissionFromCallerUnlocked(
+ requireContentUriPermissionFromCaller, grantUri, callingUid);
+
+ if (!hasPermission) {
+ throw new SecurityException("You can't launch this activity because you don't have the"
+ + " required " + ActivityInfo.requiredContentUriPermissionToShortString(
+ requireContentUriPermissionFromCaller) + " access to " + grantUri.uri);
+ }
+ }
+
+ private boolean hasRequireContentUriPermissionFromCallerUnlocked(
+ @RequiredContentUriPermission Integer requireContentUriPermissionFromCaller,
+ GrantUri grantUri, int uid) {
final boolean readMet = !isRequiredContentUriPermissionRead(
requireContentUriPermissionFromCaller)
|| checkContentUriPermissionFullUnlocked(grantUri, uid,
@@ -727,26 +767,48 @@
|| checkContentUriPermissionFullUnlocked(grantUri, uid,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
- boolean hasPermission =
- requireContentUriPermissionFromCaller == CONTENT_URI_PERMISSION_READ_OR_WRITE
- ? (readMet || writeMet) : (readMet && writeMet);
+ return requireContentUriPermissionFromCaller == CONTENT_URI_PERMISSION_READ_OR_WRITE
+ ? (readMet || writeMet) : (readMet && writeMet);
+ }
- if (!hasPermission) {
- throw new SecurityException("You can't launch this activity because you don't have the"
- + " required " + ActivityInfo.requiredContentUriPermissionToShortString(
- requireContentUriPermissionFromCaller) + " access to " + grantUri.uri);
+ private void tryAddingContentUriWithoutCallerReadPermissionWhenAttributeIsNoneUnlocked(
+ @RequiredContentUriPermission Integer requireContentUriPermissionFromCaller,
+ GrantUri grantUri, int callingUid, Integer requestHashCode) {
+ // We're interested in requireContentUriPermissionFromCaller that is set to
+ // CONTENT_URI_PERMISSION_NONE and content URIs. Hence, ignore if
+ // requireContentUriPermissionFromCaller is not set to CONTENT_URI_PERMISSION_NONE or the
+ // URI is a non-content URI.
+ if (requireContentUriPermissionFromCaller == null
+ || requireContentUriPermissionFromCaller != CONTENT_URI_PERMISSION_NONE
+ || !ContentResolver.SCHEME_CONTENT.equals(grantUri.uri.getScheme())
+ || requestHashCode == null) {
+ return;
+ }
+
+ if (!hasRequireContentUriPermissionFromCallerUnlocked(CONTENT_URI_PERMISSION_READ, grantUri,
+ callingUid)) {
+ synchronized (mLaunchToContentUrisWithoutCallerReadPermission) {
+ if (mLaunchToContentUrisWithoutCallerReadPermission.get(requestHashCode) == null) {
+ mLaunchToContentUrisWithoutCallerReadPermission
+ .put(requestHashCode, new ArraySet<>());
+ }
+ mLaunchToContentUrisWithoutCallerReadPermission.get(requestHashCode)
+ .add(grantUri.uri);
+ }
}
}
- private void enforceRequireContentUriPermissionFromCallerOnIntentExtraStream(Intent intent,
- int contentUserHint, int mode, int callingUid,
- @RequiredContentUriPermission Integer requireContentUriPermissionFromCaller) {
+ private void enforceRequireContentUriPermissionFromCallerOnIntentExtraStreamUnlocked(
+ Intent intent, int contentUserHint, int mode, int callingUid,
+ @RequiredContentUriPermission Integer requireContentUriPermissionFromCaller,
+ Integer requestHashCode) {
try {
final Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri.class);
if (uri != null) {
final GrantUri grantUri = GrantUri.resolve(contentUserHint, uri, mode);
- enforceRequireContentUriPermissionFromCaller(
- requireContentUriPermissionFromCaller, grantUri, callingUid);
+ enforceRequireContentUriPermissionFromCallerUnlocked(
+ requireContentUriPermissionFromCaller, grantUri, callingUid,
+ requestHashCode);
}
} catch (BadParcelableException e) {
Slog.w(TAG, "Failed to unparcel an URI in EXTRA_STREAM, skipping"
@@ -759,8 +821,9 @@
if (uris != null) {
for (int i = uris.size() - 1; i >= 0; i--) {
final GrantUri grantUri = GrantUri.resolve(contentUserHint, uris.get(i), mode);
- enforceRequireContentUriPermissionFromCaller(
- requireContentUriPermissionFromCaller, grantUri, callingUid);
+ enforceRequireContentUriPermissionFromCallerUnlocked(
+ requireContentUriPermissionFromCaller, grantUri, callingUid,
+ requestHashCode);
}
}
} catch (BadParcelableException e) {
@@ -769,6 +832,37 @@
}
}
+ private void notifyActivityLaunchRequestCompletedUnlocked(Integer requestHashCode,
+ boolean isSuccessfulLaunch, String intentAction, int callingUid,
+ String callingActivityName, int calleeUid, String calleeActivityName,
+ boolean isStartActivityForResult) {
+ ArraySet<Uri> contentUris;
+ synchronized (mLaunchToContentUrisWithoutCallerReadPermission) {
+ contentUris = mLaunchToContentUrisWithoutCallerReadPermission.get(requestHashCode);
+ mLaunchToContentUrisWithoutCallerReadPermission.remove(requestHashCode);
+ }
+ if (!isSuccessfulLaunch || contentUris == null) return;
+
+ final String[] authorities = new String[contentUris.size()];
+ final String[] schemes = new String[contentUris.size()];
+ for (int i = contentUris.size() - 1; i >= 0; i--) {
+ Uri uri = contentUris.valueAt(i);
+ authorities[i] = uri.getAuthority();
+ schemes[i] = uri.getScheme();
+ }
+ FrameworkStatsLog.write(CONTENT_OR_FILE_URI_EVENT_REPORTED,
+ CONTENT_OR_FILE_URI_EVENT_REPORTED__EVENT_TYPE__CONTENT_URI_WITHOUT_CALLER_READ_PERMISSION,
+ intentAction,
+ callingUid,
+ callingActivityName,
+ calleeUid,
+ calleeActivityName,
+ isStartActivityForResult,
+ String.join(",", authorities),
+ String.join(",", schemes),
+ /* uri_mime_type */ null);
+ }
+
@GuardedBy("mLock")
private void readGrantedUriPermissionsLocked() {
if (DEBUG) Slog.v(TAG, "readGrantedUriPermissions()");
@@ -1645,23 +1739,36 @@
public NeededUriGrants checkGrantUriPermissionFromIntent(Intent intent, int callingUid,
String targetPkg, int targetUserId) {
return internalCheckGrantUriPermissionFromIntent(intent, callingUid, targetPkg,
- targetUserId, /* requireContentUriPermissionFromCaller */ null);
+ targetUserId, /* requireContentUriPermissionFromCaller */ null,
+ /* requestHashCode */ null);
}
@Override
public NeededUriGrants checkGrantUriPermissionFromIntent(Intent intent, int callingUid,
- String targetPkg, int targetUserId, int requireContentUriPermissionFromCaller) {
+ String targetPkg, int targetUserId, int requireContentUriPermissionFromCaller,
+ int requestHashCode) {
return internalCheckGrantUriPermissionFromIntent(intent, callingUid, targetPkg,
- targetUserId, requireContentUriPermissionFromCaller);
+ targetUserId, requireContentUriPermissionFromCaller, requestHashCode);
+ }
+
+ @Override
+ public void notifyActivityLaunchRequestCompleted(int requestHashCode,
+ boolean isSuccessfulLaunch, String intentAction, int callingUid,
+ String callingActivityName, int calleeUid, String calleeActivityName,
+ boolean isStartActivityForResult) {
+ UriGrantsManagerService.this.notifyActivityLaunchRequestCompletedUnlocked(
+ requestHashCode, isSuccessfulLaunch, intentAction, callingUid,
+ callingActivityName, calleeUid, calleeActivityName,
+ isStartActivityForResult);
}
private NeededUriGrants internalCheckGrantUriPermissionFromIntent(Intent intent,
int callingUid, String targetPkg, int targetUserId,
- @Nullable Integer requireContentUriPermissionFromCaller) {
+ @Nullable Integer requireContentUriPermissionFromCaller, Integer requestHashCode) {
final int mode = (intent != null) ? intent.getFlags() : 0;
return UriGrantsManagerService.this.checkGrantUriPermissionFromIntentUnlocked(
callingUid, targetPkg, intent, mode, null, targetUserId,
- requireContentUriPermissionFromCaller);
+ requireContentUriPermissionFromCaller, requestHashCode);
}
@Override
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index ab4a4d8..4c1e16c 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -128,15 +128,20 @@
* before the release callback.
*/
boolean runVibrationOnVibrationThread(VibrationStepConductor conductor) {
- synchronized (mLock) {
- if (mRequestedActiveConductor != null) {
- Slog.wtf(TAG, "Attempt to start vibration when one already running");
- return false;
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runVibrationOnVibrationThread");
+ try {
+ synchronized (mLock) {
+ if (mRequestedActiveConductor != null) {
+ Slog.wtf(TAG, "Attempt to start vibration when one already running");
+ return false;
+ }
+ mRequestedActiveConductor = conductor;
+ mLock.notifyAll();
}
- mRequestedActiveConductor = conductor;
- mLock.notifyAll();
+ return true;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
- return true;
}
@Override
diff --git a/services/core/java/com/android/server/vibrator/VibratorController.java b/services/core/java/com/android/server/vibrator/VibratorController.java
index 4fc0b74..3c47850 100644
--- a/services/core/java/com/android/server/vibrator/VibratorController.java
+++ b/services/core/java/com/android/server/vibrator/VibratorController.java
@@ -23,6 +23,7 @@
import android.os.Parcel;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.Trace;
import android.os.VibrationEffect;
import android.os.VibratorInfo;
import android.os.vibrator.PrebakedSegment;
@@ -123,21 +124,26 @@
/** Reruns the query to the vibrator to load the {@link VibratorInfo}, if not yet successful. */
public void reloadVibratorInfoIfNeeded() {
- // Early check outside lock, for quick return.
- if (mVibratorInfoLoadSuccessful) {
- return;
- }
- synchronized (mLock) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#reloadVibratorInfoIfNeeded");
+ try {
+ // Early check outside lock, for quick return.
if (mVibratorInfoLoadSuccessful) {
return;
}
- int vibratorId = mVibratorInfo.getId();
- VibratorInfo.Builder vibratorInfoBuilder = new VibratorInfo.Builder(vibratorId);
- mVibratorInfoLoadSuccessful = mNativeWrapper.getInfo(vibratorInfoBuilder);
- mVibratorInfo = vibratorInfoBuilder.build();
- if (!mVibratorInfoLoadSuccessful) {
- Slog.e(TAG, "Failed retry of HAL getInfo for vibrator " + vibratorId);
+ synchronized (mLock) {
+ if (mVibratorInfoLoadSuccessful) {
+ return;
+ }
+ int vibratorId = mVibratorInfo.getId();
+ VibratorInfo.Builder vibratorInfoBuilder = new VibratorInfo.Builder(vibratorId);
+ mVibratorInfoLoadSuccessful = mNativeWrapper.getInfo(vibratorInfoBuilder);
+ mVibratorInfo = vibratorInfoBuilder.build();
+ if (!mVibratorInfoLoadSuccessful) {
+ Slog.e(TAG, "Failed retry of HAL getInfo for vibrator " + vibratorId);
+ }
}
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -193,8 +199,13 @@
/** Return {@code true} if the underlying vibrator is currently available, false otherwise. */
public boolean isAvailable() {
- synchronized (mLock) {
- return mNativeWrapper.isAvailable();
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#isAvailable");
+ try {
+ synchronized (mLock) {
+ return mNativeWrapper.isAvailable();
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -204,12 +215,17 @@
* <p>This will affect the state of {@link #isUnderExternalControl()}.
*/
public void setExternalControl(boolean externalControl) {
- if (!mVibratorInfo.hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
- return;
- }
- synchronized (mLock) {
- mIsUnderExternalControl = externalControl;
- mNativeWrapper.setExternalControl(externalControl);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "setExternalControl(" + externalControl + ")");
+ try {
+ if (!mVibratorInfo.hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
+ return;
+ }
+ synchronized (mLock) {
+ mIsUnderExternalControl = externalControl;
+ mNativeWrapper.setExternalControl(externalControl);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -218,28 +234,38 @@
* if given {@code effect} is {@code null}.
*/
public void updateAlwaysOn(int id, @Nullable PrebakedSegment prebaked) {
- if (!mVibratorInfo.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
- return;
- }
- synchronized (mLock) {
- if (prebaked == null) {
- mNativeWrapper.alwaysOnDisable(id);
- } else {
- mNativeWrapper.alwaysOnEnable(id, prebaked.getEffectId(),
- prebaked.getEffectStrength());
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#updateAlwaysOn");
+ try {
+ if (!mVibratorInfo.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
+ return;
}
+ synchronized (mLock) {
+ if (prebaked == null) {
+ mNativeWrapper.alwaysOnDisable(id);
+ } else {
+ mNativeWrapper.alwaysOnEnable(id, prebaked.getEffectId(),
+ prebaked.getEffectStrength());
+ }
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
/** Set the vibration amplitude. This will NOT affect the state of {@link #isVibrating()}. */
public void setAmplitude(float amplitude) {
- synchronized (mLock) {
- if (mVibratorInfo.hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
- mNativeWrapper.setAmplitude(amplitude);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#setAmplitude");
+ try {
+ synchronized (mLock) {
+ if (mVibratorInfo.hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
+ mNativeWrapper.setAmplitude(amplitude);
+ }
+ if (mIsVibrating) {
+ mCurrentAmplitude = amplitude;
+ }
}
- if (mIsVibrating) {
- mCurrentAmplitude = amplitude;
- }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -253,13 +279,18 @@
* do not support the input or a negative number if the operation failed.
*/
public long on(long milliseconds, long vibrationId) {
- synchronized (mLock) {
- long duration = mNativeWrapper.on(milliseconds, vibrationId);
- if (duration > 0) {
- mCurrentAmplitude = -1;
- notifyListenerOnVibrating(true);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#on");
+ try {
+ synchronized (mLock) {
+ long duration = mNativeWrapper.on(milliseconds, vibrationId);
+ if (duration > 0) {
+ mCurrentAmplitude = -1;
+ notifyListenerOnVibrating(true);
+ }
+ return duration;
}
- return duration;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -273,6 +304,7 @@
* do not support the input or a negative number if the operation failed.
*/
public long on(VibrationEffect.VendorEffect vendorEffect, long vibrationId) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#on (vendor)");
synchronized (mLock) {
Parcel vendorData = Parcel.obtain();
try {
@@ -288,6 +320,7 @@
return duration;
} finally {
vendorData.recycle();
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
}
@@ -302,14 +335,19 @@
* do not support the input or a negative number if the operation failed.
*/
public long on(PrebakedSegment prebaked, long vibrationId) {
- synchronized (mLock) {
- long duration = mNativeWrapper.perform(prebaked.getEffectId(),
- prebaked.getEffectStrength(), vibrationId);
- if (duration > 0) {
- mCurrentAmplitude = -1;
- notifyListenerOnVibrating(true);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#on (Prebaked)");
+ try {
+ synchronized (mLock) {
+ long duration = mNativeWrapper.perform(prebaked.getEffectId(),
+ prebaked.getEffectStrength(), vibrationId);
+ if (duration > 0) {
+ mCurrentAmplitude = -1;
+ notifyListenerOnVibrating(true);
+ }
+ return duration;
}
- return duration;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -323,16 +361,21 @@
* do not support the input or a negative number if the operation failed.
*/
public long on(PrimitiveSegment[] primitives, long vibrationId) {
- if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
- return 0;
- }
- synchronized (mLock) {
- long duration = mNativeWrapper.compose(primitives, vibrationId);
- if (duration > 0) {
- mCurrentAmplitude = -1;
- notifyListenerOnVibrating(true);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#on (Primitive)");
+ try {
+ if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
+ return 0;
}
- return duration;
+ synchronized (mLock) {
+ long duration = mNativeWrapper.compose(primitives, vibrationId);
+ if (duration > 0) {
+ mCurrentAmplitude = -1;
+ notifyListenerOnVibrating(true);
+ }
+ return duration;
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -345,17 +388,22 @@
* @return The duration of the effect playing, or 0 if unsupported.
*/
public long on(RampSegment[] primitives, long vibrationId) {
- if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) {
- return 0;
- }
- synchronized (mLock) {
- int braking = mVibratorInfo.getDefaultBraking();
- long duration = mNativeWrapper.composePwle(primitives, braking, vibrationId);
- if (duration > 0) {
- mCurrentAmplitude = -1;
- notifyListenerOnVibrating(true);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#on (PWLE)");
+ try {
+ if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) {
+ return 0;
}
- return duration;
+ synchronized (mLock) {
+ int braking = mVibratorInfo.getDefaultBraking();
+ long duration = mNativeWrapper.composePwle(primitives, braking, vibrationId);
+ if (duration > 0) {
+ mCurrentAmplitude = -1;
+ notifyListenerOnVibrating(true);
+ }
+ return duration;
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -365,10 +413,15 @@
* <p>This will affect the state of {@link #isVibrating()}.
*/
public void off() {
- synchronized (mLock) {
- mNativeWrapper.off();
- mCurrentAmplitude = 0;
- notifyListenerOnVibrating(false);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorController#off");
+ try {
+ synchronized (mLock) {
+ mNativeWrapper.off();
+ mCurrentAmplitude = 0;
+ notifyListenerOnVibrating(false);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 799934a..899f0b1 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -462,20 +462,31 @@
@Override // Binder call
public void performHapticFeedback(int uid, int deviceId, String opPkg, int constant,
String reason, int flags, int privFlags) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "performHapticFeedback");
// Note that the `performHapticFeedback` method does not take a token argument from the
// caller, and instead, uses this service as the token. This is to mitigate performance
// impact that would otherwise be caused due to marshal latency. Haptic feedback effects are
// short-lived, so we don't need to cancel when the process dies.
- performHapticFeedbackInternal(uid, deviceId, opPkg, constant, reason, /* token= */
- this, flags, privFlags);
+ try {
+ performHapticFeedbackInternal(uid, deviceId, opPkg, constant, reason, /* token= */
+ this, flags, privFlags);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
}
@Override // Binder call
public void performHapticFeedbackForInputDevice(int uid, int deviceId, String opPkg,
int constant, int inputDeviceId, int inputSource, String reason, int flags,
int privFlags) {
- performHapticFeedbackForInputDeviceInternal(uid, deviceId, opPkg, constant, inputDeviceId,
- inputSource, reason, /* token= */ this, flags, privFlags);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "performHapticFeedbackForInputDevice");
+ try {
+ performHapticFeedbackForInputDeviceInternal(uid, deviceId, opPkg, constant,
+ inputDeviceId,
+ inputSource, reason, /* token= */ this, flags, privFlags);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
}
/**
@@ -919,30 +930,25 @@
@GuardedBy("mLock")
@Nullable
private Vibration.EndInfo startVibrationOnThreadLocked(VibrationStepConductor conductor) {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationThreadLocked");
- try {
- HalVibration vib = conductor.getVibration();
- int mode = startAppOpModeLocked(vib.callerInfo);
- switch (mode) {
- case AppOpsManager.MODE_ALLOWED:
- Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
- // Make sure mCurrentVibration is set while triggering the VibrationThread.
- mCurrentVibration = conductor;
- if (!mVibrationThread.runVibrationOnVibrationThread(mCurrentVibration)) {
- // Shouldn't happen. The method call already logs a wtf.
- mCurrentVibration = null; // Aborted.
- return new Vibration.EndInfo(Status.IGNORED_ERROR_SCHEDULING);
- }
- return null;
- case AppOpsManager.MODE_ERRORED:
- Slog.w(TAG, "Start AppOpsManager operation errored for uid "
- + vib.callerInfo.uid);
- return new Vibration.EndInfo(Status.IGNORED_ERROR_APP_OPS);
- default:
- return new Vibration.EndInfo(Status.IGNORED_APP_OPS);
- }
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ HalVibration vib = conductor.getVibration();
+ int mode = startAppOpModeLocked(vib.callerInfo);
+ switch (mode) {
+ case AppOpsManager.MODE_ALLOWED:
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
+ // Make sure mCurrentVibration is set while triggering the VibrationThread.
+ mCurrentVibration = conductor;
+ if (!mVibrationThread.runVibrationOnVibrationThread(mCurrentVibration)) {
+ // Shouldn't happen. The method call already logs a wtf.
+ mCurrentVibration = null; // Aborted.
+ return new Vibration.EndInfo(Status.IGNORED_ERROR_SCHEDULING);
+ }
+ return null;
+ case AppOpsManager.MODE_ERRORED:
+ Slog.w(TAG, "Start AppOpsManager operation errored for uid "
+ + vib.callerInfo.uid);
+ return new Vibration.EndInfo(Status.IGNORED_ERROR_APP_OPS);
+ default:
+ return new Vibration.EndInfo(Status.IGNORED_APP_OPS);
}
}
@@ -1050,21 +1056,16 @@
@GuardedBy("mLock")
private void reportFinishedVibrationLocked(Vibration.EndInfo vibrationEndInfo) {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
- try {
- HalVibration vib = mCurrentVibration.getVibration();
- if (DEBUG) {
- Slog.d(TAG, "Reporting vibration " + vib.id + " finished with "
- + vibrationEndInfo);
- }
- // DO NOT write metrics at this point, wait for the VibrationThread to report the
- // vibration was released, after all cleanup. The metrics will be reported then.
- endVibrationLocked(vib, vibrationEndInfo, /* shouldWriteStats= */ false);
- finishAppOpModeLocked(vib.callerInfo);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ HalVibration vib = mCurrentVibration.getVibration();
+ if (DEBUG) {
+ Slog.d(TAG, "Reporting vibration " + vib.id + " finished with "
+ + vibrationEndInfo);
}
+ // DO NOT write metrics at this point, wait for the VibrationThread to report the
+ // vibration was released, after all cleanup. The metrics will be reported then.
+ endVibrationLocked(vib, vibrationEndInfo, /* shouldWriteStats= */ false);
+ finishAppOpModeLocked(vib.callerInfo);
}
private void onSyncedVibrationComplete(long vibrationId) {
@@ -1418,40 +1419,34 @@
@GuardedBy("mLock")
@Nullable
- private SparseArray<PrebakedSegment> fixupAlwaysOnEffectsLocked(
- CombinedVibration effect) {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "fixupAlwaysOnEffectsLocked");
- try {
- SparseArray<VibrationEffect> effects;
- if (effect instanceof CombinedVibration.Mono) {
- VibrationEffect syncedEffect = ((CombinedVibration.Mono) effect).getEffect();
- effects = transformAllVibratorsLocked(unused -> syncedEffect);
- } else if (effect instanceof CombinedVibration.Stereo) {
- effects = ((CombinedVibration.Stereo) effect).getEffects();
- } else {
- // Only synced combinations can be used for always-on effects.
- return null;
- }
- SparseArray<PrebakedSegment> result = new SparseArray<>();
- for (int i = 0; i < effects.size(); i++) {
- PrebakedSegment prebaked = extractPrebakedSegment(effects.valueAt(i));
- if (prebaked == null) {
- Slog.e(TAG, "Only prebaked effects supported for always-on.");
- return null;
- }
- int vibratorId = effects.keyAt(i);
- VibratorController vibrator = mVibrators.get(vibratorId);
- if (vibrator != null && vibrator.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
- result.put(vibratorId, prebaked);
- }
- }
- if (result.size() == 0) {
- return null;
- }
- return result;
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ private SparseArray<PrebakedSegment> fixupAlwaysOnEffectsLocked(CombinedVibration effect) {
+ SparseArray<VibrationEffect> effects;
+ if (effect instanceof CombinedVibration.Mono) {
+ VibrationEffect syncedEffect = ((CombinedVibration.Mono) effect).getEffect();
+ effects = transformAllVibratorsLocked(unused -> syncedEffect);
+ } else if (effect instanceof CombinedVibration.Stereo) {
+ effects = ((CombinedVibration.Stereo) effect).getEffects();
+ } else {
+ // Only synced combinations can be used for always-on effects.
+ return null;
}
+ SparseArray<PrebakedSegment> result = new SparseArray<>();
+ for (int i = 0; i < effects.size(); i++) {
+ PrebakedSegment prebaked = extractPrebakedSegment(effects.valueAt(i));
+ if (prebaked == null) {
+ Slog.e(TAG, "Only prebaked effects supported for always-on.");
+ return null;
+ }
+ int vibratorId = effects.keyAt(i);
+ VibratorController vibrator = mVibrators.get(vibratorId);
+ if (vibrator != null && vibrator.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
+ result.put(vibratorId, prebaked);
+ }
+ }
+ if (result.size() == 0) {
+ return null;
+ }
+ return result;
}
@Nullable
@@ -1580,25 +1575,42 @@
@Override
public boolean prepareSyncedVibration(long requiredCapabilities, int[] vibratorIds) {
- if ((mCapabilities & requiredCapabilities) != requiredCapabilities) {
- // This sync step requires capabilities this device doesn't have, skipping sync...
- return false;
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "prepareSyncedVibration");
+ try {
+ if ((mCapabilities & requiredCapabilities) != requiredCapabilities) {
+ // This sync step requires capabilities this device doesn't have, skipping
+ // sync...
+ return false;
+ }
+ return mNativeWrapper.prepareSynced(vibratorIds);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
- return mNativeWrapper.prepareSynced(vibratorIds);
}
@Override
public boolean triggerSyncedVibration(long vibrationId) {
- return mNativeWrapper.triggerSynced(vibrationId);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "triggerSyncedVibration");
+ try {
+ return mNativeWrapper.triggerSynced(vibrationId);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
}
@Override
public void cancelSyncedVibration() {
- mNativeWrapper.cancelSynced();
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "cancelSyncedVibration");
+ try {
+ mNativeWrapper.cancelSynced();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
}
@Override
public void noteVibratorOn(int uid, long duration) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "noteVibratorOn");
try {
if (duration <= 0) {
// Tried to turn vibrator ON and got:
@@ -1616,16 +1628,21 @@
mFrameworkStatsLogger.writeVibratorStateOnAsync(uid, duration);
} catch (RemoteException e) {
Slog.e(TAG, "Error logging VibratorStateChanged to ON", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@Override
public void noteVibratorOff(int uid) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "noteVibratorOff");
try {
mBatteryStatsService.noteVibratorOff(uid);
mFrameworkStatsLogger.writeVibratorStateOffAsync(uid);
} catch (RemoteException e) {
Slog.e(TAG, "Error logging VibratorStateChanged to OFF", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -1634,11 +1651,16 @@
if (DEBUG) {
Slog.d(TAG, "Vibration " + vibrationId + " finished with " + vibrationEndInfo);
}
- synchronized (mLock) {
- if (mCurrentVibration != null
- && mCurrentVibration.getVibration().id == vibrationId) {
- reportFinishedVibrationLocked(vibrationEndInfo);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "onVibrationCompleted");
+ try {
+ synchronized (mLock) {
+ if (mCurrentVibration != null
+ && mCurrentVibration.getVibration().id == vibrationId) {
+ reportFinishedVibrationLocked(vibrationEndInfo);
+ }
}
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
@@ -1647,34 +1669,40 @@
if (DEBUG) {
Slog.d(TAG, "VibrationThread released after finished vibration");
}
- synchronized (mLock) {
- if (DEBUG) {
- Slog.d(TAG, "Processing VibrationThread released callback");
- }
- if (Build.IS_DEBUGGABLE && mCurrentVibration != null
- && mCurrentVibration.getVibration().id != vibrationId) {
- Slog.wtf(TAG, TextUtils.formatSimple(
- "VibrationId mismatch on release. expected=%d, released=%d",
- mCurrentVibration.getVibration().id, vibrationId));
- }
- if (mCurrentVibration != null) {
- // This is when we consider the current vibration complete, so report metrics.
- mFrameworkStatsLogger.writeVibrationReportedAsync(
- mCurrentVibration.getVibration().getStatsInfo(
- /* completionUptimeMillis= */ SystemClock.uptimeMillis()));
- mCurrentVibration = null;
- }
- if (mNextVibration != null) {
- VibrationStepConductor nextConductor = mNextVibration;
- mNextVibration = null;
- Vibration.EndInfo vibrationEndInfo = startVibrationOnThreadLocked(
- nextConductor);
- if (vibrationEndInfo != null) {
- // Failed to start the vibration, end it and report metrics right away.
- endVibrationLocked(nextConductor.getVibration(),
- vibrationEndInfo, /* shouldWriteStats= */ true);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "onVibrationThreadReleased: " + vibrationId);
+ try {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slog.d(TAG, "Processing VibrationThread released callback");
+ }
+ if (Build.IS_DEBUGGABLE && mCurrentVibration != null
+ && mCurrentVibration.getVibration().id != vibrationId) {
+ Slog.wtf(TAG, TextUtils.formatSimple(
+ "VibrationId mismatch on release. expected=%d, released=%d",
+ mCurrentVibration.getVibration().id, vibrationId));
+ }
+ if (mCurrentVibration != null) {
+ // This is when we consider the current vibration complete, so report
+ // metrics.
+ mFrameworkStatsLogger.writeVibrationReportedAsync(
+ mCurrentVibration.getVibration().getStatsInfo(
+ /* completionUptimeMillis= */ SystemClock.uptimeMillis()));
+ mCurrentVibration = null;
+ }
+ if (mNextVibration != null) {
+ VibrationStepConductor nextConductor = mNextVibration;
+ mNextVibration = null;
+ Vibration.EndInfo vibrationEndInfo = startVibrationOnThreadLocked(
+ nextConductor);
+ if (vibrationEndInfo != null) {
+ // Failed to start the vibration, end it and report metrics right away.
+ endVibrationLocked(nextConductor.getVibration(),
+ vibrationEndInfo, /* shouldWriteStats= */ true);
+ }
}
}
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
}
@@ -1917,22 +1945,17 @@
@GuardedBy("mLock")
private void endExternalVibrateLocked(Vibration.EndInfo vibrationEndInfo,
boolean continueExternalControl) {
- Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "endExternalVibrateLocked");
- try {
- if (mCurrentExternalVibration == null) {
- return;
- }
- mCurrentExternalVibration.unlinkToDeath();
- if (!continueExternalControl) {
- setExternalControl(false, mCurrentExternalVibration.stats);
- }
- // The external control was turned off, end it and report metrics right away.
- endVibrationLocked(mCurrentExternalVibration, vibrationEndInfo,
- /* shouldWriteStats= */ true);
- mCurrentExternalVibration = null;
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ if (mCurrentExternalVibration == null) {
+ return;
}
+ mCurrentExternalVibration.unlinkToDeath();
+ if (!continueExternalControl) {
+ setExternalControl(false, mCurrentExternalVibration.stats);
+ }
+ // The external control was turned off, end it and report metrics right away.
+ endVibrationLocked(mCurrentExternalVibration, vibrationEndInfo,
+ /* shouldWriteStats= */ true);
+ mCurrentExternalVibration = null;
}
private HapticFeedbackVibrationProvider getHapticVibrationProvider() {
@@ -1987,143 +2010,160 @@
@Override
public ExternalVibrationScale onExternalVibrationStart(ExternalVibration vib) {
- // Create Vibration.Stats as close to the received request as possible, for tracking.
- ExternalVibrationSession externalVibration = new ExternalVibrationSession(vib);
- // Mute the request until we run all the checks and accept the vibration.
- externalVibration.muteScale();
- boolean alreadyUnderExternalControl = false;
- boolean waitForCompletion = false;
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "onExternalVibrationStart");
+ try {
+ // Create Vibration.Stats as close to the received request as possible, for
+ // tracking.
+ ExternalVibrationSession externalVibration = new ExternalVibrationSession(vib);
+ // Mute the request until we run all the checks and accept the vibration.
+ externalVibration.muteScale();
+ boolean alreadyUnderExternalControl = false;
+ boolean waitForCompletion = false;
- synchronized (mLock) {
- if (!hasExternalControlCapability()) {
- endVibrationLocked(externalVibration,
- new Vibration.EndInfo(Status.IGNORED_UNSUPPORTED),
- /* shouldWriteStats= */ true);
- return externalVibration.getScale();
- }
+ synchronized (mLock) {
+ if (!hasExternalControlCapability()) {
+ endVibrationLocked(externalVibration,
+ new Vibration.EndInfo(Status.IGNORED_UNSUPPORTED),
+ /* shouldWriteStats= */ true);
+ return externalVibration.getScale();
+ }
- if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE,
- vib.getUid(), -1 /*owningUid*/, true /*exported*/)
- != PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "pkg=" + vib.getPackage() + ", uid=" + vib.getUid()
- + " tried to play externally controlled vibration"
- + " without VIBRATE permission, ignoring.");
- endVibrationLocked(externalVibration,
- new Vibration.EndInfo(Status.IGNORED_MISSING_PERMISSION),
- /* shouldWriteStats= */ true);
- return externalVibration.getScale();
- }
+ if (ActivityManager.checkComponentPermission(
+ android.Manifest.permission.VIBRATE,
+ vib.getUid(), -1 /*owningUid*/, true /*exported*/)
+ != PackageManager.PERMISSION_GRANTED) {
+ Slog.w(TAG, "pkg=" + vib.getPackage() + ", uid=" + vib.getUid()
+ + " tried to play externally controlled vibration"
+ + " without VIBRATE permission, ignoring.");
+ endVibrationLocked(externalVibration,
+ new Vibration.EndInfo(Status.IGNORED_MISSING_PERMISSION),
+ /* shouldWriteStats= */ true);
+ return externalVibration.getScale();
+ }
- Vibration.EndInfo vibrationEndInfo = shouldIgnoreVibrationLocked(
- externalVibration.callerInfo);
+ Vibration.EndInfo vibrationEndInfo = shouldIgnoreVibrationLocked(
+ externalVibration.callerInfo);
- if (vibrationEndInfo == null
- && mCurrentExternalVibration != null
- && mCurrentExternalVibration.isHoldingSameVibration(vib)) {
- // We are already playing this external vibration, so we can return the same
- // scale calculated in the previous call to this method.
- return mCurrentExternalVibration.getScale();
- }
+ if (vibrationEndInfo == null
+ && mCurrentExternalVibration != null
+ && mCurrentExternalVibration.isHoldingSameVibration(vib)) {
+ // We are already playing this external vibration, so we can return the same
+ // scale calculated in the previous call to this method.
+ return mCurrentExternalVibration.getScale();
+ }
- if (vibrationEndInfo == null) {
- // Check if ongoing vibration is more important than this vibration.
- vibrationEndInfo = shouldIgnoreVibrationForOngoingLocked(externalVibration);
- }
+ if (vibrationEndInfo == null) {
+ // Check if ongoing vibration is more important than this vibration.
+ vibrationEndInfo = shouldIgnoreVibrationForOngoingLocked(externalVibration);
+ }
- if (vibrationEndInfo != null) {
- endVibrationLocked(externalVibration, vibrationEndInfo,
- /* shouldWriteStats= */ true);
- return externalVibration.getScale();
- }
+ if (vibrationEndInfo != null) {
+ endVibrationLocked(externalVibration, vibrationEndInfo,
+ /* shouldWriteStats= */ true);
+ return externalVibration.getScale();
+ }
- if (mCurrentExternalVibration == null) {
- // If we're not under external control right now, then cancel any normal
- // vibration that may be playing and ready the vibrator for external control.
- if (mCurrentVibration != null) {
+ if (mCurrentExternalVibration == null) {
+ // If we're not under external control right now, then cancel any normal
+ // vibration that may be playing and ready the vibrator for external
+ // control.
+ if (mCurrentVibration != null) {
+ externalVibration.stats.reportInterruptedAnotherVibration(
+ mCurrentVibration.getVibration().callerInfo);
+ clearNextVibrationLocked(
+ new Vibration.EndInfo(Status.IGNORED_FOR_EXTERNAL,
+ externalVibration.callerInfo));
+ mCurrentVibration.notifyCancelled(
+ new Vibration.EndInfo(Status.CANCELLED_SUPERSEDED,
+ externalVibration.callerInfo),
+ /* immediate= */ true);
+ waitForCompletion = true;
+ }
+ } else {
+ // At this point we have an externally controlled vibration playing already.
+ // Since the interface defines that only one externally controlled
+ // vibration can
+ // play at a time, we need to first mute the ongoing vibration and then
+ // return
+ // a scale from this function for the new one, so we can be assured that the
+ // ongoing will be muted in favor of the new vibration.
+ //
+ // Note that this doesn't support multiple concurrent external controls,
+ // as we would need to mute the old one still if it came from a different
+ // controller.
+ alreadyUnderExternalControl = true;
+ mCurrentExternalVibration.notifyEnded();
externalVibration.stats.reportInterruptedAnotherVibration(
- mCurrentVibration.getVibration().callerInfo);
- clearNextVibrationLocked(
- new Vibration.EndInfo(Status.IGNORED_FOR_EXTERNAL,
- externalVibration.callerInfo));
- mCurrentVibration.notifyCancelled(
+ mCurrentExternalVibration.callerInfo);
+ endExternalVibrateLocked(
new Vibration.EndInfo(Status.CANCELLED_SUPERSEDED,
externalVibration.callerInfo),
- /* immediate= */ true);
- waitForCompletion = true;
+ /* continueExternalControl= */ true);
}
- } else {
- // At this point we have an externally controlled vibration playing already.
- // Since the interface defines that only one externally controlled vibration can
- // play at a time, we need to first mute the ongoing vibration and then return
- // a scale from this function for the new one, so we can be assured that the
- // ongoing will be muted in favor of the new vibration.
- //
- // Note that this doesn't support multiple concurrent external controls, as we
- // would need to mute the old one still if it came from a different controller.
- alreadyUnderExternalControl = true;
- mCurrentExternalVibration.notifyEnded();
- externalVibration.stats.reportInterruptedAnotherVibration(
- mCurrentExternalVibration.callerInfo);
- endExternalVibrateLocked(
- new Vibration.EndInfo(Status.CANCELLED_SUPERSEDED,
- externalVibration.callerInfo),
- /* continueExternalControl= */ true);
- }
- VibrationAttributes attrs = fixupVibrationAttributes(vib.getVibrationAttributes(),
- /* effect= */ null);
- if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
- // Force update of user settings before checking if this vibration effect should
- // be ignored or scaled.
- mVibrationSettings.update();
- }
-
- mCurrentExternalVibration = externalVibration;
- externalVibration.linkToDeath(this::onExternalVibrationBinderDied);
- externalVibration.scale(mVibrationScaler, attrs.getUsage());
- }
-
- if (waitForCompletion) {
- if (!mVibrationThread.waitForThreadIdle(VIBRATION_CANCEL_WAIT_MILLIS)) {
- Slog.e(TAG, "Timed out waiting for vibration to cancel");
- synchronized (mLock) {
- // Trigger endExternalVibrateLocked to unlink to death recipient.
- endExternalVibrateLocked(
- new Vibration.EndInfo(Status.IGNORED_ERROR_CANCELLING),
- /* continueExternalControl= */ false);
- // Mute the request, vibration will be ignored.
- externalVibration.muteScale();
+ VibrationAttributes attrs = fixupVibrationAttributes(
+ vib.getVibrationAttributes(),
+ /* effect= */ null);
+ if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
+ // Force update of user settings before checking if this vibration effect
+ // should be ignored or scaled.
+ mVibrationSettings.update();
}
- return externalVibration.getScale();
+
+ mCurrentExternalVibration = externalVibration;
+ externalVibration.linkToDeath(this::onExternalVibrationBinderDied);
+ externalVibration.scale(mVibrationScaler, attrs.getUsage());
}
- }
- if (!alreadyUnderExternalControl) {
+
+ if (waitForCompletion) {
+ if (!mVibrationThread.waitForThreadIdle(VIBRATION_CANCEL_WAIT_MILLIS)) {
+ Slog.e(TAG, "Timed out waiting for vibration to cancel");
+ synchronized (mLock) {
+ // Trigger endExternalVibrateLocked to unlink to death recipient.
+ endExternalVibrateLocked(
+ new Vibration.EndInfo(Status.IGNORED_ERROR_CANCELLING),
+ /* continueExternalControl= */ false);
+ // Mute the request, vibration will be ignored.
+ externalVibration.muteScale();
+ }
+ return externalVibration.getScale();
+ }
+ }
+ if (!alreadyUnderExternalControl) {
+ if (DEBUG) {
+ Slog.d(TAG, "Vibrator going under external control.");
+ }
+ setExternalControl(true, externalVibration.stats);
+ }
if (DEBUG) {
- Slog.d(TAG, "Vibrator going under external control.");
+ Slog.d(TAG, "Playing external vibration: " + vib);
}
- setExternalControl(true, externalVibration.stats);
+ // Vibrator will start receiving data from external channels after this point.
+ // Report current time as the vibration start time, for debugging.
+ externalVibration.stats.reportStarted();
+ return externalVibration.getScale();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
- if (DEBUG) {
- Slog.d(TAG, "Playing external vibration: " + vib);
- }
- // Vibrator will start receiving data from external channels after this point.
- // Report current time as the vibration start time, for debugging.
- externalVibration.stats.reportStarted();
- return externalVibration.getScale();
}
@Override
public void onExternalVibrationStop(ExternalVibration vib) {
- synchronized (mLock) {
- if (mCurrentExternalVibration != null
- && mCurrentExternalVibration.isHoldingSameVibration(vib)) {
- if (DEBUG) {
- Slog.d(TAG, "Stopping external vibration: " + vib);
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "onExternalVibrationStop");
+ try {
+ synchronized (mLock) {
+ if (mCurrentExternalVibration != null
+ && mCurrentExternalVibration.isHoldingSameVibration(vib)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Stopping external vibration: " + vib);
+ }
+ endExternalVibrateLocked(
+ new Vibration.EndInfo(Status.FINISHED),
+ /* continueExternalControl= */ false);
}
- endExternalVibrateLocked(
- new Vibration.EndInfo(Status.FINISHED),
- /* continueExternalControl= */ false);
}
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 1822a80..bc11bac 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -603,7 +603,8 @@
.checkGrantUriPermissionFromIntent(intent, resolvedCallingUid,
activityInfo.applicationInfo.packageName,
UserHandle.getUserId(activityInfo.applicationInfo.uid),
- activityInfo.requireContentUriPermissionFromCaller);
+ activityInfo.requireContentUriPermissionFromCaller,
+ /* requestHashCode */ this.hashCode());
} else {
intentGrants = supervisor.mService.mUgmInternal
.checkGrantUriPermissionFromIntent(intent, resolvedCallingUid,
@@ -717,6 +718,9 @@
* @return The starter result.
*/
int execute() {
+ // Required for logging ContentOrFileUriEventReported in the finally block.
+ String callerActivityName = null;
+ ActivityRecord launchingRecord = null;
try {
onExecutionStarted();
@@ -737,6 +741,7 @@
? Binder.getCallingUid() : mRequest.realCallingUid;
launchingState = mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(
mRequest.intent, caller, callingUid);
+ callerActivityName = caller != null ? caller.info.name : null;
}
if (mRequest.intent != null) {
@@ -812,7 +817,7 @@
final ActivityOptions originalOptions = mRequest.activityOptions != null
? mRequest.activityOptions.getOriginalOptions() : null;
// Only track the launch time of activity that will be resumed.
- final ActivityRecord launchingRecord = mDoResume ? mLastStartActivityRecord : null;
+ launchingRecord = mDoResume ? mLastStartActivityRecord : null;
// If the new record is the one that started, a new activity has created.
final boolean newActivityCreated = mStartActivity == launchingRecord;
// Notify ActivityMetricsLogger that the activity has launched.
@@ -828,6 +833,23 @@
return getExternalResult(res);
}
} finally {
+ // Notify UriGrantsManagerService that activity launch completed. Required for logging
+ // the ContentOrFileUriEventReported message.
+ mSupervisor.mService.mUgmInternal.notifyActivityLaunchRequestCompleted(
+ mRequest.hashCode(),
+ // isSuccessfulLaunch
+ launchingRecord != null,
+ // Intent action
+ mRequest.intent != null ? mRequest.intent.getAction() : null,
+ mRequest.realCallingUid,
+ callerActivityName,
+ // Callee UID
+ mRequest.activityInfo != null
+ ? mRequest.activityInfo.applicationInfo.uid : INVALID_UID,
+ // Callee Activity name
+ mRequest.activityInfo != null ? mRequest.activityInfo.name : null,
+ // isStartActivityForResult
+ launchingRecord != null && launchingRecord.resultTo != null);
onExecutionComplete();
}
}
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_2/background/cpus b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_2/background/cpus
new file mode 100644
index 0000000..8b0fab8
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_2/background/cpus
@@ -0,0 +1 @@
+0-1
diff --git a/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_2/top-app/cpus b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_2/top-app/cpus
new file mode 100644
index 0000000..40c7bb2
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/CpuInfoReaderTest/valid_cpuset_2/top-app/cpus
@@ -0,0 +1 @@
+0-3
diff --git a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java
index 2fbe8aa..3fe038a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.content.res.AssetManager;
+import android.util.IntArray;
import android.util.Log;
import android.util.SparseArray;
@@ -48,6 +49,7 @@
private static final String TAG = CpuInfoReaderTest.class.getSimpleName();
private static final String ROOT_DIR_NAME = "CpuInfoReaderTest";
private static final String VALID_CPUSET_DIR = "valid_cpuset";
+ private static final String VALID_CPUSET_2_DIR = "valid_cpuset_2";
private static final String VALID_CPUSET_WITH_EMPTY_CPUS = "valid_cpuset_with_empty_cpus";
private static final String VALID_CPUFREQ_WITH_EMPTY_AFFECTED_CPUS =
"valid_cpufreq_with_empty_affected_cpus";
@@ -88,54 +90,95 @@
}
@Test
+ public void testReadCpuInfoWithUpdatedCpuset() throws Exception {
+ CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
+ getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(VALID_PROC_STAT));
+
+ SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos();
+ SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos =
+ getFirstCpuInfosWithTimeInStateSnapshot();
+
+ compareCpuInfos("CPU infos first snapshot", expectedCpuInfos, actualCpuInfos);
+
+ cpuInfoReader.setCpusetDir(getCacheFile(VALID_CPUSET_2_DIR));
+ cpuInfoReader.setCpuFreqDir(getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_2_DIR));
+ cpuInfoReader.setProcStatFile(getCacheFile(VALID_PROC_STAT_2));
+
+ actualCpuInfos = cpuInfoReader.readCpuInfos();
+
+ IntArray cpusetCategories = new IntArray();
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP);
+ expectedCpuInfos = getSecondCpuInfosWithTimeInStateSnapshot(cpusetCategories);
+
+ compareCpuInfos("CPU infos second snapshot", expectedCpuInfos, actualCpuInfos);
+ }
+
+ @Test
+ public void testReadCpuInfoWithUpdatedCpusetBeforeStopSignal() throws Exception {
+ CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
+ getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(VALID_PROC_STAT));
+
+ SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos();
+ SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos =
+ getFirstCpuInfosWithTimeInStateSnapshot();
+
+ compareCpuInfos("CPU infos first snapshot", expectedCpuInfos, actualCpuInfos);
+
+ cpuInfoReader.setCpusetDir(getCacheFile(VALID_CPUSET_2_DIR));
+ // When stopping the periodic cpuset reading, the reader will create a new snapshot.
+ cpuInfoReader.stopPeriodicCpusetReading();
+ // Any cpuset update after the stop signal should be ignored by the reader.
+ cpuInfoReader.setCpusetDir(getCacheFile(VALID_CPUSET_DIR));
+ cpuInfoReader.setCpuFreqDir(getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_2_DIR));
+ cpuInfoReader.setProcStatFile(getCacheFile(VALID_PROC_STAT_2));
+
+ actualCpuInfos = cpuInfoReader.readCpuInfos();
+
+ IntArray cpusetCategories = new IntArray();
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP);
+ expectedCpuInfos = getSecondCpuInfosWithTimeInStateSnapshot(cpusetCategories);
+
+ compareCpuInfos("CPU infos second snapshot", expectedCpuInfos, actualCpuInfos);
+ }
+
+
+ @Test
+ public void testReadCpuInfoWithUpdatedCpusetAfterStopSignal() throws Exception {
+ CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
+ getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(VALID_PROC_STAT));
+
+ SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos();
+ SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos =
+ getFirstCpuInfosWithTimeInStateSnapshot();
+
+ compareCpuInfos("CPU infos first snapshot", expectedCpuInfos, actualCpuInfos);
+
+ cpuInfoReader.stopPeriodicCpusetReading();
+ // Any cpuset update after the stop signal should be ignored by the reader.
+ cpuInfoReader.setCpusetDir(getCacheFile(VALID_CPUSET_2_DIR));
+ cpuInfoReader.setCpuFreqDir(getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_2_DIR));
+ cpuInfoReader.setProcStatFile(getCacheFile(VALID_PROC_STAT_2));
+
+ actualCpuInfos = cpuInfoReader.readCpuInfos();
+
+ expectedCpuInfos = getSecondCpuInfosWithTimeInStateSnapshot();
+ compareCpuInfos("CPU infos second snapshot", expectedCpuInfos, actualCpuInfos);
+ }
+
+ @Test
public void testReadCpuInfoWithTimeInState() throws Exception {
CpuInfoReader cpuInfoReader = newCpuInfoReader(getCacheFile(VALID_CPUSET_DIR),
getCacheFile(VALID_CPUFREQ_WITH_TIME_IN_STATE_DIR), getCacheFile(VALID_PROC_STAT));
SparseArray<CpuInfoReader.CpuInfo> actualCpuInfos = cpuInfoReader.readCpuInfos();
- SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos = new SparseArray<>();
- expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0,
- FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_230_000,
- /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ 488_095,
- /* normalizedAvailableCpuFreqKHz= */ 2_402_267,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610,
- /* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050,
- /* idleTimeMillis= */ 409_036_950, /* iowaitTimeMillis= */ 1_322_810,
- /* irqTimeMillis= */ 8_146_740, /* softirqTimeMillis= */ 428_970,
- /* stealTimeMillis= */ 81_950, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
- expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1,
- FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000,
- /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 502_380,
- /* normalizedAvailableCpuFreqKHz= */ 2_693_525,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280,
- /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020,
- /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960,
- /* irqTimeMillis= */ 14_786_940, /* softirqTimeMillis= */ 1_498_130,
- /* stealTimeMillis= */ 78_780, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
- expectedCpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
- FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
- /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
- /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285,
- /* normalizedAvailableCpuFreqKHz= */ 1_901_608,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_959_280,
- /* niceTimeMillis= */ 7_789_450, /* systemTimeMillis= */ 54_014_020,
- /* idleTimeMillis= */ 402_717_120, /* iowaitTimeMillis= */ 1_166_960,
- /* irqTimeMillis= */ 14_796_940, /* softirqTimeMillis= */ 1_478_130,
- /* stealTimeMillis= */ 88_780, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
- expectedCpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
- FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
- /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
- /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285,
- /* normalizedAvailableCpuFreqKHz= */ 1_907_125,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_349_610,
- /* niceTimeMillis= */ 7_850_930, /* systemTimeMillis= */ 52_127_050,
- /* idleTimeMillis= */ 409_136_950, /* iowaitTimeMillis= */ 1_332_810,
- /* irqTimeMillis= */ 8_136_740, /* softirqTimeMillis= */ 438_970,
- /* stealTimeMillis= */ 71_950, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
+ SparseArray<CpuInfoReader.CpuInfo> expectedCpuInfos =
+ getFirstCpuInfosWithTimeInStateSnapshot();
compareCpuInfos("CPU infos first snapshot", expectedCpuInfos, actualCpuInfos);
@@ -144,49 +187,7 @@
actualCpuInfos = cpuInfoReader.readCpuInfos();
- expectedCpuInfos.clear();
- expectedCpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0,
- FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
- /* maxCpuFreqKHz= */ 2_600_000, /* avgTimeInStateCpuFreqKHz= */ 419_354,
- /* normalizedAvailableCpuFreqKHz= */ 2_525_919,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
- /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
- /* idleTimeMillis= */ 110_000_000, /* iowaitTimeMillis= */ 1_100_000,
- /* irqTimeMillis= */ 1_400_000, /* softirqTimeMillis= */ 80_000,
- /* stealTimeMillis= */ 21_000, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
- expectedCpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1,
- FLAG_CPUSET_CATEGORY_TOP_APP, /* isOnline= */ true, /* curCpuFreqKHz= */ 2_800_000,
- /* maxCpuFreqKHz= */ 2_900_000, /* avgTimeInStateCpuFreqKHz= */ 429_032,
- /* normalizedAvailableCpuFreqKHz= */ 2_503_009,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 900_000,
- /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
- /* idleTimeMillis= */ 1_000_000, /* iowaitTimeMillis= */ 90_000,
- /* irqTimeMillis= */ 200_000, /* softirqTimeMillis= */ 100_000,
- /* stealTimeMillis= */ 100_000, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
- expectedCpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
- FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
- /* isOnline= */ true, /* curCpuFreqKHz= */ 2_000_000,
- /* maxCpuFreqKHz= */ 2_100_000, /* avgTimeInStateCpuFreqKHz= */ 403_225,
- /* normalizedAvailableCpuFreqKHz= */ 1_788_209,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
- /* niceTimeMillis= */ 2_000_000, /* systemTimeMillis= */ 0,
- /* idleTimeMillis= */ 10_000_000, /* iowaitTimeMillis= */ 1_000_000,
- /* irqTimeMillis= */ 20_000_000, /* softirqTimeMillis= */ 1_000_000,
- /* stealTimeMillis= */ 100_000, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
- expectedCpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
- FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
- /* isOnline= */ false, /* curCpuFreqKHz= */ MISSING_FREQUENCY,
- /* maxCpuFreqKHz= */ 2_100_000, /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY,
- /* normalizedAvailableCpuFreqKHz= */ MISSING_FREQUENCY,
- new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 2_000_000,
- /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 1_000_000,
- /* idleTimeMillis= */ 100_000, /* iowaitTimeMillis= */ 100_000,
- /* irqTimeMillis= */ 100_000, /* softirqTimeMillis= */ 1_000_000,
- /* stealTimeMillis= */ 1_000, /* guestTimeMillis= */ 0,
- /* guestNiceTimeMillis= */ 0)));
+ expectedCpuInfos = getSecondCpuInfosWithTimeInStateSnapshot();
compareCpuInfos("CPU infos second snapshot", expectedCpuInfos, actualCpuInfos);
}
@@ -592,4 +593,108 @@
}
return rootDir.delete();
}
+
+ private SparseArray<CpuInfoReader.CpuInfo> getFirstCpuInfosWithTimeInStateSnapshot() {
+ SparseArray<CpuInfoReader.CpuInfo> cpuInfos = new SparseArray<>();
+ cpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, FLAG_CPUSET_CATEGORY_TOP_APP,
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 1_230_000,
+ /* maxCpuFreqKHz= */ 2_500_000, /* avgTimeInStateCpuFreqKHz= */ 488_095,
+ /* normalizedAvailableCpuFreqKHz= */ 2_402_267,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_249_610,
+ /* niceTimeMillis= */ 7_950_930, /* systemTimeMillis= */ 52_227_050,
+ /* idleTimeMillis= */ 409_036_950, /* iowaitTimeMillis= */ 1_322_810,
+ /* irqTimeMillis= */ 8_146_740, /* softirqTimeMillis= */ 428_970,
+ /* stealTimeMillis= */ 81_950, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ cpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, FLAG_CPUSET_CATEGORY_TOP_APP,
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 1_450_000,
+ /* maxCpuFreqKHz= */ 2_800_000, /* avgTimeInStateCpuFreqKHz= */ 502_380,
+ /* normalizedAvailableCpuFreqKHz= */ 2_693_525,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_949_280,
+ /* niceTimeMillis= */ 7_799_450, /* systemTimeMillis= */ 54_004_020,
+ /* idleTimeMillis= */ 402_707_120, /* iowaitTimeMillis= */ 1_186_960,
+ /* irqTimeMillis= */ 14_786_940, /* softirqTimeMillis= */ 1_498_130,
+ /* stealTimeMillis= */ 78_780, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ cpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2,
+ FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
+ /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285,
+ /* normalizedAvailableCpuFreqKHz= */ 1_901_608,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 28_959_280,
+ /* niceTimeMillis= */ 7_789_450, /* systemTimeMillis= */ 54_014_020,
+ /* idleTimeMillis= */ 402_717_120, /* iowaitTimeMillis= */ 1_166_960,
+ /* irqTimeMillis= */ 14_796_940, /* softirqTimeMillis= */ 1_478_130,
+ /* stealTimeMillis= */ 88_780, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ cpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3,
+ FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND,
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
+ /* maxCpuFreqKHz= */ 2_000_000, /* avgTimeInStateCpuFreqKHz= */ 464_285,
+ /* normalizedAvailableCpuFreqKHz= */ 1_907_125,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 32_349_610,
+ /* niceTimeMillis= */ 7_850_930, /* systemTimeMillis= */ 52_127_050,
+ /* idleTimeMillis= */ 409_136_950, /* iowaitTimeMillis= */ 1_332_810,
+ /* irqTimeMillis= */ 8_136_740, /* softirqTimeMillis= */ 438_970,
+ /* stealTimeMillis= */ 71_950, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ return cpuInfos;
+ }
+
+ private SparseArray<CpuInfoReader.CpuInfo> getSecondCpuInfosWithTimeInStateSnapshot() {
+ IntArray cpusetCategories = new IntArray();
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND);
+ cpusetCategories.add(FLAG_CPUSET_CATEGORY_TOP_APP | FLAG_CPUSET_CATEGORY_BACKGROUND);
+ return getSecondCpuInfosWithTimeInStateSnapshot(cpusetCategories);
+ }
+
+ private SparseArray<CpuInfoReader.CpuInfo> getSecondCpuInfosWithTimeInStateSnapshot(
+ IntArray cpusetCategories) {
+ SparseArray<CpuInfoReader.CpuInfo> cpuInfos = new SparseArray<>();
+ cpuInfos.append(0, new CpuInfoReader.CpuInfo(/* cpuCore= */ 0, cpusetCategories.get(0),
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 1_000_000,
+ /* maxCpuFreqKHz= */ 2_600_000, /* avgTimeInStateCpuFreqKHz= */ 419_354,
+ /* normalizedAvailableCpuFreqKHz= */ 2_525_919,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
+ /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
+ /* idleTimeMillis= */ 110_000_000, /* iowaitTimeMillis= */ 1_100_000,
+ /* irqTimeMillis= */ 1_400_000, /* softirqTimeMillis= */ 80_000,
+ /* stealTimeMillis= */ 21_000, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ cpuInfos.append(1, new CpuInfoReader.CpuInfo(/* cpuCore= */ 1, cpusetCategories.get(1),
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 2_800_000,
+ /* maxCpuFreqKHz= */ 2_900_000, /* avgTimeInStateCpuFreqKHz= */ 429_032,
+ /* normalizedAvailableCpuFreqKHz= */ 2_503_009,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 900_000,
+ /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 10_000_000,
+ /* idleTimeMillis= */ 1_000_000, /* iowaitTimeMillis= */ 90_000,
+ /* irqTimeMillis= */ 200_000, /* softirqTimeMillis= */ 100_000,
+ /* stealTimeMillis= */ 100_000, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ cpuInfos.append(2, new CpuInfoReader.CpuInfo(/* cpuCore= */ 2, cpusetCategories.get(2),
+ /* isOnline= */ true, /* curCpuFreqKHz= */ 2_000_000,
+ /* maxCpuFreqKHz= */ 2_100_000, /* avgTimeInStateCpuFreqKHz= */ 403_225,
+ /* normalizedAvailableCpuFreqKHz= */ 1_788_209,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 10_000_000,
+ /* niceTimeMillis= */ 2_000_000, /* systemTimeMillis= */ 0,
+ /* idleTimeMillis= */ 10_000_000, /* iowaitTimeMillis= */ 1_000_000,
+ /* irqTimeMillis= */ 20_000_000, /* softirqTimeMillis= */ 1_000_000,
+ /* stealTimeMillis= */ 100_000, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ cpuInfos.append(3, new CpuInfoReader.CpuInfo(/* cpuCore= */ 3, cpusetCategories.get(3),
+ /* isOnline= */ false,
+ /* curCpuFreqKHz= */ MISSING_FREQUENCY, /* maxCpuFreqKHz= */ 2_100_000,
+ /* avgTimeInStateCpuFreqKHz= */ MISSING_FREQUENCY,
+ /* normalizedAvailableCpuFreqKHz= */ MISSING_FREQUENCY,
+ new CpuInfoReader.CpuUsageStats(/* userTimeMillis= */ 2_000_000,
+ /* niceTimeMillis= */ 1_000_000, /* systemTimeMillis= */ 1_000_000,
+ /* idleTimeMillis= */ 100_000, /* iowaitTimeMillis= */ 100_000,
+ /* irqTimeMillis= */ 100_000, /* softirqTimeMillis= */ 1_000_000,
+ /* stealTimeMillis= */ 1_000, /* guestTimeMillis= */ 0,
+ /* guestNiceTimeMillis= */ 0)));
+ return cpuInfos;
+ }
+
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuMonitorServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuMonitorServiceTest.java
index 994313f..d9e09d8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuMonitorServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuMonitorServiceTest.java
@@ -26,6 +26,7 @@
import static com.android.server.cpu.CpuInfoReader.FLAG_CPUSET_CATEGORY_BACKGROUND;
import static com.android.server.cpu.CpuInfoReader.FLAG_CPUSET_CATEGORY_TOP_APP;
import static com.android.server.cpu.CpuMonitorService.DEFAULT_MONITORING_INTERVAL_MILLISECONDS;
+import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -75,6 +76,7 @@
private static final long TEST_NORMAL_MONITORING_INTERVAL_MILLISECONDS = 100;
private static final long TEST_DEBUG_MONITORING_INTERVAL_MILLISECONDS = 150;
private static final long TEST_LATEST_AVAILABILITY_DURATION_MILLISECONDS = 300;
+ private static final long TEST_STOP_PERIODIC_CPUSET_READING_DELAY_MILLISECONDS = 0;
private static final CpuAvailabilityMonitoringConfig TEST_MONITORING_CONFIG_ALL_CPUSET =
new CpuAvailabilityMonitoringConfig.Builder(CPUSET_ALL)
.addThreshold(30).addThreshold(70).build();
@@ -119,7 +121,8 @@
mService = new CpuMonitorService(mMockContext, mMockCpuInfoReader, mServiceHandlerThread,
/* shouldDebugMonitor= */ true, TEST_NORMAL_MONITORING_INTERVAL_MILLISECONDS,
TEST_DEBUG_MONITORING_INTERVAL_MILLISECONDS,
- TEST_LATEST_AVAILABILITY_DURATION_MILLISECONDS);
+ TEST_LATEST_AVAILABILITY_DURATION_MILLISECONDS,
+ TEST_STOP_PERIODIC_CPUSET_READING_DELAY_MILLISECONDS);
doNothing().when(() -> ServiceManager.addService(eq("cpu_monitor"), any(Binder.class),
anyBoolean(), anyInt()));
@@ -535,6 +538,18 @@
}
@Test
+ public void testBootCompleted() throws Exception {
+ mService.onBootPhase(PHASE_BOOT_COMPLETED);
+
+ // Message to stop periodic cpuset reading is posted on the service handler thread. Sync
+ // with this thread before proceeding.
+ syncWithHandler(mServiceHandler, /* delayMillis= */ 0);
+
+ verify(mMockCpuInfoReader, timeout(ASYNC_CALLBACK_WAIT_TIMEOUT_MILLISECONDS))
+ .stopPeriodicCpusetReading();
+ }
+
+ @Test
public void testHeavyCpuLoadMonitoring() throws Exception {
// TODO(b/267500110): Once heavy CPU load detection logic is added, add unittest.
}
@@ -567,7 +582,8 @@
mServiceHandlerThread, /* shouldDebugMonitor= */ false,
TEST_NORMAL_MONITORING_INTERVAL_MILLISECONDS,
TEST_DEBUG_MONITORING_INTERVAL_MILLISECONDS,
- TEST_LATEST_AVAILABILITY_DURATION_MILLISECONDS);
+ TEST_LATEST_AVAILABILITY_DURATION_MILLISECONDS,
+ TEST_STOP_PERIODIC_CPUSET_READING_DELAY_MILLISECONDS);
startService();
}