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

Commit e94d0cfd authored by Winson's avatar Winson
Browse files

Add DomainVerificationDebug

Includes functionality for printing current domain verification state
and user selections for any/all packages/users.

Exempt-From-Owner-Approval: Already approved by owners on main branch

Bug: 163565712

Test: manual, looks right

Change-Id: I2930f9ebf2ecbdf0a0f64a5894059c9145988fe8
parent 6ad29543
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ public final class DumpState {
    public static final int DUMP_KEYSETS = 1 << 14;
    public static final int DUMP_VERSION = 1 << 15;
    public static final int DUMP_INSTALLS = 1 << 16;
    public static final int DUMP_INTENT_FILTER_VERIFIERS = 1 << 17;
    public static final int DUMP_DOMAIN_VERIFIER = 1 << 17;
    public static final int DUMP_DOMAIN_PREFERRED = 1 << 18;
    public static final int DUMP_FROZEN = 1 << 19;
    public static final int DUMP_DEXOPT = 1 << 20;
+23 −67
Original line number Diff line number Diff line
@@ -23948,9 +23948,8 @@ public class PackageManagerService extends IPackageManager.Stub
                dumpState.setDump(DumpState.DUMP_MESSAGES);
            } else if ("v".equals(cmd) || "verifiers".equals(cmd)) {
                dumpState.setDump(DumpState.DUMP_VERIFIERS);
            } else if ("i".equals(cmd) || "ifv".equals(cmd)
                    || "intent-filter-verifiers".equals(cmd)) {
                dumpState.setDump(DumpState.DUMP_INTENT_FILTER_VERIFIERS);
            } else if ("dv".equals(cmd) || "domain-verifier".equals(cmd)) {
                dumpState.setDump(DumpState.DUMP_DOMAIN_VERIFIER);
            } else if ("version".equals(cmd)) {
                dumpState.setDump(DumpState.DUMP_VERSION);
            } else if ("k".equals(cmd) || "keysets".equals(cmd)) {
@@ -24044,16 +24043,16 @@ public class PackageManagerService extends IPackageManager.Stub
                }
            }
            if (dumpState.isDumping(DumpState.DUMP_INTENT_FILTER_VERIFIERS) &&
            if (dumpState.isDumping(DumpState.DUMP_DOMAIN_VERIFIER) &&
                    packageName == null) {
                ComponentName verifierComponent =
                        mIntentFilterVerificationManager.getVerifierComponent();
                DomainVerificationProxy proxy = mDomainVerificationManager.getProxy();
                ComponentName verifierComponent = proxy.getComponentName();
                if (verifierComponent != null) {
                    String verifierPackageName = verifierComponent.getPackageName();
                    if (!checkin) {
                        if (dumpState.onTitlePrinted())
                            pw.println();
                        pw.println("Intent Filter Verifier:");
                        pw.println("Domain Verifier:");
                        pw.print("  Using: ");
                        pw.print(verifierPackageName);
                        pw.print(" (uid=");
@@ -24061,14 +24060,14 @@ public class PackageManagerService extends IPackageManager.Stub
                                UserHandle.USER_SYSTEM));
                        pw.println(")");
                    } else if (verifierPackageName != null) {
                        pw.print("ifv,"); pw.print(verifierPackageName);
                        pw.print("dv,"); pw.print(verifierPackageName);
                        pw.print(",");
                        pw.println(getPackageUid(verifierPackageName, MATCH_DEBUG_TRIAGED_MISSING,
                                UserHandle.USER_SYSTEM));
                    }
                } else {
                    pw.println();
                    pw.println("No Intent Filter Verifier available!");
                    pw.println("No Domain Verifier available!");
                }
            }
