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

Commit 4b09d08c authored by Ryan Mitchell's avatar Ryan Mitchell Committed by Android (Google) Code Review
Browse files

Merge "Revert "Stop idmap2d after several seconds pass"" into qt-r1-dev

parents 1ec1ecb3 16f36b8c
Loading
Loading
Loading
Loading
+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();
        }
    }
}
+49 −10
Original line number Original line Diff line number Diff line
@@ -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;


@@ -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;


@@ -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");
@@ -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,
@@ -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;
@@ -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;
@@ -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());
@@ -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.
+0 −1
Original line number Original line Diff line number Diff line
@@ -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);