Convert DomainVerificationService.Connection to synchronous set

Unfortunately it's possible to call this during PackageManagerService
initialization, so this needs to be attached before PMS gets created.

Rather than using a deferred injection, this makes PMS call
setConnection to directly set the callback. A better isolated might be
worth exploring in the future, but overall it shouldn't really matter.

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

Bug: 163565712

Test: com.android.server.pm.test.domain.verify

Change-Id: Ib60f5560ecaa510474228aa1c38eff5d6041ab58
This commit is contained in:
Winson
2021-01-20 12:26:37 -08:00
parent 0af8c46c2f
commit 47dbabfc14
5 changed files with 98 additions and 109 deletions

View File

@@ -6456,6 +6456,9 @@ public class PackageManagerService extends IPackageManager.Stub
mAppInstallDir = new File(Environment.getDataDirectory(), "app");
mAppLib32InstallDir = getAppLib32InstallDir();
mDomainVerificationManager = injector.getDomainVerificationManagerInternal();
mDomainVerificationManager.setConnection(mDomainVerificationConnection);
// Link up the watchers
mPackages.registerObserver(mWatcher);
mSharedLibraries.registerObserver(mWatcher);
@@ -6482,7 +6485,6 @@ public class PackageManagerService extends IPackageManager.Stub
mProcessLoggingHandler = new ProcessLoggingHandler();
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
mIntentFilterVerificationManager = injector.getIntentFilterVerificationManager();
mDomainVerificationManager = injector.getDomainVerificationManagerInternal();
ArrayMap<String, SystemConfig.SharedLibraryEntry> libConfig
= systemConfig.getSharedLibraries();

View File

@@ -25,10 +25,14 @@ import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.domain.verify.DomainVerificationManager;
import android.content.pm.domain.verify.DomainVerificationSet;
import android.os.Binder;
import android.os.UserHandle;
import android.util.IndentingPrintWriter;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import com.android.internal.annotations.GuardedBy;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.PackageSetting;
import com.android.server.pm.domain.verify.models.DomainVerificationPkgState;
import com.android.server.pm.domain.verify.proxy.DomainVerificationProxy;
@@ -50,6 +54,8 @@ public interface DomainVerificationManagerInternal extends DomainVerificationMan
@NonNull
UUID generateNewId();
void setConnection(@NonNull Connection connection);
@NonNull
DomainVerificationProxy getProxy();
@@ -219,4 +225,36 @@ public interface DomainVerificationManagerInternal extends DomainVerificationMan
void setDomainVerificationStatusInternal(int callingUid, @NonNull UUID domainSetId,
@NonNull Set<String> domains, int state)
throws InvalidDomainSetException, NameNotFoundException;
interface Connection {
/**
* Notify that a settings change has been made and that eventually
* {@link #writeSettings(TypedXmlSerializer)} should be invoked by the parent.
*/
void scheduleWriteSettings();
/**
* Delegate to {@link Binder#getCallingUid()} to allow mocking in tests.
*/
int getCallingUid();
/**
* Delegate to {@link UserHandle#getCallingUserId()} to allow mocking in tests.
*/
@UserIdInt
int getCallingUserId();
/**
* @see DomainVerificationProxy.BaseConnection#schedule(int, java.lang.Object)
*/
void schedule(int code, @Nullable Object object);
@Nullable
PackageSetting getPackageSettingLocked(@NonNull String pkgName);
@Nullable
AndroidPackage getPackageLocked(@NonNull String pkgName);
}
}

View File