@@ -24185,63 +24184,20 @@ public class PackageManagerService extends IPackageManager.Stub
                }
            }
            if (!checkin
                    && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)
                    && packageName == null) {
                pw.println();
                int count = mSettings.getPackagesLocked().size();
                if (count == 0) {
                    pw.println("No applications!");
                    pw.println();
                } else {
                    final String prefix = "  ";
                    Collection<PackageSetting> allPackageSettings =
                            mSettings.getPackagesLocked().values();
                    if (allPackageSettings.size() == 0) {
                        pw.println("No domain preferred apps!");
                        pw.println();
                    } else {
                        pw.println("App verification status:");
                        pw.println();
                        count = 0;
                        for (PackageSetting ps : allPackageSettings) {
                            IntentFilterVerificationInfo ivi = ps.getIntentFilterVerificationInfo();
                            if (ivi == null || ivi.getPackageName() == null) continue;
                            pw.println(prefix + "Package: " + ivi.getPackageName());
                            pw.println(prefix + "Domains: " + ivi.getDomainsString());
                            pw.println(prefix + "Status:  " + ivi.getStatusString());
                            pw.println();
                            count++;
                        }
                        if (count == 0) {
                            pw.println(prefix + "No app verification established.");
                            pw.println();
                        }
                        for (int userId : mUserManager.getUserIds()) {
                            pw.println("App linkages for user " + userId + ":");
                            pw.println();
                            count = 0;
                            for (PackageSetting ps : allPackageSettings) {
                                final long status = ps.getDomainVerificationStatusForUser(userId);
                                if (status >> 32 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED
                                        && !DEBUG_DOMAIN_VERIFICATION) {
                                    continue;
                                }
                                pw.println(prefix + "Package: " + ps.name);
                                pw.println(prefix + "Domains: " + dumpDomainString(ps.name));
                                String statusStr = IntentFilterVerificationInfo.
                                        getStatusStringFromValue(status);
                                pw.println(prefix + "Status:  " + statusStr);
                                pw.println();
                                count++;
                            }
                            if (count == 0) {
                                pw.println(prefix + "No configured app linkages.");
                                pw.println();
                            }
                        }
                    }
            if (!checkin && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)) {
                android.util.IndentingPrintWriter writer =
                        new android.util.IndentingPrintWriter(pw);
                if (dumpState.onTitlePrinted()) pw.println();
                writer.println("Domain verification status:");
                writer.increaseIndent();
                try {
                    mDomainVerificationManager.printState(writer, packageName, UserHandle.USER_ALL);
                } catch (PackageManager.NameNotFoundException e) {
                    pw.println("Failure printing domain verification information");
                    Slog.e(TAG, "Failure printing domain verification information", e);
                }
                writer.decreaseIndent();
            }
            if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
@@ -24430,8 +24386,8 @@ public class PackageManagerService extends IPackageManager.Stub
                            UserHandle.USER_SYSTEM));
            proto.end(requiredVerifierPackageToken);
            ComponentName verifierComponent =
                    mIntentFilterVerificationManager.getVerifierComponent();
            DomainVerificationProxy proxy = mDomainVerificationManager.getProxy();
            ComponentName verifierComponent = proxy.getComponentName();
            if (verifierComponent != null) {
                String verifierPackageName = verifierComponent.getPackageName();
                final long verifierPackageToken =
+228 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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 com.android.server.pm.domain.verify;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import android.content.pm.domain.verify.DomainVerificationManager;
import android.content.pm.domain.verify.DomainVerificationState;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.PackageUtils;
import android.util.SparseArray;

import com.android.internal.util.CollectionUtils;
import com.android.server.pm.PackageSetting;
import com.android.server.pm.domain.verify.models.DomainVerificationPkgState;
import com.android.server.pm.domain.verify.models.DomainVerificationStateMap;
import com.android.server.pm.domain.verify.models.DomainVerificationUserState;
import com.android.server.pm.parsing.pkg.AndroidPackage;

import java.util.Arrays;

public class DomainVerificationDebug {

    @NonNull
    private final DomainVerificationCollector mCollector;

    DomainVerificationDebug(DomainVerificationCollector collector) {
        mCollector = collector;
    }

    public void printState(@NonNull IndentingPrintWriter writer, @Nullable String packageName,
            @Nullable @UserIdInt Integer userId,
            @NonNull DomainVerificationService.Connection connection,
            @NonNull DomainVerificationStateMap<DomainVerificationPkgState> stateMap)
            throws NameNotFoundException {
        ArrayMap<String, Integer> reusedMap = new ArrayMap<>();
        ArraySet<String> reusedSet = new ArraySet<>();

        if (packageName == null) {
            int size = stateMap.size();
            for (int index = 0; index < size; index++) {
                DomainVerificationPkgState pkgState = stateMap.valueAt(index);
                String pkgName = pkgState.getPackageName();
                PackageSetting pkgSetting = connection.getPackageSettingLocked(pkgName);
                if (pkgSetting == null || pkgSetting.getPkg() == null) {
                    continue;
                }

                boolean wasHeaderPrinted = printState(writer, pkgState, pkgSetting.getPkg(),
                        reusedMap, false);
                printState(writer, pkgState, pkgSetting.getPkg(), userId, reusedSet,
                        wasHeaderPrinted);
            }
        } else {
            DomainVerificationPkgState pkgState = stateMap.get(packageName);
            if (pkgState == null) {
                throw DomainVerificationUtils.throwPackageUnavailable(packageName);
            }

            PackageSetting pkgSetting = connection.getPackageSettingLocked(packageName);
            if (pkgSetting == null || pkgSetting.getPkg() == null) {
                throw DomainVerificationUtils.throwPackageUnavailable(packageName);
            }

            AndroidPackage pkg = pkgSetting.getPkg();
            printState(writer, pkgState, pkg, reusedMap, false);
            printState(writer, pkgState, pkg, userId, reusedSet, true);
        }
    }

    boolean printState(@NonNull IndentingPrintWriter writer,
            @NonNull DomainVerificationPkgState pkgState, @NonNull AndroidPackage pkg,
            @NonNull ArrayMap<String, Integer> reusedMap, boolean wasHeaderPrinted) {
        reusedMap.clear();
        reusedMap.putAll(pkgState.getStateMap());

        ArraySet<String> declaredDomains = mCollector.collectAutoVerifyDomains(pkg);
        int declaredSize = declaredDomains.size();
        for (int declaredIndex = 0; declaredIndex < declaredSize; declaredIndex++) {
            String domain = declaredDomains.valueAt(declaredIndex);
            reusedMap.putIfAbsent(domain, DomainVerificationState.STATE_NO_RESPONSE);
        }

        boolean printedHeader = false;

        if (!reusedMap.isEmpty()) {
            if (!wasHeaderPrinted) {
                Signature[] signatures = pkg.getSigningDetails().signatures;
                String signaturesDigest = signatures == null ? null : Arrays.toString(
                        PackageUtils.computeSignaturesSha256Digests(
                                pkg.getSigningDetails().signatures));

                writer.println(pkgState.getPackageName() + " " + pkgState.getId() + ":");
                writer.increaseIndent();
                writer.println("Signatures: " + signaturesDigest);
                writer.decreaseIndent();
                printedHeader = true;
            }

            writer.increaseIndent();
            writer.println("Domain verification state:");
            writer.increaseIndent();
            int stateSize = reusedMap.size();
            for (int stateIndex = 0; stateIndex < stateSize; stateIndex++) {
                String domain = reusedMap.keyAt(stateIndex);
                Integer state = reusedMap.valueAt(stateIndex);
                writer.print(domain);
                writer.print(": ");
                writer.println(DomainVerificationManager.stateToDebugString(state));
            }
            writer.decreaseIndent();
            writer.decreaseIndent();
        }

        return printedHeader;
    }

    void printState(@NonNull IndentingPrintWriter writer,
            @NonNull DomainVerificationPkgState pkgState, @NonNull AndroidPackage pkg,
            @Nullable @UserIdInt Integer userId, @NonNull ArraySet<String> reusedSet,
            boolean wasHeaderPrinted) {
        if (userId == null) {
            return;
        }

        ArraySet<String> allWebDomains = mCollector.collectAllWebDomains(pkg);
        SparseArray<DomainVerificationUserState> userStates =
                pkgState.getUserSelectionStates();
        if (userId == UserHandle.USER_ALL) {
            int size = userStates.size();
            if (size == 0) {
                printState(writer, pkgState, userId, null, reusedSet, allWebDomains,
                        wasHeaderPrinted);
            } else {
                for (int index = 0; index < size; index++) {
                    DomainVerificationUserState userState = userStates.valueAt(index);
                    printState(writer, pkgState, userState.getUserId(), userState, reusedSet,
                            allWebDomains, wasHeaderPrinted);
                }
            }
        } else {
            DomainVerificationUserState userState = userStates.get(userId);
            printState(writer, pkgState, userId, userState, reusedSet, allWebDomains,
                    wasHeaderPrinted);
        }
    }

    boolean printState(@NonNull IndentingPrintWriter writer,
            @NonNull DomainVerificationPkgState pkgState, @UserIdInt int userId,
            @Nullable DomainVerificationUserState userState, @NonNull ArraySet<String> reusedSet,
            @NonNull ArraySet<String> allWebDomains, boolean wasHeaderPrinted) {
        reusedSet.clear();
        reusedSet.addAll(allWebDomains);
        if (userState != null) {
            reusedSet.removeAll(userState.getEnabledHosts());
        }

        boolean printedHeader = false;

        ArraySet<String> enabledHosts = userState == null ? null : userState.getEnabledHosts();
        int enabledSize = CollectionUtils.size(enabledHosts);
        int disabledSize = reusedSet.size();
        if (enabledSize > 0 || disabledSize > 0) {
            if (!wasHeaderPrinted) {
                writer.println(pkgState.getPackageName() + " " + pkgState.getId() + ":");
                printedHeader = true;
            }

            boolean isLinkHandlingAllowed = userState == null
                    || !userState.isDisallowLinkHandling();

            writer.increaseIndent();
            writer.print("User ");
            writer.print(userId == UserHandle.USER_ALL ? "all" : userId);
            writer.println(":");
            writer.increaseIndent();
            writer.print("Verification link handling allowed: ");
            writer.println(isLinkHandlingAllowed);
            writer.println("Selection state:");
            writer.increaseIndent();

            if (enabledSize > 0) {
                writer.println("Enabled:");
                writer.increaseIndent();
                for (int enabledIndex = 0; enabledIndex < enabledSize; enabledIndex++) {
                    //noinspection ConstantConditions
                    writer.println(enabledHosts.valueAt(enabledIndex));
                }
                writer.decreaseIndent();
            }

            if (disabledSize > 0) {
                writer.println("Disabled:");
                writer.increaseIndent();
                for (int disabledIndex = 0; disabledIndex < disabledSize; disabledIndex++) {
                    writer.println(reusedSet.valueAt(disabledIndex));
                }
                writer.decreaseIndent();
            }

            writer.decreaseIndent();
            writer.decreaseIndent();
            writer.decreaseIndent();
        }

        return printedHeader;
    }
}
+15 −0
Original line number Diff line number Diff line
@@ -17,9 +17,12 @@
package com.android.server.pm.domain.verify;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.domain.verify.DomainVerificationManager;
import android.content.pm.domain.verify.DomainVerificationSet;
import android.util.IndentingPrintWriter;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;

@@ -42,6 +45,9 @@ public interface DomainVerificationManagerInternal extends DomainVerificationMan
    @NonNull
    UUID generateNewId();

    @NonNull
    DomainVerificationProxy getProxy();

    /**
     * Update the proxy implementation that talks to the domain verification agent on device. The
     * default proxy is a stub that does nothing, and broadcast functionality will only work once a
@@ -139,4 +145,13 @@ public interface DomainVerificationManagerInternal extends DomainVerificationMan
    void restoreSettings(@NonNull TypedXmlPullParser parser)
            throws IOException, XmlPullParserException;

    /**
     * Print the verification state and user selection state of a package.
     *
     * @param packageName the package whose state to change, or all packages if none is specified
     * @param userId      the specific user to print, or null to skip printing user selection
     *                    states, supports {@link android.os.UserHandle#USER_ALL}
     */
    void printState(@NonNull IndentingPrintWriter writer, @Nullable String packageName,
            @Nullable @UserIdInt Integer userId) throws NameNotFoundException;
}
+21 −2
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.os.Binder;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Singleton;
import android.util.Slog;
import android.util.SparseArray;
@@ -103,6 +104,9 @@ public class DomainVerificationService extends SystemService
    @NonNull
    private final DomainVerificationEnforcer mEnforcer;

    @NonNull
    private final DomainVerificationDebug mDebug;

    @NonNull
    private final IDomainVerificationManager.Stub mStub = new DomainVerificationManagerStub(this);

