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

Commit b97ce434 authored by Android Build Merger (Role)'s avatar Android Build Merger (Role) Committed by Android (Google) Code Review
Browse files

Merge "Merge changes I2cb4200b,If1fa00be into qt-dev am: 6b268152 am:...

Merge "Merge changes I2cb4200b,If1fa00be into qt-dev am: 6b268152 am: d581e0aa" into qt-r1-dev-plus-aosp
parents 455197f2 4788a518
Loading
Loading
Loading
Loading
+48 −10
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.net.NetworkStackClient;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
@@ -115,6 +116,7 @@ public class PackageWatchdog {
    // File containing the XML data of monitored packages /data/system/package-watchdog.xml
    private final AtomicFile mPolicyFile;
    private final ExplicitHealthCheckController mHealthCheckController;
    private final NetworkStackClient mNetworkStackClient;
    @GuardedBy("mLock")
    private boolean mIsPackagesReady;
    // Flag to control whether explicit health checks are supported or not
@@ -135,7 +137,8 @@ public class PackageWatchdog {
                        new File(new File(Environment.getDataDirectory(), "system"),
                                "package-watchdog.xml")),
                new Handler(Looper.myLooper()), BackgroundThread.getHandler(),
                new ExplicitHealthCheckController(context));
                new ExplicitHealthCheckController(context),
                NetworkStackClient.getInstance());
    }

    /**
@@ -143,12 +146,14 @@ public class PackageWatchdog {
     */
    @VisibleForTesting
    PackageWatchdog(Context context, AtomicFile policyFile, Handler shortTaskHandler,
            Handler longTaskHandler, ExplicitHealthCheckController controller) {
            Handler longTaskHandler, ExplicitHealthCheckController controller,
            NetworkStackClient networkStackClient) {
        mContext = context;
        mPolicyFile = policyFile;
        mShortTaskHandler = shortTaskHandler;
        mLongTaskHandler = longTaskHandler;
        mHealthCheckController = controller;
        mNetworkStackClient = networkStackClient;
        loadFromFile();
    }

@@ -174,6 +179,7 @@ public class PackageWatchdog {
                    () -> syncRequestsAsync());
            setPropertyChangedListenerLocked();
            updateConfigs();
            registerNetworkStackHealthListener();
        }
    }

@@ -630,29 +636,40 @@ public class PackageWatchdog {
            synchronized (mLock) {
                PackageHealthObserver registeredObserver = observer.mRegisteredObserver;
                if (registeredObserver != null) {
                    PackageManager pm = mContext.getPackageManager();
                    Iterator<MonitoredPackage> it = failedPackages.iterator();
                    while (it.hasNext()) {
                        String failedPackage = it.next().getName();
                        long versionCode = 0;
                        Slog.i(TAG, "Explicit health check failed for package " + failedPackage);
                        try {
                            versionCode = pm.getPackageInfo(
                                    failedPackage, 0 /* flags */).getLongVersionCode();
                        } catch (PackageManager.NameNotFoundException e) {
                        VersionedPackage versionedPkg = getVersionedPackage(failedPackage);
                        if (versionedPkg == null) {
                            Slog.w(TAG, "Explicit health check failed but could not find package "
                                    + failedPackage);
                            // TODO(b/120598832): Skip. We only continue to pass tests for now since
                            // the tests don't install any packages
                            versionedPkg = new VersionedPackage(failedPackage, 0L);
                        }
                        registeredObserver.execute(
                                new VersionedPackage(failedPackage, versionCode));
                        registeredObserver.execute(versionedPkg);
                    }
                }
            }
        });
    }

    @Nullable
    private VersionedPackage getVersionedPackage(String packageName) {
        final PackageManager pm = mContext.getPackageManager();
        if (pm == null) {
            return null;
        }
        try {
            final long versionCode = pm.getPackageInfo(
                    packageName, 0 /* flags */).getLongVersionCode();
            return new VersionedPackage(packageName, versionCode);
        } catch (PackageManager.NameNotFoundException e) {
            return null;
        }
    }

    /**
     * Loads mAllObservers from file.
     *
@@ -726,6 +743,27 @@ public class PackageWatchdog {
        }
    }

    private void registerNetworkStackHealthListener() {
        // TODO: have an internal method to trigger a rollback by reporting high severity errors,
        // and rely on ActivityManager to inform the watchdog of severe network stack crashes
        // instead of having this listener in parallel.
        mNetworkStackClient.registerHealthListener(
                packageName -> {
                    final VersionedPackage pkg = getVersionedPackage(packageName);
                    if (pkg == null) {
                        Slog.wtf(TAG, "NetworkStack failed but could not find its package");
                        return;
                    }
                    // This is a severe failure and recovery should be attempted immediately.
                    // TODO: have a better way to handle such failures.
                    final List<VersionedPackage> pkgList = Collections.singletonList(pkg);
                    final long failureCount = getTriggerFailureCount();
                    for (int i = 0; i < failureCount; i++) {
                        onPackageFailure(pkgList);
                    }
                });
    }

    /**
     * Persists mAllObservers to file. Threshold information is ignored.
     */
