Add dual dumping for RoleManagerService.

This change adds dual dumping for RoleManagerService.

Bug: 110557011
Test: adb shell dumpsys role
Change-Id: I2782cd896df5d79274963785e46d04a295d83f7f
This commit is contained in:
Hai Zhang
2018-12-05 17:30:35 -08:00
parent b3e9b9b186
commit 33456fbfd7
4 changed files with 153 additions and 17 deletions

View File

@@ -34,6 +34,7 @@ import "frameworks/base/core/proto/android/server/alarmmanagerservice.proto";
import "frameworks/base/core/proto/android/server/fingerprint.proto";
import "frameworks/base/core/proto/android/server/jobscheduler.proto";
import "frameworks/base/core/proto/android/server/powermanagerservice.proto";
import "frameworks/base/core/proto/android/server/rolemanagerservice.proto";
import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
import "frameworks/base/core/proto/android/service/appwidget.proto";
import "frameworks/base/core/proto/android/service/battery.proto";
@@ -308,6 +309,11 @@ message IncidentProto {
(section).userdebug_and_eng_only = true
];
optional com.android.server.role.RoleManagerServiceDumpProto role = 3024 [
(section).type = SECTION_DUMPSYS,
(section).args = "role --proto"
];
// Reserved for OEMs.
extensions 50000 to 100000;
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
syntax = "proto2";
package com.android.server.role;
option java_multiple_files = true;
import "frameworks/base/libs/incident/proto/android/privacy.proto";
message RoleManagerServiceDumpProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
// List of per-user states for all users.
repeated RoleUserStateProto user_states = 1;
}
message RoleUserStateProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
// The user id of this state.
optional int32 user_id = 1;
// The version of this state.
optional int32 version = 2;
// The hash of packages for this state.
optional string packages_hash = 3;
// The set of roles in this state.
repeated RoleProto roles = 4;
}
message RoleProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
// The name of this role, e.g. "android.app.role.DIALER".
optional string name = 1;
// The package names of the holders of this role.
repeated string holders = 2;
}

View File

@@ -41,17 +41,23 @@ import android.util.ArraySet;
import android.util.PackageUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.BitUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FunctionalUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -130,11 +136,11 @@ public class RoleManagerService extends SystemService {
userState = getUserStateLocked(userId);
}
String packagesHash = computeComponentStateHash(userId);
String lastGrantPackagesHash;
String oldPackagesHash;
synchronized (mLock) {
lastGrantPackagesHash = userState.getLastGrantPackagesHashLocked();
oldPackagesHash = userState.getPackagesHashLocked();
}
boolean needGrant = !Objects.equals(packagesHash, lastGrantPackagesHash);
boolean needGrant = !Objects.equals(packagesHash, oldPackagesHash);
if (needGrant) {
// Some vital packages state has changed since last role grant
// Run grants again
@@ -154,7 +160,7 @@ public class RoleManagerService extends SystemService {
try {
result.get(5, TimeUnit.SECONDS);
synchronized (mLock) {
userState.setLastGrantPackagesHashLocked(packagesHash);
userState.setPackagesHashLocked(packagesHash);
}
} catch (InterruptedException | ExecutionException | TimeoutException e) {
Slog.e(LOG_TAG, "Failed to grant defaults for user " + userId, e);
@@ -222,7 +228,7 @@ public class RoleManagerService extends SystemService {
mControllerServices.remove(userId);
RoleUserState userState = mUserStates.removeReturnOld(userId);
if (userState != null) {
userState.destroySyncLocked();
userState.destroyLocked();
}
}
}
@@ -393,5 +399,36 @@ public class RoleManagerService extends SystemService {
new RoleManagerShellCommand(this).exec(this, in, out, err, args, callback,
resultReceiver);
}
@Override
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
@Nullable String[] args) {
if (!DumpUtils.checkDumpPermission(getContext(), LOG_TAG, fout)) {
return;
}
boolean dumpAsProto = args != null && ArrayUtils.contains(args, "--proto");
DualDumpOutputStream dumpOutputStream;
if (dumpAsProto) {
dumpOutputStream = new DualDumpOutputStream(new ProtoOutputStream(fd));
} else {
fout.println("ROLE MANAGER STATE (dumpsys role):");
dumpOutputStream = new DualDumpOutputStream(new IndentingPrintWriter(fout, " "));
}
synchronized (mLock) {
int[] userIds = mUserManagerInternal.getUserIds();
int userIdsLength = userIds.length;
for (int i = 0; i < userIdsLength; i++) {
int userId = userIds[i];
RoleUserState userState = getUserStateLocked(userId);
userState.dumpLocked(dumpOutputStream, "user_states",
RoleManagerServiceDumpProto.USER_STATES);
}
}
dumpOutputStream.flush();
}
}
}

View File

