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

Commit 4ea51d1b authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add dual dumping for RoleManagerService."

parents a4313a4a 33456fbf
Loading
Loading
Loading
Loading
+6 −0
Original line number 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/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;
}
+56 −0
Original line number 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 Diff line number Diff line
@@ -42,17 +42,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;
@@ -154,11 +160,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
@@ -178,7 +184,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);
@@ -246,7 +252,7 @@ public class RoleManagerService extends SystemService {
            mControllerServices.remove(userId);
            RoleUserState userState = mUserStates.removeReturnOld(userId);
            if (userState != null) {
                userState.destroySyncLocked();
                userState.destroyLocked();
            }
        }
    }
@@ -417,5 +423,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();
        }
    }
}
+49 −12
Original line number Diff line number Diff line
@@ -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();