Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 33456fbf authored by Hai Zhang's avatar Hai Zhang
Browse files

Add dual dumping for RoleManagerService.

This change adds dual dumping for RoleManagerService.

Bug: 110557011
Test: adb shell dumpsys role
Change-Id: I2782cd896df5d79274963785e46d04a295d83f7f
parent b3e9b9b1
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -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/fingerprint.proto";
import "frameworks/base/core/proto/android/server/jobscheduler.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/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/server/windowmanagerservice.proto";
import "frameworks/base/core/proto/android/service/appwidget.proto";
import "frameworks/base/core/proto/android/service/appwidget.proto";
import "frameworks/base/core/proto/android/service/battery.proto";
import "frameworks/base/core/proto/android/service/battery.proto";
@@ -308,6 +309,11 @@ message IncidentProto {
        (section).userdebug_and_eng_only = true
        (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.
    // Reserved for OEMs.
    extensions 50000 to 100000;
    extensions 50000 to 100000;
}
}
+56 −0
Original line number Original line Diff line number Diff line
/*
 * 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;
}
+42 −5
Original line number Original line Diff line number Diff line
@@ -41,17 +41,23 @@ import android.util.ArraySet;
import android.util.PackageUtils;
import android.util.PackageUtils;
import android.util.Slog;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;


import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.BitUtils;
import com.android.internal.util.BitUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FunctionalUtils;
import com.android.internal.util.FunctionalUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.Preconditions;
import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.server.LocalServices;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemService;


import java.io.ByteArrayOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Collections;
import java.util.List;
import java.util.List;
@@ -130,11 +136,11 @@ public class RoleManagerService extends SystemService {
            userState = getUserStateLocked(userId);
            userState = getUserStateLocked(userId);
        }
        }
        String packagesHash = computeComponentStateHash(userId);
        String packagesHash = computeComponentStateHash(userId);
        String lastGrantPackagesHash;
        String oldPackagesHash;
        synchronized (mLock) {
        synchronized (mLock) {
            lastGrantPackagesHash = userState.getLastGrantPackagesHashLocked();
            oldPackagesHash = userState.getPackagesHashLocked();
        }
        }
        boolean needGrant = !Objects.equals(packagesHash, lastGrantPackagesHash);
        boolean needGrant = !Objects.equals(packagesHash, oldPackagesHash);
        if (needGrant) {
        if (needGrant) {
            // Some vital packages state has changed since last role grant
            // Some vital packages state has changed since last role grant
            // Run grants again
            // Run grants again
@@ -154,7 +160,7 @@ public class RoleManagerService extends SystemService {
            try {
            try {
                result.get(5, TimeUnit.SECONDS);
                result.get(5, TimeUnit.SECONDS);
                synchronized (mLock) {
                synchronized (mLock) {
                    userState.setLastGrantPackagesHashLocked(packagesHash);
                    userState.setPackagesHashLocked(packagesHash);
                }
                }
            } catch (InterruptedException | ExecutionException | TimeoutException e) {
            } catch (InterruptedException | ExecutionException | TimeoutException e) {
                Slog.e(LOG_TAG, "Failed to grant defaults for user " + userId, 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);
            mControllerServices.remove(userId);
            RoleUserState userState = mUserStates.removeReturnOld(userId);
            RoleUserState userState = mUserStates.removeReturnOld(userId);
            if (userState != null) {
            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,
            new RoleManagerShellCommand(this).exec(this, in, out, err, args, callback,
                    resultReceiver);
                    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();
        }
    }
    }
}
}
+49 −12
Original line number Original line Diff line number Diff line
@@ -32,6 +32,7 @@ import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledLambda;


import libcore.io.IoUtils;
import libcore.io.IoUtils;
@@ -78,7 +79,7 @@ public class RoleUserState {


    @GuardedBy("RoleManagerService.mLock")
    @GuardedBy("RoleManagerService.mLock")
    @Nullable
    @Nullable
    private String mLastGrantPackagesHash;
    private String mPackagesHash;


    /**
    /**
     * Maps role names to its holders' package names. The values should never be null.
     * 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) {
    private RoleUserState(@UserIdInt int userId) {
        mUserId = userId;
        mUserId = userId;


        readSyncLocked();
        readLocked();
    }
    }


    /**
    /**
@@ -144,22 +145,22 @@ public class RoleUserState {
     * @return the hash representing the state of packages
     * @return the hash representing the state of packages
     */
     */
    @GuardedBy("RoleManagerService.mLock")
    @GuardedBy("RoleManagerService.mLock")
    public String getLastGrantPackagesHashLocked() {
    public String getPackagesHashLocked() {
        return mLastGrantPackagesHash;
        return mPackagesHash;
    }
    }


    /**
    /**
     * Set the hash representing the state of packages during the last time initial grants was run.
     * 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")
    @GuardedBy("RoleManagerService.mLock")
    public void setLastGrantPackagesHashLocked(@Nullable String lastGrantPackagesHash) {
    public void setPackagesHashLocked(@Nullable String packagesHash) {
        throwIfDestroyedLocked();
        throwIfDestroyedLocked();
        if (Objects.equals(mLastGrantPackagesHash, lastGrantPackagesHash)) {
        if (Objects.equals(mPackagesHash, packagesHash)) {
            return;
            return;
        }
        }
        mLastGrantPackagesHash = lastGrantPackagesHash;
        mPackagesHash = packagesHash;
        writeAsyncLocked();
        writeAsyncLocked();
    }
    }


@@ -311,7 +312,7 @@ public class RoleUserState {
        }
        }


        mWriteHandler.sendMessageDelayed(PooledLambda.obtainMessage(RoleUserState::writeSync, this,
        mWriteHandler.sendMessageDelayed(PooledLambda.obtainMessage(RoleUserState::writeSync, this,
                mVersion, mLastGrantPackagesHash, roles), writeDelayMillis);
                mVersion, mPackagesHash, roles), writeDelayMillis);
        Slog.i(LOG_TAG, "Scheduled writing roles.xml");
        Slog.i(LOG_TAG, "Scheduled writing roles.xml");
    }
    }


@@ -385,7 +386,7 @@ public class RoleUserState {
     * Read the state from file.
     * Read the state from file.
     */
     */
    @GuardedBy("RoleManagerService.mLock")
    @GuardedBy("RoleManagerService.mLock")
    private void readSyncLocked() {
    private void readLocked() {
        File file = getFile(mUserId);
        File file = getFile(mUserId);
        try (FileInputStream in = new AtomicFile(file).openRead()) {
        try (FileInputStream in = new AtomicFile(file).openRead()) {
            XmlPullParser parser = Xml.newPullParser();
            XmlPullParser parser = Xml.newPullParser();
@@ -421,7 +422,7 @@ public class RoleUserState {
    private void parseRolesLocked(@NonNull XmlPullParser parser) throws IOException,
    private void parseRolesLocked(@NonNull XmlPullParser parser) throws IOException,
            XmlPullParserException {
            XmlPullParserException {
        mVersion = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_VERSION));
        mVersion = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_VERSION));
        mLastGrantPackagesHash = parser.getAttributeValue(null, ATTRIBUTE_PACKAGES_HASH);
        mPackagesHash = parser.getAttributeValue(null, ATTRIBUTE_PACKAGES_HASH);
        mRoles.clear();
        mRoles.clear();


        int type;
        int type;
@@ -464,12 +465,48 @@ public class RoleUserState {
        return roleHolders;
        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
     * 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.
     * cancelled and any future interaction with this state will throw an exception.
     */
     */
    @GuardedBy("RoleManagerService.mLock")
    @GuardedBy("RoleManagerService.mLock")
    public void destroySyncLocked() {
    public void destroyLocked() {
        throwIfDestroyedLocked();
        throwIfDestroyedLocked();
        mWriteHandler.removeCallbacksAndMessages(null);
        mWriteHandler.removeCallbacksAndMessages(null);
        getFile(mUserId).delete();
        getFile(mUserId).delete();