Loading services/core/java/com/android/server/om/IdmapDaemon.java +42 −64 Original line number Diff line number Diff line Loading @@ -18,20 +18,19 @@ 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.os.SystemClock; import android.os.SystemService; import android.util.Slog; import com.android.server.FgThread; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; /** Loading @@ -45,13 +44,14 @@ class IdmapDaemon { // 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 int SERVICE_CONNECT_INTERVAL_SLEEP_MS = 200; 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(); private final Object mIdmapToken = new Object(); /** * An {@link AutoCloseable} connection to the idmap service. When the connection is closed or Loading @@ -62,14 +62,14 @@ class IdmapDaemon { private boolean mOpened = true; private Connection() { synchronized (IDMAP_TOKEN) { synchronized (mIdmapToken) { mOpenedCount.incrementAndGet(); } } @Override public void close() { synchronized (IDMAP_TOKEN) { synchronized (mIdmapToken) { if (!mOpened) { return; } Loading @@ -82,7 +82,7 @@ class IdmapDaemon { } FgThread.getHandler().postDelayed(() -> { synchronized (IDMAP_TOKEN) { synchronized (mIdmapToken) { // Only stop the service if the service does not have an open connection. if (mService == null || mOpenedCount.get() != 0) { return; Loading @@ -91,7 +91,7 @@ class IdmapDaemon { stopIdmapService(); mService = null; } }, IDMAP_TOKEN, SERVICE_TIMEOUT_MS); }, mIdmapToken, SERVICE_TIMEOUT_MS); } } } Loading @@ -104,14 +104,14 @@ class IdmapDaemon { } String createIdmap(String targetPath, String overlayPath, int policies, boolean enforce, int userId) throws Exception { try (Connection connection = connect()) { int userId) throws TimeoutException, RemoteException { try (Connection c = connect()) { return mService.createIdmap(targetPath, overlayPath, policies, enforce, userId); } } boolean removeIdmap(String overlayPath, int userId) throws Exception { try (Connection connection = connect()) { boolean removeIdmap(String overlayPath, int userId) throws TimeoutException, RemoteException { try (Connection c = connect()) { return mService.removeIdmap(overlayPath, userId); } } Loading @@ -119,76 +119,54 @@ class IdmapDaemon { boolean verifyIdmap(String targetPath, String overlayPath, int policies, boolean enforce, int userId) throws Exception { try (Connection connection = connect()) { try (Connection c = connect()) { return mService.verifyIdmap(targetPath, overlayPath, policies, enforce, userId); } } String getIdmapPath(String overlayPath, int userId) throws Exception { try (Connection connection = connect()) { String getIdmapPath(String overlayPath, int userId) throws TimeoutException, RemoteException { try (Connection c = connect()) { return mService.getIdmapPath(overlayPath, userId); } } private static void startIdmapService() { SystemProperties.set("ctl.start", IDMAP_DAEMON); } private 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(); private IBinder getIdmapService() throws TimeoutException, RemoteException { SystemService.start(IDMAP_DAEMON); // Block until the service is found. FutureTask<IBinder> bindIdmap = new FutureTask<>(() -> { while (true) { try { IBinder binder = ServiceManager.getService(IDMAP_SERVICE); final long endMillis = SystemClock.elapsedRealtime() + SERVICE_CONNECT_TIMEOUT_MS; while (SystemClock.elapsedRealtime() <= endMillis) { final IBinder binder = ServiceManager.getService(IDMAP_SERVICE); if (binder != null) { binder.linkToDeath( () -> Slog.w(TAG, String.format("service '%s' died", IDMAP_SERVICE)), 0); return binder; } } catch (Exception e) { Slog.e(TAG, "service '" + IDMAP_SERVICE + "' not retrieved; " + e.getMessage()); try { Thread.sleep(SERVICE_CONNECT_INTERVAL_SLEEP_MS); } catch (InterruptedException ignored) { } 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; throw new TimeoutException( String.format("Failed to connect to '%s' in %d milliseconds", IDMAP_SERVICE, SERVICE_CONNECT_TIMEOUT_MS)); } 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; private static void stopIdmapService() { SystemService.stop(IDMAP_DAEMON); } mService = IIdmap2.Stub.asInterface(binder); if (DEBUG) { Slog.d(TAG, "service '" + IDMAP_SERVICE + "' connected"); private Connection connect() throws TimeoutException, RemoteException { synchronized (mIdmapToken) { FgThread.getHandler().removeCallbacksAndMessages(mIdmapToken); if (mService != null) { // Not enough time has passed to stop the idmap service. Reuse the existing // interface. return new Connection(); } mService = IIdmap2.Stub.asInterface(getIdmapService()); return new Connection(); } } Loading Loading
services/core/java/com/android/server/om/IdmapDaemon.java +42 −64 Original line number Diff line number Diff line Loading @@ -18,20 +18,19 @@ 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.os.SystemClock; import android.os.SystemService; import android.util.Slog; import com.android.server.FgThread; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; /** Loading @@ -45,13 +44,14 @@ class IdmapDaemon { // 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 int SERVICE_CONNECT_INTERVAL_SLEEP_MS = 200; 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(); private final Object mIdmapToken = new Object(); /** * An {@link AutoCloseable} connection to the idmap service. When the connection is closed or Loading @@ -62,14 +62,14 @@ class IdmapDaemon { private boolean mOpened = true; private Connection() { synchronized (IDMAP_TOKEN) { synchronized (mIdmapToken) { mOpenedCount.incrementAndGet(); } } @Override public void close() { synchronized (IDMAP_TOKEN) { synchronized (mIdmapToken) { if (!mOpened) { return; } Loading @@ -82,7 +82,7 @@ class IdmapDaemon { } FgThread.getHandler().postDelayed(() -> { synchronized (IDMAP_TOKEN) { synchronized (mIdmapToken) { // Only stop the service if the service does not have an open connection. if (mService == null || mOpenedCount.get() != 0) { return; Loading @@ -91,7 +91,7 @@ class IdmapDaemon { stopIdmapService(); mService = null; } }, IDMAP_TOKEN, SERVICE_TIMEOUT_MS); }, mIdmapToken, SERVICE_TIMEOUT_MS); } } } Loading @@ -104,14 +104,14 @@ class IdmapDaemon { } String createIdmap(String targetPath, String overlayPath, int policies, boolean enforce, int userId) throws Exception { try (Connection connection = connect()) { int userId) throws TimeoutException, RemoteException { try (Connection c = connect()) { return mService.createIdmap(targetPath, overlayPath, policies, enforce, userId); } } boolean removeIdmap(String overlayPath, int userId) throws Exception { try (Connection connection = connect()) { boolean removeIdmap(String overlayPath, int userId) throws TimeoutException, RemoteException { try (Connection c = connect()) { return mService.removeIdmap(overlayPath, userId); } } Loading @@ -119,76 +119,54 @@ class IdmapDaemon { boolean verifyIdmap(String targetPath, String overlayPath, int policies, boolean enforce, int userId) throws Exception { try (Connection connection = connect()) { try (Connection c = connect()) { return mService.verifyIdmap(targetPath, overlayPath, policies, enforce, userId); } } String getIdmapPath(String overlayPath, int userId) throws Exception { try (Connection connection = connect()) { String getIdmapPath(String overlayPath, int userId) throws TimeoutException, RemoteException { try (Connection c = connect()) { return mService.getIdmapPath(overlayPath, userId); } } private static void startIdmapService() { SystemProperties.set("ctl.start", IDMAP_DAEMON); } private 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(); private IBinder getIdmapService() throws TimeoutException, RemoteException { SystemService.start(IDMAP_DAEMON); // Block until the service is found. FutureTask<IBinder> bindIdmap = new FutureTask<>(() -> { while (true) { try { IBinder binder = ServiceManager.getService(IDMAP_SERVICE); final long endMillis = SystemClock.elapsedRealtime() + SERVICE_CONNECT_TIMEOUT_MS; while (SystemClock.elapsedRealtime() <= endMillis) { final IBinder binder = ServiceManager.getService(IDMAP_SERVICE); if (binder != null) { binder.linkToDeath( () -> Slog.w(TAG, String.format("service '%s' died", IDMAP_SERVICE)), 0); return binder; } } catch (Exception e) { Slog.e(TAG, "service '" + IDMAP_SERVICE + "' not retrieved; " + e.getMessage()); try { Thread.sleep(SERVICE_CONNECT_INTERVAL_SLEEP_MS); } catch (InterruptedException ignored) { } 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; throw new TimeoutException( String.format("Failed to connect to '%s' in %d milliseconds", IDMAP_SERVICE, SERVICE_CONNECT_TIMEOUT_MS)); } 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; private static void stopIdmapService() { SystemService.stop(IDMAP_DAEMON); } mService = IIdmap2.Stub.asInterface(binder); if (DEBUG) { Slog.d(TAG, "service '" + IDMAP_SERVICE + "' connected"); private Connection connect() throws TimeoutException, RemoteException { synchronized (mIdmapToken) { FgThread.getHandler().removeCallbacksAndMessages(mIdmapToken); if (mService != null) { // Not enough time has passed to stop the idmap service. Reuse the existing // interface. return new Connection(); } mService = IIdmap2.Stub.asInterface(getIdmapService()); return new Connection(); } } Loading