Merge "Write ViewCapture data to WmTrace when WindowManager dumps." into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
7bcd1038f6
@@ -38,6 +38,7 @@ import android.graphics.Rect;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
|
import android.window.IDumpCallback;
|
||||||
|
|
||||||
import com.android.internal.infra.AndroidFuture;
|
import com.android.internal.infra.AndroidFuture;
|
||||||
|
|
||||||
@@ -116,4 +117,10 @@ interface ILauncherApps {
|
|||||||
String getShortcutIconUri(String callingPackage, String packageName, String shortcutId,
|
String getShortcutIconUri(String callingPackage, String packageName, String shortcutId,
|
||||||
int userId);
|
int userId);
|
||||||
Map<String, LauncherActivityInfoInternal> getActivityOverrides(String callingPackage, int userId);
|
Map<String, LauncherActivityInfoInternal> getActivityOverrides(String callingPackage, int userId);
|
||||||
|
|
||||||
|
/** Register a callback to be called right before the wmtrace data is moved to the bugreport. */
|
||||||
|
void registerDumpCallback(IDumpCallback cb);
|
||||||
|
|
||||||
|
/** Unregister a callback, so that it won't be called when LauncherApps dumps. */
|
||||||
|
void unRegisterDumpCallback(IDumpCallback cb);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package android.content.pm;
|
package android.content.pm;
|
||||||
|
|
||||||
import static android.Manifest.permission;
|
import static android.Manifest.permission;
|
||||||
|
import static android.Manifest.permission.READ_FRAME_BUFFER;
|
||||||
|
|
||||||
import android.annotation.CallbackExecutor;
|
import android.annotation.CallbackExecutor;
|
||||||
import android.annotation.IntDef;
|
import android.annotation.IntDef;
|
||||||
@@ -68,6 +69,7 @@ import android.util.ArrayMap;
|
|||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
import android.window.IDumpCallback;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.infra.AndroidFuture;
|
import com.android.internal.infra.AndroidFuture;
|
||||||
@@ -1171,6 +1173,32 @@ public class LauncherApps {
|
|||||||
return shortcuts;
|
return shortcuts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a callback to be called right before the wmtrace data is moved to the bugreport.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@RequiresPermission(READ_FRAME_BUFFER)
|
||||||
|
public void registerDumpCallback(IDumpCallback cb) {
|
||||||
|
try {
|
||||||
|
mService.registerDumpCallback(cb);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
e.rethrowAsRuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister a callback, so that it won't be called when LauncherApps dumps.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@RequiresPermission(READ_FRAME_BUFFER)
|
||||||
|
public void unRegisterDumpCallback(IDumpCallback cb) {
|
||||||
|
try {
|
||||||
|
mService.unRegisterDumpCallback(cb);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
e.rethrowAsRuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns {@link ShortcutInfo}s that match {@code query}.
|
* Returns {@link ShortcutInfo}s that match {@code query}.
|
||||||
*
|
*
|
||||||
|
|||||||
24
core/java/android/window/IDumpCallback.aidl
Normal file
24
core/java/android/window/IDumpCallback.aidl
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package android.window;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for processes which need to feed data to another process when it dumps.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
interface IDumpCallback {
|
||||||
|
oneway void onDump(in ParcelFileDescriptor outFd);
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.server.pm;
|
package com.android.server.pm;
|
||||||
|
|
||||||
|
import static android.Manifest.permission.READ_FRAME_BUFFER;
|
||||||
import static android.app.ActivityOptions.KEY_SPLASH_SCREEN_THEME;
|
import static android.app.ActivityOptions.KEY_SPLASH_SCREEN_THEME;
|
||||||
import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
|
import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
|
||||||
import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
|
import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
|
||||||
@@ -25,6 +26,8 @@ import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
|
|||||||
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
|
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
|
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
|
import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
|
||||||
|
import static android.content.PermissionChecker.PERMISSION_GRANTED;
|
||||||
|
import static android.content.PermissionChecker.checkCallingOrSelfPermissionForPreflight;
|
||||||
import static android.content.pm.LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS;
|
import static android.content.pm.LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS;
|
||||||
import static android.content.pm.LauncherApps.FLAG_CACHE_NOTIFICATION_SHORTCUTS;
|
import static android.content.pm.LauncherApps.FLAG_CACHE_NOTIFICATION_SHORTCUTS;
|
||||||
import static android.content.pm.LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS;
|
import static android.content.pm.LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS;
|
||||||
@@ -32,6 +35,7 @@ import static android.content.pm.LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS;
|
|||||||
import android.annotation.AppIdInt;
|
import android.annotation.AppIdInt;
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
|
import android.annotation.RequiresPermission;
|
||||||
import android.annotation.UserIdInt;
|
import android.annotation.UserIdInt;
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.ActivityManagerInternal;
|
import android.app.ActivityManagerInternal;
|
||||||
@@ -90,6 +94,7 @@ import android.util.ArrayMap;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
import android.window.IDumpCallback;
|
||||||
|
|
||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
@@ -104,6 +109,15 @@ import com.android.server.SystemService;
|
|||||||
import com.android.server.pm.pkg.AndroidPackage;
|
import com.android.server.pm.pkg.AndroidPackage;
|
||||||
import com.android.server.wm.ActivityTaskManagerInternal;
|
import com.android.server.wm.ActivityTaskManagerInternal;
|
||||||
|
|
||||||
|
import java.io.FileDescriptor;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
import java.nio.file.attribute.PosixFilePermission;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -111,6 +125,7 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -118,6 +133,15 @@ import java.util.concurrent.ExecutionException;
|
|||||||
* managed profiles.
|
* managed profiles.
|
||||||
*/
|
*/
|
||||||
public class LauncherAppsService extends SystemService {
|
public class LauncherAppsService extends SystemService {
|
||||||
|
private static final String WM_TRACE_DIR = "/data/misc/wmtrace/";
|
||||||
|
private static final String VC_FILE_SUFFIX = ".vc";
|
||||||
|
|
||||||
|
private static final Set<PosixFilePermission> WM_TRACE_FILE_PERMISSIONS = Set.of(
|
||||||
|
PosixFilePermission.OWNER_WRITE,
|
||||||
|
PosixFilePermission.GROUP_READ,
|
||||||
|
PosixFilePermission.OTHERS_READ,
|
||||||
|
PosixFilePermission.OWNER_READ
|
||||||
|
);
|
||||||
|
|
||||||
private final LauncherAppsImpl mLauncherAppsImpl;
|
private final LauncherAppsImpl mLauncherAppsImpl;
|
||||||
|
|
||||||
@@ -191,6 +215,8 @@ public class LauncherAppsService extends SystemService {
|
|||||||
|
|
||||||
final LauncherAppsServiceInternal mInternal;
|
final LauncherAppsServiceInternal mInternal;
|
||||||
|
|
||||||
|
private RemoteCallbackList<IDumpCallback> mDumpCallbacks = new RemoteCallbackList<>();
|
||||||
|
|
||||||
public LauncherAppsImpl(Context context) {
|
public LauncherAppsImpl(Context context) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mIPM = AppGlobals.getPackageManager();
|
mIPM = AppGlobals.getPackageManager();
|
||||||
@@ -1431,6 +1457,66 @@ public class LauncherAppsService extends SystemService {
|
|||||||
getActivityOptionsForLauncher(opts), user.getIdentifier());
|
getActivityOptionsForLauncher(opts), user.getIdentifier());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using a pipe, outputs view capture data to the wmtrace dir
|
||||||
|
*/
|
||||||
|
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||||
|
super.dump(fd, pw, args);
|
||||||
|
|
||||||
|
// Before the wmtrace directory is picked up by dumpstate service, some processes need
|
||||||
|
// to write their data to that location. They can do that via these dumpCallbacks.
|
||||||
|
int i = mDumpCallbacks.beginBroadcast();
|
||||||
|
while (i > 0) {
|
||||||
|
i--;
|
||||||
|
dumpDataToWmTrace((String) mDumpCallbacks.getBroadcastCookie(i) + "_" + i,
|
||||||
|
mDumpCallbacks.getBroadcastItem(i));
|
||||||
|
}
|
||||||
|
mDumpCallbacks.finishBroadcast();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dumpDataToWmTrace(String name, IDumpCallback cb) {
|
||||||
|
ParcelFileDescriptor[] pipe;
|
||||||
|
try {
|
||||||
|
pipe = ParcelFileDescriptor.createPipe();
|
||||||
|
cb.onDump(pipe[1]);
|
||||||
|
} catch (IOException | RemoteException e) {
|
||||||
|
Log.d(TAG, "failed to pipe view capture data", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Path path = Paths.get(WM_TRACE_DIR + Paths.get(name + VC_FILE_SUFFIX).getFileName());
|
||||||
|
try (InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pipe[0])) {
|
||||||
|
Files.copy(is, path, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
Files.setPosixFilePermissions(path, WM_TRACE_FILE_PERMISSIONS);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(TAG, "failed to write data to file in wmtrace dir", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresPermission(READ_FRAME_BUFFER)
|
||||||
|
@Override
|
||||||
|
public void registerDumpCallback(IDumpCallback cb) {
|
||||||
|
int status = checkCallingOrSelfPermissionForPreflight(mContext, READ_FRAME_BUFFER);
|
||||||
|
if (PERMISSION_GRANTED == status) {
|
||||||
|
String name = mContext.getPackageManager().getNameForUid(Binder.getCallingUid());
|
||||||
|
mDumpCallbacks.register(cb, name);
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "caller lacks permissions to registerDumpCallback");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresPermission(READ_FRAME_BUFFER)
|
||||||
|
@Override
|
||||||
|
public void unRegisterDumpCallback(IDumpCallback cb) {
|
||||||
|
int status = checkCallingOrSelfPermissionForPreflight(mContext, READ_FRAME_BUFFER);
|
||||||
|
if (PERMISSION_GRANTED == status) {
|
||||||
|
mDumpCallbacks.unregister(cb);
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "caller lacks permissions to unRegisterDumpCallback");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Checks if user is a profile of or same as listeningUser.
|
/** Checks if user is a profile of or same as listeningUser.
|
||||||
* and the user is enabled. */
|
* and the user is enabled. */
|
||||||
private boolean isEnabledProfileOf(UserHandle listeningUser, UserHandle user,
|
private boolean isEnabledProfileOf(UserHandle listeningUser, UserHandle user,
|
||||||
|
|||||||
Reference in New Issue
Block a user