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

Commit 5629f090 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Wait for idmap service on current thread" into rvc-dev am: 6831d480

Change-Id: I42b8050bf99da2de72786b28578784e5bd1e6fb6
parents 6064ca55 6831d480
Loading
Loading
Loading
Loading
+42 −64
Original line number Original line Diff line number Diff line
@@ -18,20 +18,19 @@ package com.android.server.om;


import static android.content.Context.IDMAP_SERVICE;
import static android.content.Context.IDMAP_SERVICE;


import static com.android.server.om.OverlayManagerService.DEBUG;
import static com.android.server.om.OverlayManagerService.TAG;
import static com.android.server.om.OverlayManagerService.TAG;


import android.os.IBinder;
import android.os.IBinder;
import android.os.IIdmap2;
import android.os.IIdmap2;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.SystemClock;
import android.os.SystemService;
import android.util.Slog;
import android.util.Slog;


import com.android.server.FgThread;
import com.android.server.FgThread;


import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicInteger;


/**
/**
@@ -45,13 +44,14 @@ class IdmapDaemon {


    // The amount of time in milliseconds to wait when attempting to connect to idmap service.
    // 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_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 final String IDMAP_DAEMON = "idmap2d";


    private static IdmapDaemon sInstance;
    private static IdmapDaemon sInstance;
    private volatile IIdmap2 mService;
    private volatile IIdmap2 mService;
    private final AtomicInteger mOpenedCount = new AtomicInteger();
    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
     * An {@link AutoCloseable} connection to the idmap service. When the connection is closed or
@@ -62,14 +62,14 @@ class IdmapDaemon {
        private boolean mOpened = true;
        private boolean mOpened = true;


        private Connection() {
        private Connection() {
            synchronized (IDMAP_TOKEN) {
            synchronized (mIdmapToken) {
                mOpenedCount.incrementAndGet();
                mOpenedCount.incrementAndGet();
            }
            }
        }
        }


        @Override
        @Override
        public void close() {
        public void close() {
            synchronized (IDMAP_TOKEN) {
            synchronized (mIdmapToken) {
                if (!mOpened) {
                if (!mOpened) {
                    return;
                    return;
                }
                }
@@ -82,7 +82,7 @@ class IdmapDaemon {
                }
                }


                FgThread.getHandler().postDelayed(() -> {
                FgThread.getHandler().postDelayed(() -> {
                    synchronized (IDMAP_TOKEN) {
                    synchronized (mIdmapToken) {
                        // Only stop the service if the service does not have an open connection.
                        // Only stop the service if the service does not have an open connection.
                        if (mService == null || mOpenedCount.get() != 0) {
                        if (mService == null || mOpenedCount.get() != 0) {
                            return;
                            return;
@@ -91,7 +91,7 @@ class IdmapDaemon {
                        stopIdmapService();
                        stopIdmapService();
                        mService = null;
                        mService = null;
                    }
                    }
                }, IDMAP_TOKEN, SERVICE_TIMEOUT_MS);
                }, mIdmapToken, SERVICE_TIMEOUT_MS);
            }
            }
        }
        }
    }
    }
@@ -104,14 +104,14 @@ class IdmapDaemon {
    }
    }


    String createIdmap(String targetPath, String overlayPath, int policies, boolean enforce,
    String createIdmap(String targetPath, String overlayPath, int policies, boolean enforce,
            int userId) throws Exception {
            int userId) throws TimeoutException, RemoteException {
        try (Connection connection = connect()) {
        try (Connection c = connect()) {
            return mService.createIdmap(targetPath, overlayPath, policies, enforce, userId);
            return mService.createIdmap(targetPath, overlayPath, policies, enforce, userId);
        }
        }
    }
    }


    boolean removeIdmap(String overlayPath, int userId) throws Exception {
    boolean removeIdmap(String overlayPath, int userId) throws TimeoutException, RemoteException {
        try (Connection connection = connect()) {
        try (Connection c = connect()) {
            return mService.removeIdmap(overlayPath, userId);
            return mService.removeIdmap(overlayPath, userId);
        }
        }
    }
    }
@@ -119,76 +119,54 @@ class IdmapDaemon {
    boolean verifyIdmap(String targetPath, String overlayPath, int policies, boolean enforce,
    boolean verifyIdmap(String targetPath, String overlayPath, int policies, boolean enforce,
             int userId)
             int userId)
            throws Exception {
            throws Exception {
        try (Connection connection = connect()) {
        try (Connection c = connect()) {
            return mService.verifyIdmap(targetPath, overlayPath, policies, enforce, userId);
            return mService.verifyIdmap(targetPath, overlayPath, policies, enforce, userId);
        }
        }
    }
    }


    String getIdmapPath(String overlayPath, int userId) throws Exception {
    String getIdmapPath(String overlayPath, int userId) throws TimeoutException, RemoteException {
        try (Connection connection = connect()) {
        try (Connection c = connect()) {
            return mService.getIdmapPath(overlayPath, userId);
            return mService.getIdmapPath(overlayPath, userId);
        }
        }
    }
    }


    private static void startIdmapService() {
    private IBinder getIdmapService() throws TimeoutException, RemoteException {
        SystemProperties.set("ctl.start", IDMAP_DAEMON);
        SystemService.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();


            // Block until the service is found.
        final long endMillis = SystemClock.elapsedRealtime() + SERVICE_CONNECT_TIMEOUT_MS;
            FutureTask<IBinder> bindIdmap = new FutureTask<>(() -> {
        while (SystemClock.elapsedRealtime() <= endMillis) {
                while (true) {
            final IBinder binder = ServiceManager.getService(IDMAP_SERVICE);
                    try {
                        IBinder binder = ServiceManager.getService(IDMAP_SERVICE);
            if (binder != null) {
            if (binder != null) {
                binder.linkToDeath(
                        () -> Slog.w(TAG, String.format("service '%s' died", IDMAP_SERVICE)), 0);
                return binder;
                return binder;
            }
            }
                    } catch (Exception e) {

                        Slog.e(TAG, "service '" + IDMAP_SERVICE + "' not retrieved; "
            try {
                                + e.getMessage());
                Thread.sleep(SERVICE_CONNECT_INTERVAL_SLEEP_MS);
            } catch (InterruptedException ignored) {
            }
            }
                    Thread.sleep(100);
        }
        }
            });


            IBinder binder;
        throw new TimeoutException(
            try {
            String.format("Failed to connect to '%s' in %d milliseconds", IDMAP_SERVICE,
                FgThread.getHandler().postAtFrontOfQueue(bindIdmap);
                    SERVICE_CONNECT_TIMEOUT_MS));
                binder = bindIdmap.get(SERVICE_CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
            } catch (Exception rethrow) {
                Slog.e(TAG, "service '" + IDMAP_SERVICE + "' not found;");
                throw rethrow;
    }
    }


            try {
    private static void stopIdmapService() {
                binder.linkToDeath(() -> {
        SystemService.stop(IDMAP_DAEMON);
                    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);
    private Connection connect() throws TimeoutException, RemoteException {
            if (DEBUG) {
        synchronized (mIdmapToken) {
                Slog.d(TAG, "service '" + IDMAP_SERVICE + "' connected");
            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();
            return new Connection();
        }
        }
    }
    }