@@ -117,6 +121,7 @@ public class DomainVerificationService extends SystemService
        mSettings = new DomainVerificationSettings();
        mCollector = new DomainVerificationCollector(platformCompat, systemConfig);
        mEnforcer = new DomainVerificationEnforcer(context);
        mDebug = new DomainVerificationDebug(mCollector);
    }

    @Override
@@ -124,6 +129,12 @@ public class DomainVerificationService extends SystemService
        publishBinderService(Context.DOMAIN_VERIFICATION_SERVICE, mStub);
    }

    @NonNull
    @Override
    public DomainVerificationProxy getProxy() {
        return mProxy;
    }

    @Override
    public void setProxy(@NonNull DomainVerificationProxy proxy) {
        mProxy = proxy;
@@ -188,8 +199,8 @@ public class DomainVerificationService extends SystemService
        if (state < DomainVerificationState.STATE_FIRST_VERIFIER_DEFINED) {
            if (state != DomainVerificationState.STATE_SUCCESS) {
                throw new IllegalArgumentException(
                        "External callers can only set STATE_SUCCESS or codes greater than or "
                                + "equal to STATE_FIRST_CALLER_DEFINED");
                        "Verifier can only set STATE_SUCCESS or codes greater than or equal to "
                                + "STATE_FIRST_VERIFIER_DEFINED");
            }
        }

@@ -571,6 +582,14 @@ public class DomainVerificationService extends SystemService
        return mProxy.runMessage(messageCode, object);
    }

    @Override
    public void printState(@NonNull IndentingPrintWriter writer, @Nullable String packageName,
            @Nullable @UserIdInt Integer userId) throws NameNotFoundException {
        synchronized (mLock) {
            mDebug.printState(writer, packageName, userId, mConnection.get(), mAttachedPkgStates);
        }
    }

    private void sendBroadcastForPackage(@NonNull String packageName) {
        mProxy.sendBroadcastForPackages(Collections.singleton(packageName));
    }
Loading