@@ -32,6 +32,7 @@ import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.internal.util.function.pooled.PooledLambda;
import libcore.io.IoUtils;
@@ -78,7 +79,7 @@ public class RoleUserState {
@GuardedBy("RoleManagerService.mLock")
@Nullable
private String mLastGrantPackagesHash;
private String mPackagesHash;
/**
* Maps role names to its holders' package names. The values should never be null.
@@ -99,7 +100,7 @@ public class RoleUserState {
private RoleUserState(@UserIdInt int userId) {
mUserId = userId;
readSyncLocked();
readLocked();
}
/**
@@ -144,22 +145,22 @@ public class RoleUserState {
* @return the hash representing the state of packages
*/
@GuardedBy("RoleManagerService.mLock")
public String getLastGrantPackagesHashLocked() {
return mLastGrantPackagesHash;
public String getPackagesHashLocked() {
return mPackagesHash;
}
/**
* Set the hash representing the state of packages during the last time initial grants was run.
*
* @param lastGrantPackagesHash the hash representing the state of packages
* @param packagesHash the hash representing the state of packages
*/
@GuardedBy("RoleManagerService.mLock")
public void setLastGrantPackagesHashLocked(@Nullable String lastGrantPackagesHash) {
public void setPackagesHashLocked(@Nullable String packagesHash) {
throwIfDestroyedLocked();
if (Objects.equals(mLastGrantPackagesHash, lastGrantPackagesHash)) {
if (Objects.equals(mPackagesHash, packagesHash)) {
return;
}
mLastGrantPackagesHash = lastGrantPackagesHash;
mPackagesHash = packagesHash;
writeAsyncLocked();
}
@@ -311,7 +312,7 @@ public class RoleUserState {
}
mWriteHandler.sendMessageDelayed(PooledLambda.obtainMessage(RoleUserState::writeSync, this,
mVersion, mLastGrantPackagesHash, roles), writeDelayMillis);
mVersion, mPackagesHash, roles), writeDelayMillis);
Slog.i(LOG_TAG, "Scheduled writing roles.xml");
}
@@ -385,7 +386,7 @@ public class RoleUserState {
* Read the state from file.
*/
@GuardedBy("RoleManagerService.mLock")
private void readSyncLocked() {
private void readLocked() {
File file = getFile(mUserId);
try (FileInputStream in = new AtomicFile(file).openRead()) {
XmlPullParser parser = Xml.newPullParser();
@@ -421,7 +422,7 @@ public class RoleUserState {
private void parseRolesLocked(@NonNull XmlPullParser parser) throws IOException,
XmlPullParserException {
mVersion = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_VERSION));
mLastGrantPackagesHash = parser.getAttributeValue(null, ATTRIBUTE_PACKAGES_HASH);
mPackagesHash = parser.getAttributeValue(null, ATTRIBUTE_PACKAGES_HASH);
mRoles.clear();
int type;
@@ -464,12 +465,48 @@ public class RoleUserState {
return roleHolders;
}
/**
* Dump this user state.
*
* @param dumpOutputStream the output stream to dump to
*/
@GuardedBy("RoleManagerService.mLock")
public void dumpLocked(@NonNull DualDumpOutputStream dumpOutputStream,
@NonNull String fieldName, long fieldId) {
throwIfDestroyedLocked();
long fieldToken = dumpOutputStream.start(fieldName, fieldId);
dumpOutputStream.write("user_id", RoleUserStateProto.USER_ID, mUserId);
dumpOutputStream.write("version", RoleUserStateProto.VERSION, mVersion);
dumpOutputStream.write("packages_hash", RoleUserStateProto.PACKAGES_HASH, mPackagesHash);
int rolesSize = mRoles.size();
for (int rolesIndex = 0; rolesIndex < rolesSize; rolesIndex++) {
String roleName = mRoles.keyAt(rolesIndex);
ArraySet<String> roleHolders = mRoles.valueAt(rolesIndex);
long rolesToken = dumpOutputStream.start("roles", RoleUserStateProto.ROLES);
dumpOutputStream.write("name", RoleProto.NAME, roleName);
int roleHoldersSize = roleHolders.size();
for (int roleHoldersIndex = 0; roleHoldersIndex < roleHoldersSize; roleHoldersIndex++) {
String roleHolder = roleHolders.valueAt(roleHoldersIndex);
dumpOutputStream.write("holders", RoleProto.HOLDERS, roleHolder);
}
dumpOutputStream.end(rolesToken);
}
dumpOutputStream.end(fieldToken);
}
/**
* Destroy this state and delete the corresponding file. Any pending writes to the file will be
* cancelled and any future interaction with this state will throw an exception.
*/
@GuardedBy("RoleManagerService.mLock")
public void destroySyncLocked() {
public void destroyLocked() {
throwIfDestroyedLocked();
mWriteHandler.removeCallbacksAndMessages(null);
getFile(mUserId).delete();