@@ -110,7 +110,7 @@ public class DomainVerificationService extends SystemService
private final Object mLock = new Object();
@NonNull
private final Singleton<Connection> mConnection;
private Connection mConnection;
@NonNull
private final SystemConfig mSystemConfig;
@@ -143,9 +143,8 @@ public class DomainVerificationService extends SystemService
private DomainVerificationProxy mProxy = new DomainVerificationProxyUnavailable();
public DomainVerificationService(@NonNull Context context, @NonNull SystemConfig systemConfig,
@NonNull PlatformCompat platformCompat, @NonNull Singleton<Connection> connection) {
@NonNull PlatformCompat platformCompat) {
super(context);
mConnection = connection;
mSystemConfig = systemConfig;
mPlatformCompat = platformCompat;
mSettings = new DomainVerificationSettings();
@@ -161,6 +160,11 @@ public class DomainVerificationService extends SystemService
publishBinderService(Context.DOMAIN_VERIFICATION_SERVICE, mStub);
}
@Override
public void setConnection(@NonNull Connection connection) {
mConnection = connection;
}
@NonNull
@Override
public DomainVerificationProxy getProxy() {
@@ -185,7 +189,7 @@ public class DomainVerificationService extends SystemService
@NonNull
@Override
public List<String> getValidVerificationPackageNames() {
mEnforcer.assertApprovedVerifier(mConnection.get().getCallingUid(), mProxy);
mEnforcer.assertApprovedVerifier(mConnection.getCallingUid(), mProxy);
List<String> packageNames = new ArrayList<>();
synchronized (mLock) {
int size = mAttachedPkgStates.size();
@@ -216,14 +220,14 @@ public class DomainVerificationService extends SystemService
@Override
public DomainVerificationSet getDomainVerificationSet(@NonNull String packageName)
throws NameNotFoundException {
mEnforcer.assertApprovedQuerent(mConnection.get().getCallingUid(), mProxy);
mEnforcer.assertApprovedQuerent(mConnection.getCallingUid(), mProxy);
synchronized (mLock) {
DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName);
if (pkgState == null) {
return null;
}
AndroidPackage pkg = mConnection.get().getPackageLocked(packageName);
AndroidPackage pkg = mConnection.getPackageLocked(packageName);
if (pkg == null) {
throw DomainVerificationUtils.throwPackageUnavailable(packageName);
}
@@ -258,7 +262,7 @@ public class DomainVerificationService extends SystemService
}
}
setDomainVerificationStatusInternal(mConnection.get().getCallingUid(), domainSetId, domains,
setDomainVerificationStatusInternal(mConnection.getCallingUid(), domainSetId, domains,
state);
}
@@ -282,13 +286,13 @@ public class DomainVerificationService extends SystemService
}
}
mConnection.get().scheduleWriteSettings();
mConnection.scheduleWriteSettings();
}
@Override
public void setDomainVerificationStatusInternal(@Nullable String packageName, int state,
@Nullable ArraySet<String> domains) throws NameNotFoundException {
mEnforcer.assertInternal(mConnection.get().getCallingUid());
mEnforcer.assertInternal(mConnection.getCallingUid());
switch (state) {
case DomainVerificationState.STATE_NO_RESPONSE:
@@ -309,7 +313,7 @@ public class DomainVerificationService extends SystemService
for (int index = 0; index < size; index++) {
DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index);
String pkgName = pkgState.getPackageName();
PackageSetting pkgSetting = mConnection.get().getPackageSettingLocked(pkgName);
PackageSetting pkgSetting = mConnection.getPackageSettingLocked(pkgName);
if (pkgSetting == null || pkgSetting.getPkg() == null) {
continue;
}
@@ -336,7 +340,7 @@ public class DomainVerificationService extends SystemService
throw DomainVerificationUtils.throwPackageUnavailable(packageName);
}
PackageSetting pkgSetting = mConnection.get().getPackageSettingLocked(packageName);
PackageSetting pkgSetting = mConnection.getPackageSettingLocked(packageName);
if (pkgSetting == null || pkgSetting.getPkg() == null) {
throw DomainVerificationUtils.throwPackageUnavailable(packageName);
}
@@ -352,7 +356,7 @@ public class DomainVerificationService extends SystemService
}
}
mConnection.get().scheduleWriteSettings();
mConnection.scheduleWriteSettings();
}
private void setDomainVerificationStatusInternal(@NonNull DomainVerificationPkgState pkgState,
@@ -368,14 +372,13 @@ public class DomainVerificationService extends SystemService
public void setDomainVerificationLinkHandlingAllowed(@NonNull String packageName,
boolean allowed) throws NameNotFoundException {
setDomainVerificationLinkHandlingAllowed(packageName, allowed,
mConnection.get().getCallingUserId());
mConnection.getCallingUserId());
}
public void setDomainVerificationLinkHandlingAllowed(@NonNull String packageName,
boolean allowed, @UserIdInt int userId) throws NameNotFoundException {
Connection connection = mConnection.get();
mEnforcer.assertApprovedUserSelector(connection.getCallingUid(),
connection.getCallingUserId(), userId);
mEnforcer.assertApprovedUserSelector(mConnection.getCallingUid(),
mConnection.getCallingUserId(), userId);
synchronized (mLock) {
DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName);
if (pkgState == null) {
@@ -386,13 +389,13 @@ public class DomainVerificationService extends SystemService
.setDisallowLinkHandling(!allowed);
}
mConnection.get().scheduleWriteSettings();
mConnection.scheduleWriteSettings();
}
@Override
public void setDomainVerificationLinkHandlingAllowedInternal(@Nullable String packageName,
boolean allowed, @UserIdInt int userId) throws NameNotFoundException {
mEnforcer.assertInternal(mConnection.get().getCallingUid());
mEnforcer.assertInternal(mConnection.getCallingUid());
if (packageName == null) {
synchronized (mLock) {
int pkgStateSize = mAttachedPkgStates.size();
@@ -426,7 +429,7 @@ public class DomainVerificationService extends SystemService
}
}
mConnection.get().scheduleWriteSettings();
mConnection.scheduleWriteSettings();
}
@Override
@@ -434,15 +437,14 @@ public class DomainVerificationService extends SystemService
@NonNull Set<String> domains, boolean enabled)
throws InvalidDomainSetException, NameNotFoundException {
setDomainVerificationUserSelection(domainSetId, domains, enabled,
mConnection.get().getCallingUserId());
mConnection.getCallingUserId());
}
public void setDomainVerificationUserSelection(@NonNull UUID domainSetId,
@NonNull Set<String> domains, boolean enabled, @UserIdInt int userId)
throws InvalidDomainSetException, NameNotFoundException {
Connection connection = mConnection.get();
mEnforcer.assertApprovedUserSelector(connection.getCallingUid(),
connection.getCallingUserId(), userId);
mEnforcer.assertApprovedUserSelector(mConnection.getCallingUid(),
mConnection.getCallingUserId(), userId);
synchronized (mLock) {
DomainVerificationPkgState pkgState = getAndValidateAttachedLocked(domainSetId, domains,
false /* forAutoVerify */);
@@ -454,14 +456,14 @@ public class DomainVerificationService extends SystemService
}
}
mConnection.get().scheduleWriteSettings();
mConnection.scheduleWriteSettings();
}
@Override
public void setDomainVerificationUserSelectionInternal(@UserIdInt int userId,
@Nullable String packageName, boolean enabled, @NonNull ArraySet<String> domains)
throws NameNotFoundException {
mEnforcer.assertInternal(mConnection.get().getCallingUid());
mEnforcer.assertInternal(mConnection.getCallingUid());
if (packageName == null) {
synchronized (mLock) {
@@ -471,7 +473,7 @@ public class DomainVerificationService extends SystemService
for (int index = 0; index < size; index++) {
DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index);
String pkgName = pkgState.getPackageName();
PackageSetting pkgSetting = mConnection.get().getPackageSettingLocked(pkgName);
PackageSetting pkgSetting = mConnection.getPackageSettingLocked(pkgName);
if (pkgSetting == null || pkgSetting.getPkg() == null) {
continue;
}
@@ -490,7 +492,7 @@ public class DomainVerificationService extends SystemService
throw DomainVerificationUtils.throwPackageUnavailable(packageName);
}
PackageSetting pkgSetting = mConnection.get().getPackageSettingLocked(packageName);
PackageSetting pkgSetting = mConnection.getPackageSettingLocked(packageName);
if (pkgSetting == null || pkgSetting.getPkg() == null) {
throw DomainVerificationUtils.throwPackageUnavailable(packageName);
}
@@ -500,7 +502,7 @@ public class DomainVerificationService extends SystemService
}
}
mConnection.get().scheduleWriteSettings();
mConnection.scheduleWriteSettings();
}
private void setDomainVerificationUserSelectionInternal(int userId,
@@ -529,7 +531,7 @@ public class DomainVerificationService extends SystemService
}
}
mConnection.get().scheduleWriteSettings();
mConnection.scheduleWriteSettings();
}
@Nullable
@@ -537,23 +539,22 @@ public class DomainVerificationService extends SystemService
public DomainVerificationUserSelection getDomainVerificationUserSelection(
@NonNull String packageName) throws NameNotFoundException {
return getDomainVerificationUserSelection(packageName,
mConnection.get().getCallingUserId());
mConnection.getCallingUserId());
}
@Nullable
@Override
public DomainVerificationUserSelection getDomainVerificationUserSelection(
@NonNull String packageName, @UserIdInt int userId) throws NameNotFoundException {
Connection connection = mConnection.get();
mEnforcer.assertApprovedUserSelector(connection.getCallingUid(),
connection.getCallingUserId(), userId);
mEnforcer.assertApprovedUserSelector(mConnection.getCallingUid(),
mConnection.getCallingUserId(), userId);
synchronized (mLock) {
DomainVerificationPkgState pkgState = mAttachedPkgStates.get(packageName);
if (pkgState == null) {
return null;
}
AndroidPackage pkg = connection.getPackageLocked(packageName);
AndroidPackage pkg = mConnection.getPackageLocked(packageName);
if (pkg == null) {
throw DomainVerificationUtils.throwPackageUnavailable(packageName);
}
@@ -834,7 +835,7 @@ public class DomainVerificationService extends SystemService
@Override
public void setLegacyUserState(@NonNull String packageName, @UserIdInt int userId, int state) {
mEnforcer.callerIsLegacyUserSelector(mConnection.get().getCallingUid());
mEnforcer.callerIsLegacyUserSelector(mConnection.getCallingUid());
mLegacySettings.add(packageName, userId, state);
}
@@ -854,7 +855,7 @@ public class DomainVerificationService extends SystemService
mAttachedPkgStates.remove(packageName);
}
mConnection.get().scheduleWriteSettings();
mConnection.scheduleWriteSettings();
}
@Override
@@ -868,7 +869,7 @@ public class DomainVerificationService extends SystemService
mSettings.removeUser(userId);
}
mConnection.get().scheduleWriteSettings();
mConnection.scheduleWriteSettings();
}
@Override
@@ -880,7 +881,7 @@ public class DomainVerificationService extends SystemService
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);
mDebug.printState(writer, packageName, userId, mConnection, mAttachedPkgStates);
}
}
@@ -925,7 +926,7 @@ public class DomainVerificationService extends SystemService
}
String pkgName = pkgState.getPackageName();
PackageSetting pkgSetting = mConnection.get().getPackageSettingLocked(pkgName);
PackageSetting pkgSetting = mConnection.getPackageSettingLocked(pkgName);
if (pkgSetting == null || pkgSetting.getPkg() == null) {
throw DomainVerificationUtils.throwPackageUnavailable(pkgName);
}
@@ -949,7 +950,7 @@ public class DomainVerificationService extends SystemService
@Override
public void verifyPackages(@Nullable List<String> packageNames, boolean reVerify) {
mEnforcer.assertInternal(mConnection.get().getCallingUid());
mEnforcer.assertInternal(mConnection.getCallingUid());
Set<String> packagesToBroadcast = new ArraySet<>();
if (packageNames == null) {
@@ -1013,14 +1014,14 @@ public class DomainVerificationService extends SystemService
@Override
public void clearDomainVerificationState(@Nullable List<String> packageNames) {
mEnforcer.assertInternal(mConnection.get().getCallingUid());
mEnforcer.assertInternal(mConnection.getCallingUid());
synchronized (mLock) {
if (packageNames == null) {
int size = mAttachedPkgStates.size();
for (int index = 0; index < size; index++) {
DomainVerificationPkgState pkgState = mAttachedPkgStates.valueAt(index);
String pkgName = pkgState.getPackageName();
PackageSetting pkgSetting = mConnection.get().getPackageSettingLocked(pkgName);
PackageSetting pkgSetting = mConnection.getPackageSettingLocked(pkgName);
if (pkgSetting == null || pkgSetting.getPkg() == null) {
continue;
}
@@ -1031,7 +1032,7 @@ public class DomainVerificationService extends SystemService
for (int index = 0; index < size; index++) {
String pkgName = packageNames.get(index);
DomainVerificationPkgState pkgState = mAttachedPkgStates.get(pkgName);
PackageSetting pkgSetting = mConnection.get().getPackageSettingLocked(pkgName);
PackageSetting pkgSetting = mConnection.getPackageSettingLocked(pkgName);
if (pkgSetting == null || pkgSetting.getPkg() == null) {
continue;
}
@@ -1071,7 +1072,7 @@ public class DomainVerificationService extends SystemService
@Override
public void clearUserSelections(@Nullable List<String> packageNames, @UserIdInt int userId) {
mEnforcer.assertInternal(mConnection.get().getCallingUid());
mEnforcer.assertInternal(mConnection.getCallingUid());
synchronized (mLock) {
if (packageNames == null) {
int size = mAttachedPkgStates.size();
@@ -1226,45 +1227,4 @@ public class DomainVerificationService extends SystemService
Slog.d(TAG + "Approval", packageName + " was " + approvalString + " for " + intent
+ " for user " + userId + ": " + reason);
}
public interface Connection {
/**
* Notify that a settings change has been made and that eventually
* {@link #writeSettings(TypedXmlSerializer)} should be invoked by the parent.
*/
void scheduleWriteSettings();
/**
* Delegate to {@link Binder#getCallingUid()} to allow mocking in tests.
*/
int getCallingUid();
/**
* Delegate to {@link UserHandle#getCallingUserId()} to allow mocking in tests.
*/
@UserIdInt
int getCallingUserId();
/**
* @see DomainVerificationProxy.BaseConnection#schedule(int, java.lang.Object)
*/
void schedule(int code, @Nullable Object object);
/**
* This can only be called when the internal {@link #mLock} is held. Otherwise it's possible
* to deadlock with {@link PackageManagerService}.
*/
@GuardedBy("mLock")
@Nullable
PackageSetting getPackageSettingLocked(@NonNull String pkgName);
/**
* This can only be called when the internal {@link #mLock} is held. Otherwise it's possible
* to deadlock with {@link PackageManagerService}.
*/
@GuardedBy("mLock")
@Nullable
AndroidPackage getPackageLocked(@NonNull String pkgName);
}
}

View File

@@ -87,7 +87,6 @@ import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.IndentingPrintWriter;
import android.util.Pair;
import android.util.Singleton;
import android.util.Slog;
import android.util.TimeUtils;
import android.view.contentcapture.ContentCaptureManager;
@@ -1064,16 +1063,7 @@ public final class SystemServer implements Dumpable {
t.traceBegin("StartDomainVerificationService");
DomainVerificationService domainVerificationService = new DomainVerificationService(
mSystemContext, SystemConfig.getInstance(), platformCompat,
new Singleton<DomainVerificationService.Connection>() {
@Override
protected DomainVerificationService.Connection create() {
// Deferred retrieval from PackageManagerService, since PMS is initialized after
// DVS. The alternative would be to expose this through the PackageManagerInternal
// local service, but making it visible to consumers of that interface isn't useful.
return mPackageManagerService.getDomainVerificationConnection();
}
});
mSystemContext, SystemConfig.getInstance(), platformCompat);
mSystemServiceManager.startService(domainVerificationService);
t.traceEnd();

View File

@@ -30,6 +30,7 @@ import android.util.SparseArray
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.pm.PackageSetting
import com.android.server.pm.domain.verify.DomainVerificationEnforcer
import com.android.server.pm.domain.verify.DomainVerificationManagerInternal
import com.android.server.pm.domain.verify.DomainVerificationService
import com.android.server.pm.domain.verify.proxy.DomainVerificationProxy
import com.android.server.pm.parsing.pkg.AndroidPackage
@@ -140,18 +141,16 @@ class DomainVerificationEnforcerTest {
any()
)
) { true }
},
object : Singleton<DomainVerificationService.Connection>() {
override fun create(): DomainVerificationService.Connection =
mockThrowOnUnmocked {
whenever(callingUid) { callingUidInt.get() }
whenever(callingUserId) { callingUserIdInt.get() }
whenever(getPackageSettingLocked(TEST_PKG)) { mockPkgSetting }
whenever(getPackageLocked(TEST_PKG)) { mockPkg }
whenever(schedule(anyInt(), any()))
whenever(scheduleWriteSettings())
}
})
}).apply {
setConnection(mockThrowOnUnmocked {
whenever(callingUid) { callingUidInt.get() }
whenever(callingUserId) { callingUserIdInt.get() }
whenever(getPackageSettingLocked(TEST_PKG)) { mockPkgSetting }
whenever(getPackageLocked(TEST_PKG)) { mockPkg }
whenever(schedule(anyInt(), any()))
whenever(scheduleWriteSettings())
})
}
)
}