Loading services/core/java/com/android/server/om/IdmapDaemon.javadeleted 100644 → 0 +0 −193 Original line number Original line Diff line number Diff line /* * 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.IoThread; 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; } IoThread.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) { IoThread.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<>(() -> { IBinder binder = null; while (binder == null) { try { binder = ServiceManager.getService(IDMAP_SERVICE); Thread.sleep(100); } catch (Exception e) { Slog.e(TAG, "service '" + IDMAP_SERVICE + "' not retrieved; " + e.getMessage()); } } return binder; }); IBinder binder; try { IoThread.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(); } } } services/core/java/com/android/server/om/IdmapManager.java +49 −10 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,9 @@ 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; Loading @@ -24,11 +27,15 @@ 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; Loading @@ -44,6 +51,11 @@ 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"); Loading @@ -58,14 +70,12 @@ 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; mIdmapDaemon = IdmapDaemon.getInstance(); if (FEATURE_FLAG_IDMAP2) { connectToIdmap2d(); } } } boolean createIdmap(@NonNull final PackageInfo targetPackage, boolean createIdmap(@NonNull final PackageInfo targetPackage, Loading @@ -81,11 +91,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 (mIdmapDaemon.verifyIdmap(overlayPath, policies, enforce, userId)) { if (mIdmap2Service.verifyIdmap(overlayPath, policies, enforce, userId)) { return true; return true; } } return mIdmapDaemon.createIdmap(targetPath, overlayPath, policies, return mIdmap2Service.createIdmap(targetPath, overlayPath, policies, enforce, enforce, userId) != null; userId) != null; } else { } else { mInstaller.idmap(targetPath, overlayPath, sharedGid); mInstaller.idmap(targetPath, overlayPath, sharedGid); return true; return true; Loading @@ -103,7 +113,7 @@ class IdmapManager { } } try { try { if (FEATURE_FLAG_IDMAP2) { if (FEATURE_FLAG_IDMAP2) { return mIdmapDaemon.removeIdmap(oi.baseCodePath, userId); return mIdmap2Service.removeIdmap(oi.baseCodePath, userId); } else { } else { mInstaller.removeIdmap(oi.baseCodePath); mInstaller.removeIdmap(oi.baseCodePath); return true; return true; Loading @@ -127,7 +137,7 @@ class IdmapManager { final int userId) { final int userId) { if (FEATURE_FLAG_IDMAP2) { if (FEATURE_FLAG_IDMAP2) { try { try { return mIdmapDaemon.getIdmapPath(overlayPackagePath, userId); return mIdmap2Service.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()); Loading @@ -141,6 +151,35 @@ 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. Loading services/core/java/com/android/server/om/OverlayManagerService.java +0 −1 Original line number Original line Diff line number Diff line Loading @@ -262,7 +262,6 @@ 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); Loading Loading
services/core/java/com/android/server/om/IdmapDaemon.javadeleted 100644 → 0 +0 −193 Original line number Original line Diff line number Diff line /* * 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.IoThread; 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; } IoThread.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) { IoThread.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<>(() -> { IBinder binder = null; while (binder == null) { try { binder = ServiceManager.getService(IDMAP_SERVICE); Thread.sleep(100); } catch (Exception e) { Slog.e(TAG, "service '" + IDMAP_SERVICE + "' not retrieved; " + e.getMessage()); } } return binder; }); IBinder binder; try { IoThread.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(); } } }
services/core/java/com/android/server/om/IdmapManager.java +49 −10 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,9 @@ 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; Loading @@ -24,11 +27,15 @@ 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; Loading @@ -44,6 +51,11 @@ 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"); Loading @@ -58,14 +70,12 @@ 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; mIdmapDaemon = IdmapDaemon.getInstance(); if (FEATURE_FLAG_IDMAP2) { connectToIdmap2d(); } } } boolean createIdmap(@NonNull final PackageInfo targetPackage, boolean createIdmap(@NonNull final PackageInfo targetPackage, Loading @@ -81,11 +91,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 (mIdmapDaemon.verifyIdmap(overlayPath, policies, enforce, userId)) { if (mIdmap2Service.verifyIdmap(overlayPath, policies, enforce, userId)) { return true; return true; } } return mIdmapDaemon.createIdmap(targetPath, overlayPath, policies, return mIdmap2Service.createIdmap(targetPath, overlayPath, policies, enforce, enforce, userId) != null; userId) != null; } else { } else { mInstaller.idmap(targetPath, overlayPath, sharedGid); mInstaller.idmap(targetPath, overlayPath, sharedGid); return true; return true; Loading @@ -103,7 +113,7 @@ class IdmapManager { } } try { try { if (FEATURE_FLAG_IDMAP2) { if (FEATURE_FLAG_IDMAP2) { return mIdmapDaemon.removeIdmap(oi.baseCodePath, userId); return mIdmap2Service.removeIdmap(oi.baseCodePath, userId); } else { } else { mInstaller.removeIdmap(oi.baseCodePath); mInstaller.removeIdmap(oi.baseCodePath); return true; return true; Loading @@ -127,7 +137,7 @@ class IdmapManager { final int userId) { final int userId) { if (FEATURE_FLAG_IDMAP2) { if (FEATURE_FLAG_IDMAP2) { try { try { return mIdmapDaemon.getIdmapPath(overlayPackagePath, userId); return mIdmap2Service.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()); Loading @@ -141,6 +151,35 @@ 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. Loading
services/core/java/com/android/server/om/OverlayManagerService.java +0 −1 Original line number Original line Diff line number Diff line Loading @@ -262,7 +262,6 @@ 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); Loading