From 33456fbfd75cd78aa8350c483c406f2573b0a98d Mon Sep 17 00:00:00 2001 From: Hai Zhang Date: Wed, 5 Dec 2018 17:30:35 -0800 Subject: [PATCH] Add dual dumping for RoleManagerService. This change adds dual dumping for RoleManagerService. Bug: 110557011 Test: adb shell dumpsys role Change-Id: I2782cd896df5d79274963785e46d04a295d83f7f --- core/proto/android/os/incident.proto | 6 ++ .../android/server/rolemanagerservice.proto | 56 +++++++++++++++++ .../server/role/RoleManagerService.java | 47 ++++++++++++-- .../android/server/role/RoleUserState.java | 61 +++++++++++++++---- 4 files changed, 153 insertions(+), 17 deletions(-) create mode 100644 core/proto/android/server/rolemanagerservice.proto diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto index 0b9e347ce5d16..a5350c9dc1b81 100644 --- a/core/proto/android/os/incident.proto +++ b/core/proto/android/os/incident.proto @@ -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; } diff --git a/core/proto/android/server/rolemanagerservice.proto b/core/proto/android/server/rolemanagerservice.proto new file mode 100644 index 0000000000000..3453a6649e02b --- /dev/null +++ b/core/proto/android/server/rolemanagerservice.proto @@ -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; +} diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java index b5ad2352896d5..500192ca00b3a 100644 --- a/services/core/java/com/android/server/role/RoleManagerService.java +++ b/services/core/java/com/android/server/role/RoleManagerService.java @@ -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(); + } } } diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java index ce0597435f715..327debf944370 100644 --- a/services/core/java/com/android/server/role/RoleUserState.java +++ b/services/core/java/com/android/server/role/RoleUserState.java @@ -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 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();