+115 −14
Original line number Diff line number Diff line
@@ -26,22 +26,27 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.IDhcpServerCallbacks;
import android.net.ip.IIpClientCallbacks;
import android.net.util.SharedLog;
import android.os.Binder;
import android.os.Build;
import android.os.Environment;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.util.ArraySet;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;

import java.io.File;
import java.io.PrintWriter;
import java.util.ArrayList;

@@ -54,6 +59,15 @@ public class NetworkStackClient {

    private static final int NETWORKSTACK_TIMEOUT_MS = 10_000;
    private static final String IN_PROCESS_SUFFIX = ".InProcess";
    private static final String PREFS_FILE = "NetworkStackClientPrefs.xml";
    private static final String PREF_KEY_LAST_CRASH_UPTIME = "lastcrash";
    private static final String CONFIG_MIN_CRASH_INTERVAL_MS = "min_crash_interval";

    // Even if the network stack is lost, do not crash the system more often than this.
    // Connectivity would be broken, but if the user needs the device for something urgent
    // (like calling emergency services) we should not bootloop the device.
    // This is the default value: the actual value can be adjusted via device config.
    private static final long DEFAULT_MIN_CRASH_INTERVAL_MS = 6 * 3_600_000L;

    private static NetworkStackClient sInstance;

@@ -67,12 +81,34 @@ public class NetworkStackClient {
    @GuardedBy("mLog")
    private final SharedLog mLog = new SharedLog(TAG);

    private volatile boolean mNetworkStackStartRequested = false;
    private volatile boolean mWasSystemServerInitialized = false;

    /**
     * If non-zero, indicates that the last framework start happened after a crash of the
     * NetworkStack which was at the specified uptime.
     */
    private volatile long mLastCrashUptime = 0L;

    @GuardedBy("mHealthListeners")
    private final ArraySet<NetworkStackHealthListener> mHealthListeners = new ArraySet<>();

    private interface NetworkStackCallback {
        void onNetworkStackConnected(INetworkStackConnector connector);
    }

    /**
     * Callback interface for severe failures of the NetworkStack.
     *
     * <p>Useful for health monitors such as PackageWatchdog.
     */
    public interface NetworkStackHealthListener {
        /**
         * Called when there is a severe failure of the network stack.
         * @param packageName Package name of the network stack.
         */
        void onNetworkStackFailure(@NonNull String packageName);
    }

    private NetworkStackClient() { }

    /**
@@ -85,6 +121,15 @@ public class NetworkStackClient {
        return sInstance;
    }

    /**
     * Add a {@link NetworkStackHealthListener} to listen to network stack health events.
     */
    public void registerHealthListener(@NonNull NetworkStackHealthListener listener) {
        synchronized (mHealthListeners) {
            mHealthListeners.add(listener);
        }
    }

    /**
     * Create a DHCP server according to the specified parameters.
     *
@@ -147,6 +192,16 @@ public class NetworkStackClient {
    }

    private class NetworkStackConnection implements ServiceConnection {
        @NonNull
        private final Context mContext;
        @NonNull
        private final String mPackageName;

        private NetworkStackConnection(@NonNull Context context, @NonNull String packageName) {
            mContext = context;
            mPackageName = packageName;
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            logi("Network stack service connected");
@@ -155,14 +210,14 @@ public class NetworkStackClient {

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // The system has lost its network stack (probably due to a crash in the
            // network stack process): better crash rather than stay in a bad state where all
            // networking is broken.
            // onServiceDisconnected is not being called on device shutdown, so this method being
            // called always indicates a bad state for the system server.
            maybeCrashWithTerribleFailure("Lost network stack");
            // This code path is only run by the system server: only the system server binds
            // to the NetworkStack as a service. Other processes get the NetworkStack from
            // the ServiceManager.
            maybeCrashWithTerribleFailure("Lost network stack", mContext, mPackageName);
        }
    }
    };

    private void registerNetworkStackService(@NonNull IBinder service) {
        final INetworkStackConnector connector = INetworkStackConnector.Stub.asInterface(service);
@@ -189,7 +244,7 @@ public class NetworkStackClient {
     */
    public void init() {
        log("Network stack init");
        mNetworkStackStartRequested = true;
        mWasSystemServerInitialized = true;
    }

    /**
@@ -202,6 +257,13 @@ public class NetworkStackClient {
     */
    public void start(Context context) {
        log("Starting network stack");

        final SharedPreferences prefs = getSharedPreferences(context);
        mLastCrashUptime = prefs.getLong(PREF_KEY_LAST_CRASH_UPTIME, 0L);
        // Remove the preference after getting the last crash uptime, so mLastCrashUptime always
        // indicates this is the first start since the last crash.
        prefs.edit().remove(PREF_KEY_LAST_CRASH_UPTIME).commit();

        final PackageManager pm = context.getPackageManager();

        // Try to bind in-process if the device was shipped with an in-process version
@@ -216,16 +278,19 @@ public class NetworkStackClient {
        }

        if (intent == null) {
            maybeCrashWithTerribleFailure("Could not resolve the network stack");
            maybeCrashWithTerribleFailure("Could not resolve the network stack", context, null);
            return;
        }

        final String packageName = intent.getComponent().getPackageName();

        // Start the network stack. The service will be added to the service manager in
        // NetworkStackConnection.onServiceConnected().
        if (!context.bindServiceAsUser(intent, new NetworkStackConnection(),
        if (!context.bindServiceAsUser(intent, new NetworkStackConnection(context, packageName),
                Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
            maybeCrashWithTerribleFailure(
                    "Could not bind to network stack in-process, or in app with " + intent);
                    "Could not bind to network stack in-process, or in app with " + intent,
                    context, packageName);
            return;
        }

@@ -274,11 +339,47 @@ public class NetworkStackClient {
        }
    }

    private void maybeCrashWithTerribleFailure(@NonNull String message) {
    private void maybeCrashWithTerribleFailure(@NonNull String message,
            @NonNull Context context, @Nullable String packageName) {
        logWtf(message, null);
        if (Build.IS_DEBUGGABLE) {
        // uptime is monotonic even after a framework restart
        final long uptime = SystemClock.elapsedRealtime();
        final long minCrashIntervalMs = DeviceConfig.getLong(DeviceConfig.NAMESPACE_CONNECTIVITY,
                CONFIG_MIN_CRASH_INTERVAL_MS, DEFAULT_MIN_CRASH_INTERVAL_MS);

        // Either the framework was not restarted after a crash of the NetworkStack, or the min
        // crash interval has passed since then.
        if (mLastCrashUptime == 0L || uptime - mLastCrashUptime > minCrashIntervalMs) {
            // The system is not bound to its network stack (for example due to a crash in the
            // network stack process): better crash rather than stay in a bad state where all
            // networking is broken.
            // Using device-encrypted SharedPreferences as DeviceConfig does not have a synchronous
            // API to persist settings before a crash.
            final SharedPreferences prefs = getSharedPreferences(context);
            if (!prefs.edit().putLong(PREF_KEY_LAST_CRASH_UPTIME, uptime).commit()) {
                logWtf("Could not persist last crash uptime", null);
            }
            throw new IllegalStateException(message);
        }

        // Here the system crashed recently already. Inform listeners that something is
        // definitely wrong.
        if (packageName != null) {
            final ArraySet<NetworkStackHealthListener> listeners;
            synchronized (mHealthListeners) {
                listeners = new ArraySet<>(mHealthListeners);
            }
            for (NetworkStackHealthListener listener : listeners) {
                listener.onNetworkStackFailure(packageName);
            }
        }
    }

    private SharedPreferences getSharedPreferences(Context context) {
        final File prefsFile = new File(
                Environment.getDataSystemDeDirectory(UserHandle.USER_SYSTEM), PREFS_FILE);
        return context.createDeviceProtectedStorageContext()
                .getSharedPreferences(prefsFile, Context.MODE_PRIVATE);
    }

    /**
@@ -350,7 +451,7 @@ public class NetworkStackClient {
                    "Only the system server should try to bind to the network stack.");
        }

        if (!mNetworkStackStartRequested) {
        if (!mWasSystemServerInitialized) {
            // The network stack is not being started in this process, e.g. this process is not
            // the system server. Get a remote connector registered by the system server.
            final INetworkStackConnector connector = getRemoteConnector();
+7 −0
Original line number Diff line number Diff line
@@ -18,11 +18,18 @@ android_test {
    srcs: ["src/**/*.java"],
    static_libs: [
        "junit",
        "mockito-target-extended-minus-junit4",
        "frameworks-base-testutils",
        "androidx.test.rules",
        "services.core",
        "services.net",
    ],
    libs: ["android.test.runner"],
    jni_libs: [
        // mockito-target-extended dependencies
        "libdexmakerjvmtiagent",
        "libstaticjvmtiagent",
    ],
    platform_apis: true,
    test_suites: ["device-tests"],
}
+8 −1
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import static org.junit.Assert.fail;
import android.Manifest;
import android.content.Context;
import android.content.pm.VersionedPackage;
import android.net.NetworkStackClient;
import android.os.Handler;
import android.os.test.TestLooper;
import android.provider.DeviceConfig;
@@ -41,6 +42,8 @@ import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.io.File;
import java.util.ArrayList;
@@ -70,9 +73,12 @@ public class PackageWatchdogTest {
    private static final long SHORT_DURATION = TimeUnit.SECONDS.toMillis(1);
    private static final long LONG_DURATION = TimeUnit.SECONDS.toMillis(5);
    private TestLooper mTestLooper;
    @Mock
    private NetworkStackClient mNetworkStackClient;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        new File(InstrumentationRegistry.getContext().getFilesDir(),
                "package-watchdog.xml").delete();
        adoptShellPermissions(Manifest.permission.READ_DEVICE_CONFIG);
@@ -732,7 +738,8 @@ public class PackageWatchdogTest {
                new AtomicFile(new File(context.getFilesDir(), "package-watchdog.xml"));
        Handler handler = new Handler(mTestLooper.getLooper());
        PackageWatchdog watchdog =
                new PackageWatchdog(context, policyFile, handler, handler, controller);
                new PackageWatchdog(context, policyFile, handler, handler, controller,
                        mNetworkStackClient);
        // Verify controller is not automatically started
        assertFalse(controller.mIsEnabled);
        if (withPackagesReady) {