Merge "Stop idmap2d after several seconds pass" into qt-r1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
aa22db3da7
194
services/core/java/com/android/server/om/IdmapDaemon.java
Normal file
194
services/core/java/com/android/server/om/IdmapDaemon.java
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.om;
|
||||||
|
|
||||||
|
import static android.content.Context.IDMAP_SERVICE;
|
||||||
|
|
||||||
|
import static com.android.server.om.OverlayManagerService.DEBUG;
|
||||||
|
import static com.android.server.om.OverlayManagerService.TAG;
|
||||||
|
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.IIdmap2;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.os.ServiceManager;
|
||||||
|
import android.os.SystemProperties;
|
||||||
|
import android.util.Slog;
|
||||||
|
|
||||||
|
import com.android.server.FgThread;
|
||||||
|
|
||||||
|
import java.util.concurrent.FutureTask;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To prevent idmap2d from continuously running, the idmap daemon will terminate after 10
|
||||||
|
* seconds without a transaction.
|
||||||
|
**/
|
||||||
|
class IdmapDaemon {
|
||||||
|
// The amount of time in milliseconds to wait after a transaction to the idmap service is made
|
||||||
|
// before stopping the service.
|
||||||
|
private static final int SERVICE_TIMEOUT_MS = 10000;
|
||||||
|
|
||||||
|
// The amount of time in milliseconds to wait when attempting to connect to idmap service.
|
||||||
|
private static final int SERVICE_CONNECT_TIMEOUT_MS = 5000;
|
||||||
|
|
||||||
|
private static final Object IDMAP_TOKEN = new Object();
|
||||||
|
private static final String IDMAP_DAEMON = "idmap2d";
|
||||||
|
|
||||||
|
private static IdmapDaemon sInstance;
|
||||||
|
private volatile IIdmap2 mService;
|
||||||
|
private final AtomicInteger mOpenedCount = new AtomicInteger();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link AutoCloseable} connection to the idmap service. When the connection is closed or
|
||||||
|
* finalized, the idmap service will be stopped after a period of time unless another connection
|
||||||
|
* to the service is open.
|
||||||
|
**/
|
||||||
|
private class Connection implements AutoCloseable {
|
||||||
|
private boolean mOpened = true;
|
||||||
|
|
||||||
|
private Connection() {
|
||||||
|
synchronized (IDMAP_TOKEN) {
|
||||||
|
mOpenedCount.incrementAndGet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
synchronized (IDMAP_TOKEN) {
|
||||||
|
if (!mOpened) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mOpened = false;
|
||||||
|
if (mOpenedCount.decrementAndGet() != 0) {
|
||||||
|
// Only post the callback to stop the service if the service does not have an
|
||||||
|
// open connection.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FgThread.getHandler().postDelayed(() -> {
|
||||||
|
synchronized (IDMAP_TOKEN) {
|
||||||
|
// Only stop the service if the service does not have an open connection.
|
||||||
|
if (mService == null || mOpenedCount.get() != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stopIdmapService();
|
||||||
|
mService = null;
|
||||||
|
}
|
||||||
|
}, IDMAP_TOKEN, SERVICE_TIMEOUT_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static IdmapDaemon getInstance() {
|
||||||
|
if (sInstance == null) {
|
||||||
|
sInstance = new IdmapDaemon();
|
||||||
|
}
|
||||||
|
return sInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
String createIdmap(String targetPath, String overlayPath, int policies, boolean enforce,
|
||||||
|
int userId) throws Exception {
|
||||||
|
try (Connection connection = connect()) {
|
||||||
|
return mService.createIdmap(targetPath, overlayPath, policies, enforce, userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean removeIdmap(String overlayPath, int userId) throws Exception {
|
||||||
|
try (Connection connection = connect()) {
|
||||||
|
return mService.removeIdmap(overlayPath, userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean verifyIdmap(String overlayPath, int policies, boolean enforce, int userId)
|
||||||
|
throws Exception {
|
||||||
|
try (Connection connection = connect()) {
|
||||||
|
return mService.verifyIdmap(overlayPath, policies, enforce, userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String getIdmapPath(String overlayPath, int userId) throws Exception {
|
||||||
|
try (Connection connection = connect()) {
|
||||||
|
return mService.getIdmapPath(overlayPath, userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void startIdmapService() {
|
||||||
|
SystemProperties.set("ctl.start", IDMAP_DAEMON);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stopIdmapService() {
|
||||||
|
SystemProperties.set("ctl.stop", IDMAP_DAEMON);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Connection connect() throws Exception {
|
||||||
|
synchronized (IDMAP_TOKEN) {
|
||||||
|
FgThread.getHandler().removeCallbacksAndMessages(IDMAP_TOKEN);
|
||||||
|
if (mService != null) {
|
||||||
|
// Not enough time has passed to stop the idmap service. Reuse the existing
|
||||||
|
// interface.
|
||||||
|
return new Connection();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the idmap service if it is not currently running.
|
||||||
|
startIdmapService();
|
||||||
|
|
||||||
|
// Block until the service is found.
|
||||||
|
FutureTask<IBinder> bindIdmap = new FutureTask<>(() -> {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
IBinder binder = ServiceManager.getService(IDMAP_SERVICE);
|
||||||
|
if (binder != null) {
|
||||||
|
return binder;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Slog.e(TAG, "service '" + IDMAP_SERVICE + "' not retrieved; "
|
||||||
|
+ e.getMessage());
|
||||||
|
}
|
||||||
|
Thread.sleep(100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
IBinder binder;
|
||||||
|
try {
|
||||||
|
FgThread.getHandler().postAtFrontOfQueue(bindIdmap);
|
||||||
|
binder = bindIdmap.get(SERVICE_CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||||
|
} catch (Exception rethrow) {
|
||||||
|
Slog.e(TAG, "service '" + IDMAP_SERVICE + "' not found;");
|
||||||
|
throw rethrow;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
binder.linkToDeath(() -> {
|
||||||
|
Slog.w(TAG, "service '" + IDMAP_SERVICE + "' died");
|
||||||
|
}, 0);
|
||||||
|
} catch (RemoteException rethrow) {
|
||||||
|
Slog.e(TAG, "service '" + IDMAP_SERVICE + "' failed to be bound");
|
||||||
|
throw rethrow;
|
||||||
|
}
|
||||||
|
|
||||||
|
mService = IIdmap2.Stub.asInterface(binder);
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.d(TAG, "service '" + IDMAP_SERVICE + "' connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Connection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,9 +16,6 @@
|
|||||||
|
|
||||||
package com.android.server.om;
|
package com.android.server.om;
|
||||||
|
|
||||||
import static android.content.Context.IDMAP_SERVICE;
|
|
||||||
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
|
|
||||||
|
|
||||||
import static com.android.server.om.OverlayManagerService.DEBUG;
|
import static com.android.server.om.OverlayManagerService.DEBUG;
|
||||||
import static com.android.server.om.OverlayManagerService.TAG;
|
import static com.android.server.om.OverlayManagerService.TAG;
|
||||||
|
|
||||||
@@ -27,15 +24,11 @@ import android.content.om.OverlayInfo;
|
|||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.os.Build.VERSION_CODES;
|
import android.os.Build.VERSION_CODES;
|
||||||
import android.os.IBinder;
|
|
||||||
import android.os.IIdmap2;
|
import android.os.IIdmap2;
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.os.ServiceManager;
|
|
||||||
import android.os.SystemProperties;
|
import android.os.SystemProperties;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
|
||||||
import com.android.internal.os.BackgroundThread;
|
|
||||||
import com.android.server.om.OverlayManagerServiceImpl.PackageManagerHelper;
|
import com.android.server.om.OverlayManagerServiceImpl.PackageManagerHelper;
|
||||||
import com.android.server.pm.Installer;
|
import com.android.server.pm.Installer;
|
||||||
|
|
||||||
@@ -51,11 +44,6 @@ import java.io.File;
|
|||||||
*/
|
*/
|
||||||
class IdmapManager {
|
class IdmapManager {
|
||||||
private static final boolean FEATURE_FLAG_IDMAP2 = true;
|
private static final boolean FEATURE_FLAG_IDMAP2 = true;
|
||||||
|
|
||||||
private final Installer mInstaller;
|
|
||||||
private final PackageManagerHelper mPackageManager;
|
|
||||||
private IIdmap2 mIdmap2Service;
|
|
||||||
|
|
||||||
private static final boolean VENDOR_IS_Q_OR_LATER;
|
private static final boolean VENDOR_IS_Q_OR_LATER;
|
||||||
static {
|
static {
|
||||||
final String value = SystemProperties.get("ro.vndk.version", "29");
|
final String value = SystemProperties.get("ro.vndk.version", "29");
|
||||||
@@ -70,12 +58,14 @@ class IdmapManager {
|
|||||||
VENDOR_IS_Q_OR_LATER = isQOrLater;
|
VENDOR_IS_Q_OR_LATER = isQOrLater;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final Installer mInstaller;
|
||||||
|
private final PackageManagerHelper mPackageManager;
|
||||||
|
private final IdmapDaemon mIdmapDaemon;
|
||||||
|
|
||||||
IdmapManager(final Installer installer, final PackageManagerHelper packageManager) {
|
IdmapManager(final Installer installer, final PackageManagerHelper packageManager) {
|
||||||
mInstaller = installer;
|
mInstaller = installer;
|
||||||
mPackageManager = packageManager;
|
mPackageManager = packageManager;
|
||||||
if (FEATURE_FLAG_IDMAP2) {
|
mIdmapDaemon = IdmapDaemon.getInstance();
|
||||||
connectToIdmap2d();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean createIdmap(@NonNull final PackageInfo targetPackage,
|
boolean createIdmap(@NonNull final PackageInfo targetPackage,
|
||||||
@@ -91,11 +81,11 @@ class IdmapManager {
|
|||||||
if (FEATURE_FLAG_IDMAP2) {
|
if (FEATURE_FLAG_IDMAP2) {
|
||||||
int policies = calculateFulfilledPolicies(targetPackage, overlayPackage, userId);
|
int policies = calculateFulfilledPolicies(targetPackage, overlayPackage, userId);
|
||||||
boolean enforce = enforceOverlayable(overlayPackage);
|
boolean enforce = enforceOverlayable(overlayPackage);
|
||||||
if (mIdmap2Service.verifyIdmap(overlayPath, policies, enforce, userId)) {
|
if (mIdmapDaemon.verifyIdmap(overlayPath, policies, enforce, userId)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return mIdmap2Service.createIdmap(targetPath, overlayPath, policies, enforce,
|
return mIdmapDaemon.createIdmap(targetPath, overlayPath, policies,
|
||||||
userId) != null;
|
enforce, userId) != null;
|
||||||
} else {
|
} else {
|
||||||
mInstaller.idmap(targetPath, overlayPath, sharedGid);
|
mInstaller.idmap(targetPath, overlayPath, sharedGid);
|
||||||
return true;
|
return true;
|
||||||
@@ -113,7 +103,7 @@ class IdmapManager {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (FEATURE_FLAG_IDMAP2) {
|
if (FEATURE_FLAG_IDMAP2) {
|
||||||
return mIdmap2Service.removeIdmap(oi.baseCodePath, userId);
|
return mIdmapDaemon.removeIdmap(oi.baseCodePath, userId);
|
||||||
} else {
|
} else {
|
||||||
mInstaller.removeIdmap(oi.baseCodePath);
|
mInstaller.removeIdmap(oi.baseCodePath);
|
||||||
return true;
|
return true;
|
||||||
@@ -137,7 +127,7 @@ class IdmapManager {
|
|||||||
final int userId) {
|
final int userId) {
|
||||||
if (FEATURE_FLAG_IDMAP2) {
|
if (FEATURE_FLAG_IDMAP2) {
|
||||||
try {
|
try {
|
||||||
return mIdmap2Service.getIdmapPath(overlayPackagePath, userId);
|
return mIdmapDaemon.getIdmapPath(overlayPackagePath, userId);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Slog.w(TAG, "failed to get idmap path for " + overlayPackagePath + ": "
|
Slog.w(TAG, "failed to get idmap path for " + overlayPackagePath + ": "
|
||||||
+ e.getMessage());
|
+ e.getMessage());
|
||||||
@@ -151,35 +141,6 @@ class IdmapManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connectToIdmap2d() {
|
|
||||||
IBinder binder = ServiceManager.getService(IDMAP_SERVICE);
|
|
||||||
if (binder != null) {
|
|
||||||
try {
|
|
||||||
binder.linkToDeath(new IBinder.DeathRecipient() {
|
|
||||||
@Override
|
|
||||||
public void binderDied() {
|
|
||||||
Slog.w(TAG, "service '" + IDMAP_SERVICE + "' died; reconnecting...");
|
|
||||||
connectToIdmap2d();
|
|
||||||
}
|
|
||||||
|
|
||||||
}, 0);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
binder = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (binder != null) {
|
|
||||||
mIdmap2Service = IIdmap2.Stub.asInterface(binder);
|
|
||||||
if (DEBUG) {
|
|
||||||
Slog.d(TAG, "service '" + IDMAP_SERVICE + "' connected");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Slog.w(TAG, "service '" + IDMAP_SERVICE + "' not found; trying again...");
|
|
||||||
BackgroundThread.getHandler().postDelayed(() -> {
|
|
||||||
connectToIdmap2d();
|
|
||||||
}, SECOND_IN_MILLIS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if overlayable and policies should be enforced on the specified overlay for backwards
|
* Checks if overlayable and policies should be enforced on the specified overlay for backwards
|
||||||
* compatibility with pre-Q overlays.
|
* compatibility with pre-Q overlays.
|
||||||
|
|||||||
@@ -262,6 +262,7 @@ public final class OverlayManagerService extends SystemService {
|
|||||||
|
|
||||||
initIfNeeded();
|
initIfNeeded();
|
||||||
onSwitchUser(UserHandle.USER_SYSTEM);
|
onSwitchUser(UserHandle.USER_SYSTEM);
|
||||||
|
IdmapDaemon.stopIdmapService();
|
||||||
|
|
||||||
publishBinderService(Context.OVERLAY_SERVICE, mService);
|
publishBinderService(Context.OVERLAY_SERVICE, mService);
|
||||||
publishLocalService(OverlayManagerService.class, this);
|
publishLocalService(OverlayManagerService.class, this);
|
||||||
|
|||||||
Reference in New Issue
Block a user