Snap for 8730993 from 390bbe4f067c8d115dac5bb40976f96aa9a42d66 to mainline-tzdata3-release
Change-Id: Ic379a4e97648a1b68b2777b6574dc9f3e64cbe10
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index b61e3aa..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,10 +0,0 @@
-*~
-.project
-.classpath
-*.iml
-gen/
-*.pyc
-*.swp
-__pycache__
-.idea
-/bin/
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..d26195e
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,35 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_library {
+ name: "car-frameworks-service",
+ installable: true,
+ libs: [
+ "services",
+ "android.hardware.automotive.vehicle-V2.0-java",
+ "com.android.car.internal.common",
+ ],
+ required: ["libcar-framework-service-jni"],
+ srcs: [
+ "src/**/*.java",
+ ],
+ static_libs: [
+ "android.car.watchdoglib",
+ "com.android.car.internal.system",
+ "android.automotive.watchdog.internal-java",
+ ],
+}
+
+cc_library_shared {
+ name: "libcar-framework-service-jni",
+ shared_libs: [
+ "libandroid_runtime",
+ "libhidlbase",
+ "liblog",
+ "libnativehelper",
+ "libsuspend",
+ "libutils",
+ ],
+ srcs: ["src/jni/com_android_internal_car_CarServiceHelperService.cpp"],
+}
diff --git a/builtInServices/PREUPLOAD.cfg b/PREUPLOAD.cfg
similarity index 100%
rename from builtInServices/PREUPLOAD.cfg
rename to PREUPLOAD.cfg
diff --git a/builtInServices/Android.bp b/builtInServices/Android.bp
deleted file mode 100644
index eeda2da..0000000
--- a/builtInServices/Android.bp
+++ /dev/null
@@ -1,43 +0,0 @@
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-java_sdk_library {
- name: "car-frameworks-service",
- libs: [
- "services",
- "android.car",
- "android.car.builtin", // Will remove once split is complete
- "android.hardware.automotive.vehicle-V2.0-java",
- ],
- srcs: [
- "src/**/*.java",
- ],
- static_libs: [
- "android.car.watchdoglib",
- "android.automotive.watchdog.internal-V1-java",
- ],
- api_lint: {
- enabled: true,
- },
-
- min_sdk_version: "33",
- apex_available: [
- "//apex_available:platform",
- "com.android.car.framework"
- ],
-
- unsafe_ignore_missing_latest_api: true,
-
- test: {
- enabled: false,
- },
- system: {
- enabled: true,
- sdk_version: "module_current",
- },
- module_lib: {
- enabled: true,
- sdk_version: "module_current",
- },
-}
diff --git a/builtInServices/TEST_MAPPING b/builtInServices/TEST_MAPPING
deleted file mode 100644
index 2832b34..0000000
--- a/builtInServices/TEST_MAPPING
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "auto-presubmit": [
- {
- "name": "CarServiceCrashDumpTest"
- },
- {
- "name": "FrameworkOptCarServicesTest"
- }
- ]
-}
diff --git a/builtInServices/api/current.txt b/builtInServices/api/current.txt
deleted file mode 100644
index d802177..0000000
--- a/builtInServices/api/current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/builtInServices/api/module-lib-current.txt b/builtInServices/api/module-lib-current.txt
deleted file mode 100644
index ddf15cf..0000000
--- a/builtInServices/api/module-lib-current.txt
+++ /dev/null
@@ -1,96 +0,0 @@
-// Signature format: 2.0
-package com.android.internal.car {
-
- public interface CarServiceHelperInterface {
- method @Nullable public android.os.UserHandle createUserEvenWhenDisallowed(@Nullable String, @NonNull String, int);
- method @Nullable public java.io.File dumpServiceStacks();
- method public void setSafetyMode(boolean);
- }
-
- public interface CarServiceHelperServiceUpdatable {
- method public void dump(@NonNull java.io.PrintWriter, @Nullable String[]);
- method public com.android.server.wm.CarLaunchParamsModifierUpdatable getCarLaunchParamsModifierUpdatable();
- method public void initBootUser();
- method public void onFactoryReset(@NonNull java.util.function.BiConsumer<java.lang.Integer,android.os.Bundle>);
- method public void onStart();
- method public void onUserRemoved(@NonNull android.os.UserHandle);
- method public void sendUserLifecycleEvent(int, @Nullable android.os.UserHandle, @NonNull android.os.UserHandle);
- }
-
-}
-
-package com.android.server.wm {
-
- public final class ActivityOptionsWrapper {
- method public com.android.server.wm.TaskDisplayAreaWrapper getLaunchTaskDisplayArea();
- method public android.app.ActivityOptions getOptions();
- }
-
- public final class ActivityRecordWrapper {
- method public boolean allowingEmbedded();
- method public android.content.ComponentName getComponentName();
- method public com.android.server.wm.TaskDisplayAreaWrapper getDisplayArea();
- method public int getHandoverLaunchDisplayId();
- method public com.android.server.wm.TaskDisplayAreaWrapper getHandoverTaskDisplayArea();
- method public int getUserId();
- method public boolean isDisplayTrusted();
- method public boolean isNoDisplay();
- }
-
- public final class CalculateParams {
- method public com.android.server.wm.ActivityRecordWrapper getActivity();
- method public com.android.server.wm.LaunchParamsWrapper getCurrentParams();
- method public com.android.server.wm.ActivityOptionsWrapper getOptions();
- method public com.android.server.wm.LaunchParamsWrapper getOutParams();
- method public int getPhase();
- method public com.android.server.wm.RequestWrapper getRequest();
- method public com.android.server.wm.ActivityRecordWrapper getSource();
- method public com.android.server.wm.TaskWrapper getTask();
- method public com.android.server.wm.WindowLayoutWrapper getWindowLayout();
- method public boolean supportsMultiDisplay();
- }
-
- public interface CarLaunchParamsModifierInterface {
- method @Nullable public com.android.server.wm.TaskDisplayAreaWrapper findTaskDisplayArea(int, int);
- method @Nullable public com.android.server.wm.TaskDisplayAreaWrapper getDefaultTaskDisplayAreaOnDisplay(int);
- method @NonNull public java.util.List<com.android.server.wm.TaskDisplayAreaWrapper> getFallbackDisplayAreasForActivity(@NonNull com.android.server.wm.ActivityRecordWrapper, @Nullable com.android.server.wm.RequestWrapper);
- }
-
- public interface CarLaunchParamsModifierUpdatable {
- method public int calculate(com.android.server.wm.CalculateParams);
- method public android.hardware.display.DisplayManager.DisplayListener getDisplayListener();
- method public void handleCurrentUserSwitching(int);
- method public void handleUserStarting(int);
- method public void handleUserStopped(int);
- }
-
- public final class LaunchParamsWrapper {
- method public android.graphics.Rect getBounds();
- method public com.android.server.wm.TaskDisplayAreaWrapper getPreferredTaskDisplayArea();
- method public int getWindowingMode();
- method public void setBounds(android.graphics.Rect);
- method public void setPreferredTaskDisplayArea(com.android.server.wm.TaskDisplayAreaWrapper);
- method public void setWindowingMode(int);
- field public static int RESULT_CONTINUE;
- field public static int RESULT_DONE;
- field public static int RESULT_SKIP;
- }
-
- public final class RequestWrapper {
- }
-
- public final class TaskDisplayAreaWrapper {
- method public android.view.Display getDisplay();
- }
-
- public final class TaskWrapper {
- method public com.android.server.wm.TaskWrapper getRootTask();
- method public com.android.server.wm.TaskDisplayAreaWrapper getTaskDisplayArea();
- method public int getUserId();
- }
-
- public final class WindowLayoutWrapper {
- }
-
-}
-
diff --git a/builtInServices/api/module-lib-removed.txt b/builtInServices/api/module-lib-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/builtInServices/api/module-lib-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/builtInServices/api/removed.txt b/builtInServices/api/removed.txt
deleted file mode 100644
index d802177..0000000
--- a/builtInServices/api/removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/builtInServices/api/system-current.txt b/builtInServices/api/system-current.txt
deleted file mode 100644
index d802177..0000000
--- a/builtInServices/api/system-current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/builtInServices/api/system-removed.txt b/builtInServices/api/system-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/builtInServices/api/system-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/builtInServices/api/test-current.txt b/builtInServices/api/test-current.txt
deleted file mode 100644
index d802177..0000000
--- a/builtInServices/api/test-current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/builtInServices/api/test-removed.txt b/builtInServices/api/test-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/builtInServices/api/test-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/builtInServices/host_tests/Android.bp b/builtInServices/host_tests/Android.bp
deleted file mode 100644
index 9d68572..0000000
--- a/builtInServices/host_tests/Android.bp
+++ /dev/null
@@ -1,14 +0,0 @@
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-java_test_host {
- name: "CarServiceCrashDumpTest",
- srcs: ["src/**/CarServiceCrashDumpTest.java"],
- libs: [
- "compatibility-host-util",
- "junit",
- "tradefed",
- "truth-prebuilt",
- ],
-}
diff --git a/builtInServices/host_tests/src/com/android/internal/car/test/CarServiceCrashDumpTest.java b/builtInServices/host_tests/src/com/android/internal/car/test/CarServiceCrashDumpTest.java
deleted file mode 100644
index bf19a3c..0000000
--- a/builtInServices/host_tests/src/com/android/internal/car/test/CarServiceCrashDumpTest.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2021 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.internal.car.test;
-
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import com.android.compatibility.common.util.CommonTestUtils;
-import com.android.compatibility.common.util.PollingCheck;
-import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-
-import static org.junit.Assume.assumeTrue;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
-
-@RunWith(DeviceJUnit4ClassRunner.class)
-public final class CarServiceCrashDumpTest extends BaseHostJUnit4Test {
- private static final int DEFAULT_TIMEOUT_SEC = 20;
- private static final long POLL_TIMEOUT_MS = 20000;
- private static final String BUILD_TYPE_PROPERTY = "ro.build.type";
-
- // This must be in sync with WatchDog lib.
- private static final List<String> HAL_INTERFACES_OF_INTEREST = Arrays.asList(
- "android.hardware.audio@4.0::IDevicesFactory",
- "android.hardware.audio@5.0::IDevicesFactory",
- "android.hardware.audio@6.0::IDevicesFactory",
- "android.hardware.audio@7.0::IDevicesFactory",
- "android.hardware.biometrics.face@1.0::IBiometricsFace",
- "android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint",
- "android.hardware.bluetooth@1.0::IBluetoothHci",
- "android.hardware.camera.provider@2.4::ICameraProvider",
- "android.hardware.gnss@1.0::IGnss",
- "android.hardware.graphics.allocator@2.0::IAllocator",
- "android.hardware.graphics.composer@2.1::IComposer",
- "android.hardware.health@2.0::IHealth",
- "android.hardware.light@2.0::ILight",
- "android.hardware.media.c2@1.0::IComponentStore",
- "android.hardware.media.omx@1.0::IOmx",
- "android.hardware.media.omx@1.0::IOmxStore",
- "android.hardware.neuralnetworks@1.0::IDevice",
- "android.hardware.power.stats@1.0::IPowerStats",
- "android.hardware.sensors@1.0::ISensors",
- "android.hardware.sensors@2.0::ISensors",
- "android.hardware.sensors@2.1::ISensors",
- "android.hardware.vr@1.0::IVr",
- "android.system.suspend@1.0::ISystemSuspend"
- );
-
- // Which native processes to dump into dropbox's stack traces, must be in sync with Watchdog
- // lib.
- private static final String[] NATIVE_STACKS_OF_INTEREST = new String[] {
- "/system/bin/audioserver",
- "/system/bin/cameraserver",
- "/system/bin/drmserver",
- "/system/bin/keystore2",
- "/system/bin/mediadrmserver",
- "/system/bin/mediaserver",
- "/system/bin/netd",
- "/system/bin/sdcard",
- "/system/bin/surfaceflinger",
- "/system/bin/vold",
- "media.extractor", // system/bin/mediaextractor
- "media.metrics", // system/bin/mediametrics
- "media.codec", // vendor/bin/hw/android.hardware.media.omx@1.0-service
- "media.swcodec", // /apex/com.android.media.swcodec/bin/mediaswcodec
- "media.transcoding", // Media transcoding service
- "com.android.bluetooth", // Bluetooth service
- "/apex/com.android.os.statsd/bin/statsd", // Stats daemon
- };
-
- /**
- * Executes the shell command and returns the output.
- */
- private String executeCommand(String command, Object... args) throws Exception {
- String fullCommand = String.format(command, args);
- return getDevice().executeShellCommand(fullCommand);
- }
-
- /**
- * Waits until the car service is ready.
- */
- private void waitForCarServiceReady() throws Exception {
- CommonTestUtils.waitUntil("timed out waiting for car service ",
- DEFAULT_TIMEOUT_SEC, () -> isCarServiceReady());
- }
-
- private boolean isCarServiceReady() {
- String cmd = "service check car_service";
- try {
- String output = getDevice().executeShellCommand(cmd).strip();
- return !output.endsWith("not found");
- } catch (Exception e) {
- CLog.w("%s failed: %s", cmd, e.getMessage());
- }
- return false;
- }
-
- @Before
- public void setUp() throws Exception {
- executeCommand("logcat -c");
- }
-
- /**
- * Read the content of the dumped file.
- */
- private String getDumpFile() throws Exception {
- AtomicReference<String> log = new AtomicReference<>();
- String dumpString = "ActivityManager: Dumping to ";
- String doneDumpingString = "ActivityManager: Done dumping";
- PollingCheck.check("dumpStackTrace not found in log", POLL_TIMEOUT_MS, () -> {
- String logString = executeCommand("logcat -d");
- if (logString.contains("ActivityManager: dumpStackTraces") && logString.contains(
- dumpString) && logString.contains(doneDumpingString)) {
- log.set(logString);
- return true;
- }
- return false;
- });
- String logString = log.get();
- int start = logString.indexOf(dumpString) + dumpString.length();
- int end = logString.indexOf("\n", start);
- if (end == -1) {
- end = logString.length();
- }
- return logString.substring(start, end);
- }
-
- /**
- * Get a list of PIDs for the interesting HALs that would be dumped.
- */
- private List<String> getHalPids() throws Exception {
- String lshalResult = executeCommand("lshal -i -p");
- List<String> pids = new ArrayList<String>();
- int i = 0;
- for (String line: lshalResult.split("\n")) {
- line = line.strip();
- if (line.equals("")) {
- // When we see an empty line, we stops the parsing.
- break;
- }
- if (i < 2) {
- // Skip the first two lines
- i++;
- continue;
- }
- String[] fields = line.split("\\s+");
- for (String interestHal: HAL_INTERFACES_OF_INTEREST) {
- if (fields[0].contains(interestHal)) {
- pids.add(fields[1]);
- break;
- }
- }
- i++;
- }
- return pids;
- }
-
- /**
- * Get a list of PIDs for the native services that would be dumped.
- */
- private List<String> getNativePids() throws Exception {
- List<String> pids = new ArrayList<String>();
- for (String name: NATIVE_STACKS_OF_INTEREST) {
- String pid = executeCommand(String.format("pidof %s", name)).strip();
- if (!pid.equals("")) {
- pids.add(pid);
- }
- }
- return pids;
- }
-
- @Test
- public void testCarServiceCrashDump() throws Exception {
- String buildType = getDevice().getProperty("ro.build.type");
- // Only run on userdebug devices.
- assumeTrue(buildType.equals("userdebug") || buildType.equals("eng"));
-
- List<String> pids = new ArrayList<String>();
-
- getDevice().enableAdbRoot();
-
- String systemServerPid = executeCommand(String.format("pidof %s", "system_server")).strip();
- assertWithMessage("system_service pid not empty").that(systemServerPid).isNotEmpty();
- pids.add(systemServerPid);
-
- List<String> halPids = getHalPids();
- pids.addAll(halPids);
- assertWithMessage("hal pids").that(halPids.size() > 0).isTrue();
-
- List<String> nativePids = getNativePids();
- pids.addAll(nativePids);
- assertWithMessage("native pids").that(nativePids.size() > 0).isTrue();
-
- executeCommand("am crash --user 0 com.android.car");
-
- String dumpFile = getDumpFile();
- assertWithMessage("dump file").that(dumpFile).isNotEmpty();
-
- String grepResult = executeCommand("cat %s", dumpFile);
-
- assertWithMessage("dumped content not empty").that(grepResult)
- .isNotEmpty();
-
- for (String pid : pids) {
- assertWithMessage("dumped content contains interesting pid").that(grepResult)
- .contains(String.format("----- pid %s at", pid));
- }
- }
-
- @After
- public void tearDown() throws Exception {
- waitForCarServiceReady();
- }
-}
diff --git a/builtInServices/src/com/android/internal/car/CarServiceHelperInterface.java b/builtInServices/src/com/android/internal/car/CarServiceHelperInterface.java
deleted file mode 100644
index 362fd07..0000000
--- a/builtInServices/src/com/android/internal/car/CarServiceHelperInterface.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2021 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.internal.car;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.os.UserHandle;
-
-import java.io.File;
-
-/**
- * Interface implemented by CarServiceHelperService.
- * @hide
- */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public interface CarServiceHelperInterface {
-
- /**
- * Sets safety mode
- */
- void setSafetyMode(boolean safe);
-
- /**
- * Creates user even when disallowed
- */
- @Nullable
- UserHandle createUserEvenWhenDisallowed(@Nullable String name, @NonNull String userType,
- int flags);
-
- /**
- * Dumps service stacks
- */
- @Nullable
- File dumpServiceStacks();
-}
diff --git a/builtInServices/src/com/android/internal/car/CarServiceHelperService.java b/builtInServices/src/com/android/internal/car/CarServiceHelperService.java
deleted file mode 100644
index 4e2333c..0000000
--- a/builtInServices/src/com/android/internal/car/CarServiceHelperService.java
+++ /dev/null
@@ -1,743 +0,0 @@
-/*
- * Copyright (C) 2017 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.internal.car;
-
-import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED;
-import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STARTING;
-import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
-import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STOPPING;
-import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
-import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED;
-import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING;
-import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.admin.DevicePolicyManager;
-import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
-import android.app.admin.DevicePolicyManager.OperationSafetyReason;
-import android.app.admin.DevicePolicySafetyChecker;
-import android.automotive.watchdog.internal.ICarWatchdogMonitor;
-import android.automotive.watchdog.internal.ProcessIdentifier;
-import android.automotive.watchdog.internal.StateType;
-import android.car.builtin.util.EventLogHelper;
-import android.car.watchdoglib.CarWatchdogDaemonHelper;
-import android.content.Context;
-import android.content.pm.UserInfo;
-import android.hidl.manager.V1_0.IServiceManager;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.Trace;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.system.Os;
-import android.system.OsConstants;
-import android.util.Dumpable;
-import android.util.TimeUtils;
-
-import com.android.car.internal.common.CommonConstants.UserLifecycleEventType;
-import com.android.car.internal.common.UserHelperLite;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.IResultReceiver;
-import com.android.server.LocalServices;
-import com.android.server.SystemService;
-import com.android.server.Watchdog;
-import com.android.server.am.ActivityManagerService;
-import com.android.server.pm.UserManagerInternal;
-import com.android.server.pm.UserManagerInternal.UserLifecycleListener;
-import com.android.server.utils.Slogf;
-import com.android.server.utils.TimingsTraceAndSlog;
-import com.android.server.wm.CarLaunchParamsModifier;
-import com.android.server.wm.CarLaunchParamsModifierInterface;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * System service side companion service for CarService. Starts car service and provide necessary
- * API for CarService. Only for car product.
- *
- * @hide
- */
-public class CarServiceHelperService extends SystemService
- implements Dumpable, DevicePolicySafetyChecker, CarServiceHelperInterface {
-
- @VisibleForTesting
- static final String TAG = "CarServiceHelper";
-
- // TODO(b/154033860): STOPSHIP if they're still true
- private static final boolean DBG = true;
- private static final boolean VERBOSE = true;
-
- private static final List<String> CAR_HAL_INTERFACES_OF_INTEREST = Arrays.asList(
- "android.hardware.automotive.vehicle@2.0::IVehicle",
- "android.hardware.automotive.audiocontrol@1.0::IAudioControl",
- "android.hardware.automotive.audiocontrol@2.0::IAudioControl"
- );
-
- // Message ID representing post-processing of process dumping.
- private static final int WHAT_POST_PROCESS_DUMPING = 1;
- // Message ID representing process killing.
- private static final int WHAT_PROCESS_KILL = 2;
-
- private static final String CSHS_UPDATABLE_CLASSNAME_STRING =
- "com.android.internal.car.updatable.CarServiceHelperServiceUpdatableImpl";
- private static final String PROC_PID_STAT_PATTERN =
- "(?<pid>[0-9]*)\\s\\((?<name>\\S+)\\)\\s\\S\\s(?:-?[0-9]*\\s){18}"
- + "(?<startClockTicks>[0-9]*)\\s(?:-?[0-9]*\\s)*-?[0-9]*";
-
- private final Context mContext;
- private final Object mLock = new Object();
- @GuardedBy("mLock")
- private boolean mSystemBootCompleted;
-
- private final CarLaunchParamsModifier mCarLaunchParamsModifier;
-
- private final Handler mHandler;
- private final HandlerThread mHandlerThread = new HandlerThread("CarServiceHelperService");
-
- private final ProcessTerminator mProcessTerminator = new ProcessTerminator();
-
- private final Pattern mProcPidStatPattern = Pattern.compile(PROC_PID_STAT_PATTERN);
-
- private final CarWatchdogDaemonHelper mCarWatchdogDaemonHelper;
- private final ICarWatchdogMonitorImpl mCarWatchdogMonitor = new ICarWatchdogMonitorImpl(this);
- private final CarWatchdogDaemonHelper.OnConnectionChangeListener mConnectionListener =
- (connected) -> {
- if (connected) {
- registerMonitorToWatchdogDaemon();
- }
- };
-
- private final CarDevicePolicySafetyChecker mCarDevicePolicySafetyChecker;
-
- private CarServiceHelperServiceUpdatable mCarServiceHelperServiceUpdatable;
-
- /**
- * End-to-end time (from process start) for unlocking the first non-system user.
- */
- private long mFirstUnlockedUserDuration;
-
- public CarServiceHelperService(Context context) {
- this(context,
- new CarLaunchParamsModifier(context),
- new CarWatchdogDaemonHelper(TAG),
- /* carServiceHelperServiceUpdatable= */ null,
- /* carDevicePolicySafetyChecker= */ null
- );
- }
-
- @VisibleForTesting
- CarServiceHelperService(
- Context context,
- CarLaunchParamsModifier carLaunchParamsModifier,
- CarWatchdogDaemonHelper carWatchdogDaemonHelper,
- @Nullable CarServiceHelperServiceUpdatable carServiceHelperServiceUpdatable,
- @Nullable CarDevicePolicySafetyChecker carDevicePolicySafetyChecker) {
- super(context);
-
- mContext = context;
- mHandlerThread.start();
- mHandler = new Handler(mHandlerThread.getLooper());
- mCarLaunchParamsModifier = carLaunchParamsModifier;
- mCarWatchdogDaemonHelper = carWatchdogDaemonHelper;
- try {
- if (carServiceHelperServiceUpdatable == null) {
- mCarServiceHelperServiceUpdatable = (CarServiceHelperServiceUpdatable) Class
- .forName(CSHS_UPDATABLE_CLASSNAME_STRING)
- .getConstructor(Context.class, CarServiceHelperInterface.class,
- CarLaunchParamsModifierInterface.class)
- .newInstance(mContext, this,
- mCarLaunchParamsModifier.getBuiltinInterface());
- Slogf.d(TAG, "CarServiceHelperServiceUpdatable created via reflection.");
- } else {
- mCarServiceHelperServiceUpdatable = carServiceHelperServiceUpdatable;
- }
- } catch (Exception e) {
- // TODO(b/190458000): Define recovery mechanism.
- // can't create the CarServiceHelperServiceUpdatable object
- // crash the process
- Slogf.w(TAG, e, "*** CARHELPER KILLING SYSTEM PROCESS: "
- + "Can't create CarServiceHelperServiceUpdatable.");
- Slogf.w(TAG, "*** GOODBYE!");
- Process.killProcess(Process.myPid());
- System.exit(10);
- }
- mCarLaunchParamsModifier.setUpdatable(
- mCarServiceHelperServiceUpdatable.getCarLaunchParamsModifierUpdatable());
-
- UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
- if (umi != null) {
- umi.addUserLifecycleListener(new UserLifecycleListener() {
- @Override
- public void onUserCreated(UserInfo user, Object token) {
- if (DBG) Slogf.d(TAG, "onUserCreated(): %s", user.toFullString());
- }
- @Override
- public void onUserRemoved(UserInfo user) {
- if (DBG) Slogf.d(TAG, "onUserRemoved(): $s", user.toFullString());
- mCarServiceHelperServiceUpdatable.onUserRemoved(user.getUserHandle());
- }
- });
- } else {
- Slogf.e(TAG, "UserManagerInternal not available - should only happen on unit tests");
- }
- mCarDevicePolicySafetyChecker = carDevicePolicySafetyChecker == null
- ? new CarDevicePolicySafetyChecker(this)
- : carDevicePolicySafetyChecker;
- }
-
- @Override
- public void onBootPhase(int phase) {
- EventLogHelper.writeCarHelperBootPhase(phase);
- if (DBG) Slogf.d(TAG, "onBootPhase: %d", phase);
-
- TimingsTraceAndSlog t = newTimingsTraceAndSlog();
- if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
- t.traceBegin("onBootPhase.3pApps");
- mCarLaunchParamsModifier.init();
- setupAndStartUsers(t);
- t.traceEnd();
- } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
- t.traceBegin("onBootPhase.completed");
- synchronized (mLock) {
- mSystemBootCompleted = true;
- }
- try {
- mCarWatchdogDaemonHelper.notifySystemStateChange(
- StateType.BOOT_PHASE, phase, /* arg2= */ 0);
- } catch (RemoteException | RuntimeException e) {
- Slogf.w(TAG, "Failed to notify boot phase change: %s", e);
- }
- t.traceEnd();
- }
- }
-
- @Override
- public void onStart() {
- EventLogHelper.writeCarHelperStart();
-
- mCarWatchdogDaemonHelper.addOnConnectionChangeListener(mConnectionListener);
- mCarWatchdogDaemonHelper.connect();
- mCarServiceHelperServiceUpdatable.onStart();
- }
-
- @Override
- public void dump(PrintWriter pw, String[] args) {
- // Usage: adb shell dumpsys system_server_dumper --name CarServiceHelper
- if (args == null || args.length == 0 || args[0].equals("-a")) {
- pw.printf("System boot completed: %b\n", mSystemBootCompleted);
- pw.print("First unlocked user duration: ");
- TimeUtils.formatDuration(mFirstUnlockedUserDuration, pw); pw.println();
- pw.printf("Queued tasks: %d\n", mProcessTerminator.mQueuedTask);
- mCarServiceHelperServiceUpdatable.dump(pw, args);
- mCarDevicePolicySafetyChecker.dump(pw);
- return;
- }
-
- if ("--is-operation-safe".equals(args[0]) & args.length > 1) {
- String arg1 = args[1];
- int operation = 0;
- try {
- operation = Integer.parseInt(arg1);
- } catch (Exception e) {
- pw.printf("Invalid operation type: %s\n", arg1);
- return;
-
- }
- int reason = getUnsafeOperationReason(operation);
- boolean safe = reason == DevicePolicyManager.OPERATION_SAFETY_REASON_NONE;
- pw.printf("Operation %s is %s. Reason: %s\n",
- DevicePolicyManager.operationToString(operation),
- safe ? "SAFE" : "UNSAFE",
- DevicePolicyManager.operationSafetyReasonToString(reason));
- return;
- }
-
- if ("--user-metrics-only".equals(args[0]) || "--dump-service-stacks".equals(args[0])) {
- mCarServiceHelperServiceUpdatable.dump(pw, args);
- return;
- }
-
- pw.printf("Invalid args: %s\n", Arrays.toString(args));
- }
-
- @Override
- public String getDumpableName() {
- return "CarServiceHelper";
- }
-
- @Override
- public void onUserUnlocking(@NonNull TargetUser user) {
- if (isPreCreated(user, USER_LIFECYCLE_EVENT_TYPE_UNLOCKING)) return;
- EventLogHelper.writeCarHelperUserUnlocking(user.getUserIdentifier());
- if (DBG) Slogf.d(TAG, "onUserUnlocking(%s)", user);
-
- mCarServiceHelperServiceUpdatable
- .sendUserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING,
- /* userFrom= */ null, user.getUserHandle());
- }
-
- @Override
- public void onUserUnlocked(@NonNull TargetUser user) {
- if (isPreCreated(user, USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)) return;
- int userId = user.getUserIdentifier();
- EventLogHelper.writeCarHelperUserUnlocked(userId);
- if (DBG) Slogf.d(TAG, "onUserUnlocked(%s)", user);
-
- if (mFirstUnlockedUserDuration == 0 && !UserHelperLite.isHeadlessSystemUser(userId)) {
- mFirstUnlockedUserDuration = SystemClock.elapsedRealtime()
- - Process.getStartElapsedRealtime();
- Slogf.i(TAG, "Time to unlock 1st user(%s): %s", user,
- TimeUtils.formatDuration(mFirstUnlockedUserDuration));
- }
- mCarServiceHelperServiceUpdatable.sendUserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED,
- /* userFrom= */ null, user.getUserHandle());
- }
-
- @Override
- public void onUserStarting(@NonNull TargetUser user) {
- if (isPreCreated(user, USER_LIFECYCLE_EVENT_TYPE_STARTING)) return;
- EventLogHelper.writeCarHelperUserStarting(user.getUserIdentifier());
- if (DBG) Slogf.d(TAG, "onUserStarting(%s)", user);
-
- mCarServiceHelperServiceUpdatable.sendUserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING,
- /* userFrom= */ null, user.getUserHandle());
- int userId = user.getUserIdentifier();
- mCarLaunchParamsModifier.handleUserStarting(userId);
- }
-
- @Override
- public void onUserStopping(@NonNull TargetUser user) {
- if (isPreCreated(user, USER_LIFECYCLE_EVENT_TYPE_STOPPING)) return;
- EventLogHelper.writeCarHelperUserStopping(user.getUserIdentifier());
- if (DBG) Slogf.d(TAG, "onUserStopping(%s)", user);
-
- mCarServiceHelperServiceUpdatable.sendUserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPING,
- /* userFrom= */ null, user.getUserHandle());
- int userId = user.getUserIdentifier();
- mCarLaunchParamsModifier.handleUserStopped(userId);
- }
-
- @Override
- public void onUserStopped(@NonNull TargetUser user) {
- if (isPreCreated(user, USER_LIFECYCLE_EVENT_TYPE_STOPPED)) return;
- EventLogHelper.writeCarHelperUserStopped(user.getUserIdentifier());
- if (DBG) Slogf.d(TAG, "onUserStopped(%s)", user);
-
- mCarServiceHelperServiceUpdatable.sendUserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED,
- /* userFrom= */ null, user.getUserHandle());
- }
-
- @Override
- public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
- if (isPreCreated(to, USER_LIFECYCLE_EVENT_TYPE_SWITCHING)) return;
- EventLogHelper.writeCarHelperUserSwitching(
- from == null ? UserHandle.USER_NULL : from.getUserIdentifier(),
- to.getUserIdentifier());
- if (DBG) Slogf.d(TAG, "onUserSwitching(%s>>%s)", from, to);
-
- mCarServiceHelperServiceUpdatable.sendUserLifecycleEvent(
- USER_LIFECYCLE_EVENT_TYPE_SWITCHING, from.getUserHandle(),
- to.getUserHandle());
- int userId = to.getUserIdentifier();
- mCarLaunchParamsModifier.handleCurrentUserSwitching(userId);
- }
-
- @Override
- public void onUserCompletedEvent(TargetUser user, UserCompletedEventType eventType) {
- if (user.isPreCreated()) {
- if (DBG) {
- Slogf.d(TAG, "Ignoring USER_COMPLETED event %s for pre-created user %s",
- eventType, user);
- }
- return;
- }
-
- UserHandle handle = user.getUserHandle();
- if (eventType.includesOnUserUnlocked()) {
- mCarServiceHelperServiceUpdatable.sendUserLifecycleEvent(
- USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED, /* userFrom= */ null, handle);
- }
- }
-
- @Override // from DevicePolicySafetyChecker
- @OperationSafetyReason
- public int getUnsafeOperationReason(@DevicePolicyOperation int operation) {
- return mCarDevicePolicySafetyChecker.isDevicePolicyOperationSafe(operation)
- ? DevicePolicyManager.OPERATION_SAFETY_REASON_NONE
- : DevicePolicyManager.OPERATION_SAFETY_REASON_DRIVING_DISTRACTION;
- }
-
- @Override // from DevicePolicySafetyChecker
- public boolean isSafeOperation(@OperationSafetyReason int reason) {
- return mCarDevicePolicySafetyChecker.isSafe();
- }
-
- @Override // from DevicePolicySafetyChecker
- public void onFactoryReset(IResultReceiver callback) {
- if (DBG) Slogf.d(TAG, "onFactoryReset: %s", callback);
- if (callback != null) {
- mCarServiceHelperServiceUpdatable.onFactoryReset((resultCode, resultData) -> {
- try {
- callback.send(resultCode, resultData);
- } catch (RemoteException e) {
- Slogf.w(TAG, e,
- "Callback to DevicePolicySafetyChecker threw RemoteException");
- }
- });
- }
- }
-
- private boolean isPreCreated(@NonNull TargetUser user, @UserLifecycleEventType int eventType) {
- if (!user.isPreCreated()) return false;
-
- if (DBG) {
- Slogf.d(TAG, "Ignoring event of type %d for pre-created user %s", eventType, user);
- }
- return true;
- }
-
- private TimingsTraceAndSlog newTimingsTraceAndSlog() {
- return new TimingsTraceAndSlog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
- }
-
- private void setupAndStartUsers(@NonNull TimingsTraceAndSlog t) {
- // TODO(b/156263735): decide if it should return in case the device's on Retail Mode
- t.traceBegin("setupAndStartUsers");
- mCarServiceHelperServiceUpdatable.initBootUser();
- t.traceEnd();
- }
-
- // Adapted from frameworks/base/services/core/java/com/android/server/Watchdog.java
- // TODO(b/131861630) use implementation common with Watchdog.java
- //
- private static ArrayList<Integer> getInterestingHalPids() {
- try {
- IServiceManager serviceManager = IServiceManager.getService();
- ArrayList<IServiceManager.InstanceDebugInfo> dump =
- serviceManager.debugDump();
- HashSet<Integer> pids = new HashSet<>();
- for (IServiceManager.InstanceDebugInfo info : dump) {
- if (info.pid == IServiceManager.PidConstant.NO_PID) {
- continue;
- }
-
- if (Watchdog.HAL_INTERFACES_OF_INTEREST.contains(info.interfaceName) ||
- CAR_HAL_INTERFACES_OF_INTEREST.contains(info.interfaceName)) {
- pids.add(info.pid);
- }
- }
-
- return new ArrayList<Integer>(pids);
- } catch (RemoteException e) {
- return new ArrayList<Integer>();
- }
- }
-
- // Adapted from frameworks/base/services/core/java/com/android/server/Watchdog.java
- // TODO(b/131861630) use implementation common with Watchdog.java
- //
- private static ArrayList<Integer> getInterestingNativePids() {
- ArrayList<Integer> pids = getInterestingHalPids();
-
- int[] nativePids = Process.getPidsForCommands(Watchdog.NATIVE_STACKS_OF_INTEREST);
- if (nativePids != null) {
- pids.ensureCapacity(pids.size() + nativePids.length);
- for (int i : nativePids) {
- pids.add(i);
- }
- }
-
- return pids;
- }
-
- /**
- * Dumps service stack
- */
- // Borrowed from Watchdog.java. Create an ANR file from the call stacks.
- @Override
- @Nullable
- public File dumpServiceStacks() {
- ArrayList<Integer> pids = new ArrayList<>();
- pids.add(Process.myPid());
-
- return ActivityManagerService.dumpStackTraces(
- pids, null, null, getInterestingNativePids(), null);
- }
-
- private void handleClientsNotResponding(@NonNull List<ProcessIdentifier> processIdentifiers) {
- mProcessTerminator.requestTerminateProcess(processIdentifiers);
- }
-
- private void registerMonitorToWatchdogDaemon() {
- try {
- mCarWatchdogDaemonHelper.registerMonitor(mCarWatchdogMonitor);
- synchronized (mLock) {
- if (!mSystemBootCompleted) {
- return;
- }
- }
- mCarWatchdogDaemonHelper.notifySystemStateChange(
- StateType.BOOT_PHASE, SystemService.PHASE_BOOT_COMPLETED, /* arg2= */ 0);
- } catch (RemoteException | RuntimeException e) {
- Slogf.w(TAG, "Cannot register to car watchdog daemon: %s", e);
- }
- }
-
- private void killProcessAndReportToMonitor(ProcessIdentifier processIdentifier) {
- ProcessInfo processInfo = getProcessInfo(processIdentifier.pid);
- if (!processInfo.doMatch(processIdentifier.pid, processIdentifier.startTimeMillis)) {
- return;
- }
- String cmdline = getProcessCmdLine(processIdentifier.pid);
- Process.killProcess(processIdentifier.pid);
- Slogf.w(TAG, "carwatchdog killed %s %s", cmdline, processInfo);
- try {
- mCarWatchdogDaemonHelper.tellDumpFinished(mCarWatchdogMonitor, processIdentifier);
- } catch (RemoteException | RuntimeException e) {
- Slogf.w(TAG, "Cannot report monitor result to car watchdog daemon: %s", e);
- }
- }
-
- private static String getProcessCmdLine(int pid) {
- String filename = "/proc/" + pid + "/cmdline";
- try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
- String line = reader.readLine().replace('\0', ' ').trim();
- int index = line.indexOf(' ');
- if (index != -1) {
- line = line.substring(0, index);
- }
- return Paths.get(line).getFileName().toString();
- } catch (IOException | RuntimeException e) {
- Slogf.w(TAG, "Cannot read %s", filename);
- return ProcessInfo.UNKNOWN_PROCESS;
- }
- }
-
- private ProcessInfo getProcessInfo(int pid) {
- String filename = "/proc/" + pid + "/stat";
- try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
- String line = reader.readLine().replace('\0', ' ').trim();
- Matcher m = mProcPidStatPattern.matcher(line);
- if (m.find()) {
- int readPid = Integer.parseInt(Objects.requireNonNull(m.group("pid")));
- if (readPid == pid) {
- return new ProcessInfo(pid, m.group("name"),
- Long.parseLong(Objects.requireNonNull(m.group("startClockTicks"))));
- }
- }
- } catch (IOException | RuntimeException e) {
- Slogf.w(TAG, e, "Cannot read %s", filename);
- }
- return new ProcessInfo(pid, ProcessInfo.UNKNOWN_PROCESS, ProcessInfo.INVALID_START_TIME);
- }
-
- @Override
- public void setSafetyMode(boolean safe) {
- mCarDevicePolicySafetyChecker.setSafe(safe);
- }
-
- @Override
- public UserHandle createUserEvenWhenDisallowed(String name, String userType, int flags) {
- if (DBG) {
- Slogf.d(TAG, "createUserEvenWhenDisallowed(): name=%s, type=%s, flags=%s",
- UserHelperLite.safeName(name), userType, UserInfo.flagsToString(flags));
- }
- UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
- try {
- UserInfo user = umi.createUserEvenWhenDisallowed(name, userType, flags,
- /* disallowedPackages= */ null, /* token= */ null);
- if (DBG) {
- Slogf.d(TAG, "User created: %s", (user == null ? "null" : user.toFullString()));
- }
- // TODO(b/172691310): decide if user should be affiliated when DeviceOwner is set
- return user.getUserHandle();
- } catch (UserManager.CheckedUserOperationException e) {
- Slogf.e(TAG, e, "Error creating user");
- return null;
- }
- }
-
- private class ICarWatchdogMonitorImpl extends ICarWatchdogMonitor.Stub {
- private final WeakReference<CarServiceHelperService> mService;
-
- private ICarWatchdogMonitorImpl(CarServiceHelperService service) {
- mService = new WeakReference<>(service);
- }
-
- @Override
- public void onClientsNotResponding(List<ProcessIdentifier> processIdentifiers) {
- CarServiceHelperService service = mService.get();
- if (service == null || processIdentifiers == null || processIdentifiers.isEmpty()) {
- return;
- }
- service.handleClientsNotResponding(processIdentifiers);
- }
-
- @Override
- public String getInterfaceHash() {
- return ICarWatchdogMonitor.HASH;
- }
-
- @Override
- public int getInterfaceVersion() {
- return ICarWatchdogMonitor.VERSION;
- }
- }
-
- private final class ProcessTerminator {
-
- private static final long ONE_SECOND_MS = 1_000L;
-
- private final Object mProcessLock = new Object();
- private ExecutorService mExecutor;
- @GuardedBy("mProcessLock")
- private int mQueuedTask;
-
- public void requestTerminateProcess(@NonNull List<ProcessIdentifier> processIdentifiers) {
- synchronized (mProcessLock) {
- // If there is a running thread, we re-use it instead of starting a new thread.
- if (mExecutor == null) {
- mExecutor = Executors.newSingleThreadExecutor();
- }
- mQueuedTask++;
- }
- mExecutor.execute(() -> {
- for (int i = 0; i < processIdentifiers.size(); i++) {
- ProcessIdentifier processIdentifier = processIdentifiers.get(i);
- ProcessInfo processInfo = getProcessInfo(processIdentifier.pid);
- if (processInfo.doMatch(processIdentifier.pid,
- processIdentifier.startTimeMillis)) {
- dumpAndKillProcess(processIdentifier);
- }
- }
- // mExecutor will be stopped from the main thread, if there is no queued task.
- mHandler.sendMessage(obtainMessage(ProcessTerminator::postProcessing, this)
- .setWhat(WHAT_POST_PROCESS_DUMPING));
- });
- }
-
- private void postProcessing() {
- synchronized (mProcessLock) {
- mQueuedTask--;
- if (mQueuedTask == 0) {
- mExecutor.shutdown();
- mExecutor = null;
- }
- }
- }
-
- private void dumpAndKillProcess(ProcessIdentifier processIdentifier) {
- if (DBG) {
- Slogf.d(TAG, "Dumping and killing process(pid: %d)", processIdentifier.pid);
- }
- ArrayList<Integer> javaPids = new ArrayList<>(1);
- ArrayList<Integer> nativePids = new ArrayList<>();
- try {
- if (isJavaApp(processIdentifier.pid)) {
- javaPids.add(processIdentifier.pid);
- } else {
- nativePids.add(processIdentifier.pid);
- }
- } catch (IOException e) {
- Slogf.w(TAG, "Cannot get process information: %s", e);
- return;
- }
- nativePids.addAll(getInterestingNativePids());
- long startDumpTime = SystemClock.uptimeMillis();
- ActivityManagerService.dumpStackTraces(javaPids, null, null, nativePids, null);
- long dumpTime = SystemClock.uptimeMillis() - startDumpTime;
- if (DBG) {
- Slogf.d(TAG, "Dumping process took %dms", dumpTime);
- }
- // To give clients a chance of wrapping up before the termination.
- if (dumpTime < ONE_SECOND_MS) {
- mHandler.sendMessageDelayed(obtainMessage(
- CarServiceHelperService::killProcessAndReportToMonitor,
- CarServiceHelperService.this, processIdentifier).setWhat(WHAT_PROCESS_KILL),
- ONE_SECOND_MS - dumpTime);
- } else {
- killProcessAndReportToMonitor(processIdentifier);
- }
- }
-
- private boolean isJavaApp(int pid) throws IOException {
- Path exePath = new File("/proc/" + pid + "/exe").toPath();
- String target = Files.readSymbolicLink(exePath).toString();
- // Zygote's target exe is also /system/bin/app_process32 or /system/bin/app_process64.
- // But, we can be very sure that Zygote will not be the client of car watchdog daemon.
- return target.equals("/system/bin/app_process32") ||
- target.equals("/system/bin/app_process64");
- }
- }
-
- private static final class ProcessInfo {
- public static final String UNKNOWN_PROCESS = "unknown process";
- public static final int INVALID_START_TIME = -1;
-
- private static final long MILLIS_PER_JIFFY = 1000L / Os.sysconf(OsConstants._SC_CLK_TCK);
-
- public final int pid;
- public final String name;
- public final long startTimeMillis;
-
- ProcessInfo(int pid, String name, long startClockTicks) {
- this.pid = pid;
- this.name = name;
- this.startTimeMillis = startClockTicks != INVALID_START_TIME
- ? startClockTicks * MILLIS_PER_JIFFY : INVALID_START_TIME;
- }
-
- boolean doMatch(int pid, long startTimeMillis) {
- // Start time reported by the services that monitor the process health will be either
- // the actual start time of the pid or the elapsed real time when the pid was last seen
- // alive. Thus, verify whether the given start time is at least the actual start time of
- // the pid.
- return this.pid == pid && (this.startTimeMillis == INVALID_START_TIME
- || this.startTimeMillis <= startTimeMillis);
- }
-
- @Override
- public String toString() {
- return new StringBuilder("ProcessInfo { pid = ").append(pid)
- .append(", name = ").append(name)
- .append(", startTimeMillis = ")
- .append(startTimeMillis != INVALID_START_TIME ? startTimeMillis : "invalid")
- .append(" }").toString();
- }
- }
-}
diff --git a/builtInServices/src/com/android/internal/car/CarServiceHelperServiceUpdatable.java b/builtInServices/src/com/android/internal/car/CarServiceHelperServiceUpdatable.java
deleted file mode 100644
index 175da48..0000000
--- a/builtInServices/src/com/android/internal/car/CarServiceHelperServiceUpdatable.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2021 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.internal.car;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.os.Bundle;
-import android.os.UserHandle;
-
-import com.android.server.wm.CarLaunchParamsModifierUpdatable;
-
-import java.io.PrintWriter;
-import java.util.function.BiConsumer;
-
-/**
- * Contains calls from CarServiceHelperService (which is a built-in class) to
- * CarServiceHelperServiceUpdatableImpl (which is a updatable class as part of car-module).
- *
- * @hide
- */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public interface CarServiceHelperServiceUpdatable {
-
- void onUserRemoved(@NonNull UserHandle userHandle);
-
- void onStart();
-
- void dump(@NonNull PrintWriter pw, @Nullable String[] args);
-
- void sendUserLifecycleEvent(int eventType, @Nullable UserHandle userFrom,
- @NonNull UserHandle userTo);
-
- void onFactoryReset(@NonNull BiConsumer<Integer, Bundle> processFactoryReset);
-
- void initBootUser();
-
- CarLaunchParamsModifierUpdatable getCarLaunchParamsModifierUpdatable();
-}
diff --git a/builtInServices/src/com/android/server/wm/ActivityOptionsWrapper.java b/builtInServices/src/com/android/server/wm/ActivityOptionsWrapper.java
deleted file mode 100644
index f9dc751..0000000
--- a/builtInServices/src/com/android/server/wm/ActivityOptionsWrapper.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm;
-
-import android.annotation.SystemApi;
-import android.app.ActivityOptions;
-import android.window.WindowContainerToken;
-
-/**
- * Wrapper of {@link ActivityOptions}.
- * @hide
- */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public final class ActivityOptionsWrapper {
- private final ActivityOptions mOptions;
-
- private ActivityOptionsWrapper(ActivityOptions options) {
- mOptions = options;
- }
-
- /** @hide */
- public static ActivityOptionsWrapper create(ActivityOptions options) {
- if (options == null) return null;
- return new ActivityOptionsWrapper(options);
- }
-
- /**
- * Gets the underlying {@link ActivityOptions} that is wrapped by this instance.
- */
- // Exposed the original object in order to allow to use the public accessors.
- public ActivityOptions getOptions() {
- return mOptions;
- }
-
- /**
- * Gets {@link TaskDisplayAreaWrapper} to launch the Activity into
- */
- public TaskDisplayAreaWrapper getLaunchTaskDisplayArea() {
- WindowContainerToken daToken = mOptions.getLaunchTaskDisplayArea();
- if (daToken == null) return null;
- TaskDisplayArea tda = (TaskDisplayArea) WindowContainer.fromBinder(daToken.asBinder());
- return TaskDisplayAreaWrapper.create(tda);
- }
-
- @Override
- public String toString() {
- return mOptions.toString();
- }
-}
diff --git a/builtInServices/src/com/android/server/wm/ActivityRecordWrapper.java b/builtInServices/src/com/android/server/wm/ActivityRecordWrapper.java
deleted file mode 100644
index bd15a54..0000000
--- a/builtInServices/src/com/android/server/wm/ActivityRecordWrapper.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm;
-
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.content.ComponentName;
-import android.content.pm.ActivityInfo;
-
-/**
- * Wrapper of {@link ActivityRecord}.
- * @hide
- */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public final class ActivityRecordWrapper {
- private final ActivityRecord mActivityRecord;
-
- private ActivityRecordWrapper(ActivityRecord activityRecord) {
- mActivityRecord = activityRecord;
- }
-
- /** @hide */
- public static ActivityRecordWrapper create(@Nullable ActivityRecord activityRecord) {
- if (activityRecord == null) return null;
- return new ActivityRecordWrapper(activityRecord);
- }
-
- /** @hide */
- public ActivityRecord getActivityRecord() {
- return mActivityRecord;
- }
-
- /**
- * Gets which user this Activity is running for.
- */
- public int getUserId() {
- return mActivityRecord.mUserId;
- }
-
- /**
- * Gets the actual {@link ComponentName} of this Activity.
- */
- public ComponentName getComponentName() {
- if (mActivityRecord.info == null) return null;
- return mActivityRecord.info.getComponentName();
- }
-
- /**
- * Gets the {@link TaskDisplayAreaWrapper} where this is located.
- */
- public TaskDisplayAreaWrapper getDisplayArea() {
- return TaskDisplayAreaWrapper.create(mActivityRecord.getDisplayArea());
- }
-
- /**
- * Returns whether this Activity is not displayed.
- */
- public boolean isNoDisplay() {
- return mActivityRecord.noDisplay;
- }
-
- /**
- * Gets {@link TaskDisplayAreaWrapper} where the handover Activity is supposed to launch
- */
- public TaskDisplayAreaWrapper getHandoverTaskDisplayArea() {
- return TaskDisplayAreaWrapper.create(mActivityRecord.mHandoverTaskDisplayArea);
- }
-
- /**
- * Gets {@code displayId} where the handover Activity is supposed to launch
- */
- public int getHandoverLaunchDisplayId() {
- return mActivityRecord.mHandoverLaunchDisplayId;
- }
-
- /**
- * Returns whether this Activity allows to be embedded in the other Activity.
- */
- public boolean allowingEmbedded() {
- if (mActivityRecord.info == null) return false;
- return (mActivityRecord.info.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) != 0;
- }
-
- /**
- * Returns whether the display where this Activity is located is trusted.
- */
- public boolean isDisplayTrusted() {
- return mActivityRecord.getDisplayContent().isTrusted();
- }
-
- @Override
- public String toString() {
- return mActivityRecord.toString();
- }
-}
diff --git a/builtInServices/src/com/android/server/wm/CalculateParams.java b/builtInServices/src/com/android/server/wm/CalculateParams.java
deleted file mode 100644
index 8b4faff..0000000
--- a/builtInServices/src/com/android/server/wm/CalculateParams.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm;
-
-import android.annotation.SystemApi;
-import android.app.ActivityOptions;
-import android.content.pm.ActivityInfo;
-import android.view.WindowLayout;
-
-/**
- * Wrapper of the parameters of {@code LaunchParamsController.LaunchParamsModifier.onCalculate()}
- * @hide
- */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public final class CalculateParams {
- private TaskWrapper mTask;
- private WindowLayoutWrapper mLayout;
- private ActivityRecordWrapper mActivity;
- private ActivityRecordWrapper mSource;
- private ActivityOptionsWrapper mOptions;
- private RequestWrapper mRequest;
- private int mPhase;
- private LaunchParamsWrapper mCurrentParams;
- private LaunchParamsWrapper mOutParams;
- private boolean mSupportsMultiDisplay;
-
- private CalculateParams() {}
-
- /** @hide */
- public static CalculateParams create(Task task, ActivityInfo.WindowLayout layout,
- ActivityRecord actvity, ActivityRecord source,
- ActivityOptions options, ActivityStarter.Request request, int phase,
- LaunchParamsController.LaunchParams currentParams,
- LaunchParamsController.LaunchParams outParms,
- boolean supportsMultiDisplay) {
- CalculateParams params = new CalculateParams();
- params.mTask = TaskWrapper.create(task);
- params.mLayout = WindowLayoutWrapper.create(layout);
- params.mActivity = ActivityRecordWrapper.create(actvity);
- params.mSource = ActivityRecordWrapper.create(source);
- params.mOptions = ActivityOptionsWrapper.create(options);
- params.mRequest = RequestWrapper.create(request);
- params.mPhase = phase;
- params.mCurrentParams = LaunchParamsWrapper.create(currentParams);
- params.mOutParams = LaunchParamsWrapper.create(outParms);
- params.mSupportsMultiDisplay = supportsMultiDisplay;
- return params;
- }
-
- /**
- * Gets the {@link TaskWrapper} currently being positioned.
- */
- public TaskWrapper getTask() {
- return mTask;
- }
-
- /**
- * Gets the specified {@link WindowLayoutWrapper}.
- */
- public WindowLayoutWrapper getWindowLayout() {
- return mLayout;
- }
-
- /**
- * Gets the {@link ActivityRecordWrapper} currently being positioned.
- */
- public ActivityRecordWrapper getActivity() {
- return mActivity;
- }
-
- /**
- * Gets the {@link ActivityRecordWrapper} from which activity was started from.
- */
- public ActivityRecordWrapper getSource() {
- return mSource;
- }
-
- /**
- * Gets the {@link ActivityOptionsWrapper} specified for the activity.
- */
- public ActivityOptionsWrapper getOptions() {
- return mOptions;
- }
-
- /**
- * Gets the optional {@link RequestWrapper} from the activity starter.
- */
- public RequestWrapper getRequest() {
- return mRequest;
- }
-
- /**
- * Gets the {@link LaunchParamsController.LaunchParamsModifier.Phase} that the resolution should
- * finish.
- */
- public int getPhase() {
- return mPhase;
- }
-
- /**
- * Gets the current {@link LaunchParamsWrapper}.
- */
- public LaunchParamsWrapper getCurrentParams() {
- return mCurrentParams;
- }
-
- /**
- * Gets the resulting {@link LaunchParamsWrapper}.
- */
- public LaunchParamsWrapper getOutParams() {
- return mOutParams;
- }
-
- /**
- * Returns whether the current system supports the multiple display.
- */
- public boolean supportsMultiDisplay() {
- return mSupportsMultiDisplay;
- }
-}
diff --git a/builtInServices/src/com/android/server/wm/CarDisplayAreaPolicyProvider.java b/builtInServices/src/com/android/server/wm/CarDisplayAreaPolicyProvider.java
deleted file mode 100644
index ea4a4bf..0000000
--- a/builtInServices/src/com/android/server/wm/CarDisplayAreaPolicyProvider.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2021 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.wm;
-
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
-import static android.window.DisplayAreaOrganizer.FEATURE_IME_PLACEHOLDER;
-import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Provider for platform-default car display area policy for reference design.
- *
- * @hide
- */
-public class CarDisplayAreaPolicyProvider implements DisplayAreaPolicy.Provider {
-
- /**
- * This display area is mandatory to be defined. This is where the applications will be
- * launched.
- */
- private static final int DEFAULT_APP_TASK_CONTAINER = FEATURE_DEFAULT_TASK_CONTAINER;
-
- /**
- * The display partition to launch applications by default. This contains {@link
- * #DEFAULT_APP_TASK_CONTAINER}.
- */
- private static final int FOREGROUND_DISPLAY_AREA_ROOT = FEATURE_VENDOR_FIRST + 1;
-
- /**
- * Background applications task container.
- */
- private static final int BACKGROUND_TASK_CONTAINER = FEATURE_VENDOR_FIRST + 2;
- private static final int FEATURE_TASKDISPLAYAREA_PARENT = FEATURE_VENDOR_FIRST + 3;
-
- /**
- * Control bar task container.
- *
- * Currently we are launching CarLauncher activity in this TDA. This is because the audio card
- * implementation today is using fragments. If that changes in future then we can use the window
- * instead to display that view instead of fragments that need an activity.
- */
- private static final int CONTROL_BAR_DISPLAY_AREA = FEATURE_VENDOR_FIRST + 4;
-
- /**
- * Feature to display the title bar.
- */
- private static final int FEATURE_TITLE_BAR = FEATURE_VENDOR_FIRST + 5;
-
- /**
- * Feature to display voice plate.
- */
- private static final int FEATURE_VOICE_PLATE = FEATURE_VENDOR_FIRST + 6;
-
- @Override
- public DisplayAreaPolicy instantiate(WindowManagerService wmService, DisplayContent content,
- RootDisplayArea root, DisplayArea.Tokens imeContainer) {
-
- if (!content.isDefaultDisplay) {
- return new DisplayAreaPolicy.DefaultProvider().instantiate(wmService, content, root,
- imeContainer);
- }
-
- TaskDisplayArea backgroundTaskDisplayArea = new TaskDisplayArea(content, wmService,
- "BackgroundTaskDisplayArea", BACKGROUND_TASK_CONTAINER,
- /* createdByOrganizer= */ false, /* canHostHomeTask= */ false);
-
- TaskDisplayArea controlBarDisplayArea = new TaskDisplayArea(content, wmService,
- "ControlBarTaskDisplayArea", CONTROL_BAR_DISPLAY_AREA,
- /* createdByOrganizer= */ false, /* canHostHomeTask= */ false);
-
- TaskDisplayArea voicePlateTaskDisplayArea = new TaskDisplayArea(content, wmService,
- "VoicePlateTaskDisplayArea", FEATURE_VOICE_PLATE,
- /* createdByOrganizer= */ false, /* canHostHomeTask= */ false);
-
- List<TaskDisplayArea> backgroundTdaList = new ArrayList<>();
- backgroundTdaList.add(voicePlateTaskDisplayArea);
- backgroundTdaList.add(backgroundTaskDisplayArea);
- backgroundTdaList.add(controlBarDisplayArea);
-
- // Root
- DisplayAreaPolicyBuilder.HierarchyBuilder rootHierarchy =
- new DisplayAreaPolicyBuilder.HierarchyBuilder(root)
- .setTaskDisplayAreas(backgroundTdaList)
- .addFeature(new DisplayAreaPolicyBuilder.Feature.Builder(wmService.mPolicy,
- "ImePlaceholder", FEATURE_IME_PLACEHOLDER)
- .and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG)
- .build())
- // to make sure there are 2 children under root.
- // TODO: replace when b/188102153 is resolved to set this to top.
- .addFeature(new DisplayAreaPolicyBuilder.Feature.Builder(wmService.mPolicy,
- "TaskDisplayAreaParent", FEATURE_TASKDISPLAYAREA_PARENT)
- .and(TYPE_APPLICATION)
- .build());
-
- // Default application launches here
- RootDisplayArea defaultAppsRoot = new DisplayAreaGroup(wmService,
- "FeatureForegroundApplication", FOREGROUND_DISPLAY_AREA_ROOT);
- TaskDisplayArea defaultAppTaskDisplayArea = new TaskDisplayArea(content, wmService,
- "DefaultApplicationTaskDisplayArea", DEFAULT_APP_TASK_CONTAINER);
- List<TaskDisplayArea> firstTdaList = new ArrayList<>();
- firstTdaList.add(defaultAppTaskDisplayArea);
- DisplayAreaPolicyBuilder.HierarchyBuilder applicationHierarchy =
- new DisplayAreaPolicyBuilder.HierarchyBuilder(defaultAppsRoot)
- .setTaskDisplayAreas(firstTdaList)
- .setImeContainer(imeContainer)
- .addFeature(new DisplayAreaPolicyBuilder.Feature.Builder(wmService.mPolicy,
- "ImePlaceholder", FEATURE_IME_PLACEHOLDER)
- .and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG)
- .build())
- .addFeature(new DisplayAreaPolicyBuilder.Feature.Builder(wmService.mPolicy,
- "TitleBar", FEATURE_TITLE_BAR)
- .and(TYPE_APPLICATION_OVERLAY)
- .build());
-
- return new DisplayAreaPolicyBuilder()
- .setRootHierarchy(rootHierarchy)
- .addDisplayAreaGroupHierarchy(applicationHierarchy)
- .build(wmService);
- }
-}
diff --git a/builtInServices/src/com/android/server/wm/CarLaunchParamsModifier.java b/builtInServices/src/com/android/server/wm/CarLaunchParamsModifier.java
deleted file mode 100644
index 6472ffb..0000000
--- a/builtInServices/src/com/android/server/wm/CarLaunchParamsModifier.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * 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.wm;
-
-import static com.android.server.wm.ActivityStarter.Request;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.app.ActivityOptions;
-import android.app.ActivityTaskManager;
-import android.content.Context;
-import android.content.pm.ActivityInfo;
-import android.hardware.display.DisplayManager;
-import android.os.Handler;
-import android.os.Looper;
-import android.view.Display;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Class to control the assignment of a display for Car while launching a Activity.
- *
- * <p>This one controls which displays users are allowed to launch.
- * The policy should be passed from car service through
- * {@link com.android.internal.car.ICarServiceHelper} binder interfaces. If no policy is set,
- * this module will not change anything for launch process.</p>
- *
- * <p> The policy can only affect which display passenger users can use. Current user, assumed
- * to be a driver user, is allowed to launch any display always.</p>
- *
- * @hide
- */
-public final class CarLaunchParamsModifier implements LaunchParamsController.LaunchParamsModifier {
-
- private final Context mContext;
-
- private DisplayManager mDisplayManager; // set only from init()
- private ActivityTaskManagerService mAtm; // set only from init()
-
- private CarLaunchParamsModifierUpdatable mUpdatable;
-
- // getFallbackDisplayAreasForActivity() can return the most 3 {@link TaskDisplayAreaWrapper}.
- private final ArrayList<TaskDisplayAreaWrapper> mFallBackDisplayAreaList = new ArrayList<>(3);
-
- /** Constructor. Can be constructed any time. */
- public CarLaunchParamsModifier(Context context) {
- // This can be very early stage. So postpone interaction with other system until init.
- mContext = context;
- }
-
- public void setUpdatable(CarLaunchParamsModifierUpdatable updatable) {
- mUpdatable = updatable;
- }
-
- public CarLaunchParamsModifierInterface getBuiltinInterface() {
- return mBuiltinInterface;
- }
-
- /**
- * Initializes all internal stuffs. This should be called only after ATMS, DisplayManagerService
- * are ready.
- */
- public void init() {
- mAtm = (ActivityTaskManagerService) ActivityTaskManager.getService();
- LaunchParamsController controller = mAtm.mTaskSupervisor.getLaunchParamsController();
- controller.registerModifier(this);
- mDisplayManager = mContext.getSystemService(DisplayManager.class);
- mDisplayManager.registerDisplayListener(mUpdatable.getDisplayListener(),
- new Handler(Looper.getMainLooper()));
- }
-
- /** Notifies user switching. */
- public void handleUserStarting(@UserIdInt int startingUserId) {
- mUpdatable.handleUserStarting(startingUserId);
- }
-
- /** Notifies user switching. */
- public void handleCurrentUserSwitching(@UserIdInt int newUserId) {
- mUpdatable.handleCurrentUserSwitching(newUserId);
- }
-
- /** Notifies user stopped. */
- public void handleUserStopped(@UserIdInt int stoppedUser) {
- mUpdatable.handleUserStopped(stoppedUser);
- }
-
- /**
- * Decides display to assign while an Activity is launched.
- *
- * <p>For current user (=driver), launching to any display is allowed as long as system
- * allows it.</p>
- *
- * <p>For private display, do not change anything as private display has its own logic.</p>
- *
- * <p>For passenger displays, only run in allowed displays. If requested display is not
- * allowed, change to the 1st allowed display.</p>
- */
- @Override
- @Result
- public int onCalculate(@Nullable Task task, @Nullable ActivityInfo.WindowLayout layout,
- @Nullable ActivityRecord activity, @Nullable ActivityRecord source,
- ActivityOptions options, @Nullable Request request, int phase,
- LaunchParamsController.LaunchParams currentParams,
- LaunchParamsController.LaunchParams outParams) {
- CalculateParams params = CalculateParams.create(task, layout, activity, source,
- options, request, phase, currentParams, outParams, mAtm.mSupportsMultiDisplay);
- return mUpdatable.calculate(params);
- }
-
- @Nullable
- private TaskDisplayAreaWrapper getDefaultTaskDisplayAreaOnDisplay(int displayId) {
- if (displayId == Display.INVALID_DISPLAY) {
- return null;
- }
- DisplayContent dc = mAtm.mRootWindowContainer.getDisplayContentOrCreate(displayId);
- if (dc == null) {
- return null;
- }
- return TaskDisplayAreaWrapper.create(dc.getDefaultTaskDisplayArea());
- }
-
- /**
- * Calculates the default {@link TaskDisplayAreaWrapper} for a task. We attempt to put
- * the activity within the same display area if possible. The strategy is to find the display
- * in the following order:
- *
- * <ol>
- * <li>The display area of the top activity from the launching process will be used</li>
- * <li>The display area of the top activity from the real launching process will be used
- * </li>
- * <li>Default display area from the associated root window container.</li>
- * </ol>
- * @param activityRecordWrapper the activity being started
- * @param requestWrapper optional {@link RequestWrapper} made to start the activity record
- * @return the list of {@link TaskDisplayAreaWrapper} to house the task
- */
- private List<TaskDisplayAreaWrapper> getFallbackDisplayAreasForActivity(
- @NonNull ActivityRecordWrapper activityRecordWrapper,
- @Nullable RequestWrapper requestWrapper) {
- ActivityRecord activityRecord = activityRecordWrapper.getActivityRecord();
- Request request = requestWrapper != null ? requestWrapper.getRequest() : null;
- mFallBackDisplayAreaList.clear();
-
- WindowProcessController controllerFromLaunchingRecord = mAtm.getProcessController(
- activityRecord.launchedFromPid, activityRecord.launchedFromUid);
- TaskDisplayArea displayAreaForLaunchingRecord = controllerFromLaunchingRecord == null
- ? null : controllerFromLaunchingRecord.getTopActivityDisplayArea();
- if (displayAreaForLaunchingRecord != null) {
- mFallBackDisplayAreaList.add(
- TaskDisplayAreaWrapper.create(displayAreaForLaunchingRecord));
- }
-
- WindowProcessController controllerFromProcess = mAtm.getProcessController(
- activityRecord.getProcessName(), activityRecord.getUid());
- TaskDisplayArea displayAreaForRecord = controllerFromProcess == null ? null
- : controllerFromProcess.getTopActivityDisplayArea();
- if (displayAreaForRecord != null) {
- mFallBackDisplayAreaList.add(TaskDisplayAreaWrapper.create(displayAreaForRecord));
- }
-
- WindowProcessController controllerFromRequest =
- request == null ? null : mAtm.getProcessController(request.realCallingPid,
- request.realCallingUid);
- TaskDisplayArea displayAreaFromSourceProcess = controllerFromRequest == null ? null
- : controllerFromRequest.getTopActivityDisplayArea();
- if (displayAreaFromSourceProcess != null) {
- mFallBackDisplayAreaList.add(
- TaskDisplayAreaWrapper.create(displayAreaFromSourceProcess));
- }
- return mFallBackDisplayAreaList;
- }
-
- @Nullable
- private TaskDisplayAreaWrapper findTaskDisplayArea(int displayId, int featureId) {
- DisplayContent display = mAtm.mRootWindowContainer.getDisplayContentOrCreate(displayId);
- if (display == null) {
- return null;
- }
- TaskDisplayArea tda = display.getItemFromTaskDisplayAreas(
- displayArea -> displayArea.mFeatureId == featureId ? displayArea : null);
- return TaskDisplayAreaWrapper.create(tda);
- }
-
- private final CarLaunchParamsModifierInterface mBuiltinInterface
- = new CarLaunchParamsModifierInterface() {
- @Nullable
- @Override
- public TaskDisplayAreaWrapper findTaskDisplayArea(int displayId, int featureId) {
- return CarLaunchParamsModifier.this.findTaskDisplayArea(displayId, featureId);
- }
-
- @Nullable
- @Override
- public TaskDisplayAreaWrapper getDefaultTaskDisplayAreaOnDisplay(int displayId) {
- return CarLaunchParamsModifier.this.getDefaultTaskDisplayAreaOnDisplay(displayId);
- }
-
- @NonNull
- @Override
- public List<TaskDisplayAreaWrapper> getFallbackDisplayAreasForActivity(
- @NonNull ActivityRecordWrapper activityRecord, @Nullable RequestWrapper request) {
- return CarLaunchParamsModifier.this.getFallbackDisplayAreasForActivity(
- activityRecord, request);
- }
- };
-}
diff --git a/builtInServices/src/com/android/server/wm/CarLaunchParamsModifierInterface.java b/builtInServices/src/com/android/server/wm/CarLaunchParamsModifierInterface.java
deleted file mode 100644
index 8550c55..0000000
--- a/builtInServices/src/com/android/server/wm/CarLaunchParamsModifierInterface.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.graphics.Rect;
-import android.view.Display;
-
-import java.util.List;
-
-/**
- * Interface implemented by {@code CarLaunchParamsModifier} and used by
- * {@code CarLaunchParamsModifierUpdatable}.
- *
- * Because {@code CarLaunchParamsModifierUpdatable} calls {@code CarLaunchParamsModifierInterface}
- * with {@code mLock} acquired, {@code CarLaunchParamsModifierInterface} shouldn't call
- * {@code CarLaunchParamsModifierUpdatable} again during its execution.
- * @hide
- */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public interface CarLaunchParamsModifierInterface {
- /**
- * Returns {@link TaskDisplayAreaWrapper} of the given {@code featureId} in the given
- * {@code displayId}.
- */
- @Nullable TaskDisplayAreaWrapper findTaskDisplayArea(int displayId, int featureId);
-
- /**
- * Returns the default {@link TaskDisplayAreaWrapper} of the given {@code displayId}.
- */
- @Nullable TaskDisplayAreaWrapper getDefaultTaskDisplayAreaOnDisplay(int displayId);
-
- /**
- * Returns the list of fallback {@link TaskDisplayAreaWrapper} from the source of the request.
- */
- @NonNull List<TaskDisplayAreaWrapper> getFallbackDisplayAreasForActivity(
- @NonNull ActivityRecordWrapper activityRecord, @Nullable RequestWrapper request);
-
-}
diff --git a/builtInServices/src/com/android/server/wm/CarLaunchParamsModifierUpdatable.java b/builtInServices/src/com/android/server/wm/CarLaunchParamsModifierUpdatable.java
deleted file mode 100644
index 3abf54e..0000000
--- a/builtInServices/src/com/android/server/wm/CarLaunchParamsModifierUpdatable.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.annotation.UserIdInt;
-import android.car.app.CarActivityManager;
-import android.content.ComponentName;
-import android.hardware.display.DisplayManager;
-import android.os.ServiceSpecificException;
-import android.os.UserHandle;
-import android.util.ArrayMap;
-import android.util.Slog;
-import android.util.SparseIntArray;
-import android.view.Display;
-import android.window.DisplayAreaOrganizer;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Updatable interface of CarLaunchParamsModifier.
- * @hide
- */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public interface CarLaunchParamsModifierUpdatable {
-
- /** Returns {@link DisplayManager.DisplayListener} of CarLaunchParamsModifierUpdatable. */
- DisplayManager.DisplayListener getDisplayListener();
-
- /** Notifies user switching. */
- void handleCurrentUserSwitching(@UserIdInt int newUserId);
-
- /** Notifies user starting. */
- void handleUserStarting(@UserIdInt int startingUser);
-
- /** Notifies user stopped. */
- void handleUserStopped(@UserIdInt int stoppedUser);
-
- /**
- * Calculates {@code outParams} based on the given arguments.
- * See {@code LaunchParamsController.LaunchParamsModifier.onCalculate()} for the detail.
- */
- int calculate(CalculateParams params);
-}
diff --git a/builtInServices/src/com/android/server/wm/LaunchParamsWrapper.java b/builtInServices/src/com/android/server/wm/LaunchParamsWrapper.java
deleted file mode 100644
index 344961f..0000000
--- a/builtInServices/src/com/android/server/wm/LaunchParamsWrapper.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm;
-
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.graphics.Rect;
-
-/**
- * Wrapper of {@link com.android.server.wm.LaunchParamsController.LaunchParams}.
- * @hide
- */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public final class LaunchParamsWrapper {
- /** Returned when the modifier does not want to influence the bounds calculation */
- public static int RESULT_SKIP = LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
- /**
- * Returned when the modifier has changed the bounds and would like its results to be the
- * final bounds applied.
- */
- public static int RESULT_DONE = LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
- /**
- * Returned when the modifier has changed the bounds but is okay with other modifiers
- * influencing the bounds.
- */
- public static int RESULT_CONTINUE = LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
-
- private final LaunchParamsController.LaunchParams mLaunchParams;
-
- private LaunchParamsWrapper(LaunchParamsController.LaunchParams launchParams) {
- mLaunchParams = launchParams;
- }
-
- /** @hide */
- public static LaunchParamsWrapper create(
- @Nullable LaunchParamsController.LaunchParams launchParams) {
- if (launchParams == null) return null;
- return new LaunchParamsWrapper(launchParams);
- }
-
- /**
- * Gets the {@link TaskDisplayAreaWrapper} the {@link Task} would prefer to be on.
- */
- public TaskDisplayAreaWrapper getPreferredTaskDisplayArea() {
- return TaskDisplayAreaWrapper.create(mLaunchParams.mPreferredTaskDisplayArea);
- }
-
- /**
- * Sets the {@link TaskDisplayAreaWrapper} the {@link Task} would prefer to be on.
- */
- public void setPreferredTaskDisplayArea(TaskDisplayAreaWrapper tda) {
- mLaunchParams.mPreferredTaskDisplayArea = tda.getTaskDisplayArea();
- }
-
- /**
- * Gets the windowing mode to be in.
- */
- public int getWindowingMode() {
- return mLaunchParams.mWindowingMode;
- }
-
- /**
- * Sets the windowing mode to be in.
- */
- public void setWindowingMode(int windowingMode) {
- mLaunchParams.mWindowingMode = windowingMode;
- }
-
- /**
- * Gets the bounds within the parent container.
- */
- public Rect getBounds() {
- return mLaunchParams.mBounds;
- }
-
- /**
- * Sets the bounds within the parent container.
- */
- public void setBounds(Rect bounds) {
- mLaunchParams.mBounds.set(bounds);
- }
-
- @Override
- public String toString() {
- return "LaunchParams{" +
- "mPreferredTaskDisplayArea=" + mLaunchParams.mPreferredTaskDisplayArea +
- ", mWindowingMode=" + mLaunchParams.mWindowingMode +
- ", mBounds=" + mLaunchParams.mBounds.toString() + '}';
- }
-}
diff --git a/builtInServices/src/com/android/server/wm/RequestWrapper.java b/builtInServices/src/com/android/server/wm/RequestWrapper.java
deleted file mode 100644
index d6e1795..0000000
--- a/builtInServices/src/com/android/server/wm/RequestWrapper.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm;
-
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-
-/**
- * Wrapper of {@link com.android.server.wm.ActivityStarter.Request}.
- * @hide
- */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public final class RequestWrapper {
- private final ActivityStarter.Request mRequest;
-
- private RequestWrapper(ActivityStarter.Request request) {
- mRequest = request;
- }
-
- /** @hide */
- public static RequestWrapper create(@Nullable ActivityStarter.Request request) {
- if (request == null) return null;
- return new RequestWrapper(request);
- }
-
- /** @hide */
- public ActivityStarter.Request getRequest() {
- return mRequest;
- }
-
- @Override
- public String toString() {
- return mRequest.toString();
- }
-}
diff --git a/builtInServices/src/com/android/server/wm/TaskDisplayAreaWrapper.java b/builtInServices/src/com/android/server/wm/TaskDisplayAreaWrapper.java
deleted file mode 100644
index 9faef06..0000000
--- a/builtInServices/src/com/android/server/wm/TaskDisplayAreaWrapper.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm;
-
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.view.Display;
-
-/**
- * Wrapper of {@link TaskDisplayArea}.
- * @hide
- */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public final class TaskDisplayAreaWrapper {
- private final TaskDisplayArea mTaskDisplayArea;
-
- private TaskDisplayAreaWrapper(TaskDisplayArea taskDisplayArea) {
- mTaskDisplayArea = taskDisplayArea;
- }
-
- /** @hide */
- public static TaskDisplayAreaWrapper create(@Nullable TaskDisplayArea taskDisplayArea) {
- if (taskDisplayArea == null) return null;
- return new TaskDisplayAreaWrapper(taskDisplayArea);
- }
-
- /** @hide */
- public TaskDisplayArea getTaskDisplayArea() {
- return mTaskDisplayArea;
- }
-
- /**
- * Gets the display this {@link TaskDisplayAreaWrapper} is on.
- */
- public Display getDisplay() {
- return mTaskDisplayArea.getDisplayContent().getDisplay();
- }
-
- @Override
- public String toString() {
- return mTaskDisplayArea.toString();
- }
-}
diff --git a/builtInServices/src/com/android/server/wm/TaskWrapper.java b/builtInServices/src/com/android/server/wm/TaskWrapper.java
deleted file mode 100644
index 3a2c682..0000000
--- a/builtInServices/src/com/android/server/wm/TaskWrapper.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm;
-
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-
-/**
- * Wrapper of {@link Task}.
- * @hide
- */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public final class TaskWrapper {
- private final Task mTask;
-
- private TaskWrapper(Task task) {
- mTask = task;
- }
-
- /** @hide */
- public static TaskWrapper create(@Nullable Task task) {
- if (task == null) return null;
- return new TaskWrapper(task);
- }
-
- /**
- * Gets the {@code userId} of this {@link Task} is created for
- */
- public int getUserId() {
- return mTask.mUserId;
- }
-
- /**
- * Gets the root {@link TaskWrapper} of the this.
- */
- public TaskWrapper getRootTask() {
- return create(mTask.getRootTask());
- }
-
- /**
- * Gets the {@link TaskDisplayAreaWrapper} this {@link Task} is on.
- */
- public TaskDisplayAreaWrapper getTaskDisplayArea() {
- return TaskDisplayAreaWrapper.create(mTask.getTaskDisplayArea());
- }
-
- @Override
- public String toString() {
- return mTask.toString();
- }
-}
diff --git a/builtInServices/src/com/android/server/wm/WindowLayoutWrapper.java b/builtInServices/src/com/android/server/wm/WindowLayoutWrapper.java
deleted file mode 100644
index e028a20..0000000
--- a/builtInServices/src/com/android/server/wm/WindowLayoutWrapper.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm;
-
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.content.pm.ActivityInfo;
-
-/**
- * Wrapper of {@link android.content.pm.ActivityInfo.WindowLayout}.
- * @hide
- */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public final class WindowLayoutWrapper {
- private final ActivityInfo.WindowLayout mLayout;
-
- private WindowLayoutWrapper(ActivityInfo.WindowLayout layout) {
- mLayout = layout;
- }
-
- /** @hide */
- public static WindowLayoutWrapper create(@Nullable ActivityInfo.WindowLayout layout) {
- if (layout == null) return null;
- return new WindowLayoutWrapper(layout);
- }
-
- @Override
- public String toString() {
- return mLayout.toString();
- }
-}
diff --git a/builtInServices/tests/src/com/android/server/wm/ActivityOptionsWrapperTest.java b/builtInServices/tests/src/com/android/server/wm/ActivityOptionsWrapperTest.java
deleted file mode 100644
index 682c31f..0000000
--- a/builtInServices/tests/src/com/android/server/wm/ActivityOptionsWrapperTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.ActivityOptions;
-
-import org.junit.Test;
-
-/**
- * This class contains unit tests for the {@link ActivityOptionsWrapper}.
- */
-public final class ActivityOptionsWrapperTest {
- @Test
- public void create_returnsActivityOptionWrapper() {
- ActivityOptions options = ActivityOptions.makeBasic();
- ActivityOptionsWrapper wrapper = ActivityOptionsWrapper.create(options);
- assertThat(wrapper).isNotNull();
- assertThat(wrapper.getOptions()).isSameInstanceAs(options);
- assertThat(wrapper.toString()).isEqualTo(options.toString());
- }
-
- @Test
- public void create_returnsNull() {
- ActivityOptionsWrapper wrapper = ActivityOptionsWrapper.create(null);
- assertThat(wrapper).isNull();
- }
-}
diff --git a/builtInServices/tests/src/com/android/server/wm/ActivityRecordWrapperTest.java b/builtInServices/tests/src/com/android/server/wm/ActivityRecordWrapperTest.java
deleted file mode 100644
index 302f974..0000000
--- a/builtInServices/tests/src/com/android/server/wm/ActivityRecordWrapperTest.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-/**
- * This class contains unit tests for the {@link ActivityRecordWrapper}.
- */
-@RunWith(MockitoJUnitRunner.class)
-public final class ActivityRecordWrapperTest {
- @Mock
- private ActivityRecord mActivityRecord;
-
- @Test
- public void create_returnsActivityOptionWrapper() {
- ActivityRecordWrapper wrapper = ActivityRecordWrapper.create(mActivityRecord);
- assertThat(wrapper).isNotNull();
- assertThat(wrapper.getActivityRecord()).isSameInstanceAs(mActivityRecord);
- assertThat(wrapper.toString()).isEqualTo(mActivityRecord.toString());
- }
-
- @Test
- public void create_returnsNull() {
- ActivityRecordWrapper wrapper = ActivityRecordWrapper.create(null);
- assertThat(wrapper).isNull();
- }
-}
diff --git a/builtInServices/tests/src/com/android/server/wm/CalculateParamsTest.java b/builtInServices/tests/src/com/android/server/wm/CalculateParamsTest.java
deleted file mode 100644
index bf34497..0000000
--- a/builtInServices/tests/src/com/android/server/wm/CalculateParamsTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.ActivityOptions;
-import android.content.pm.ActivityInfo;
-import android.view.Gravity;
-
-import com.android.server.wm.LaunchParamsController.LaunchParams;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-/**
- * This class contains unit tests for the {@link CalculateParams}.
- */
-@RunWith(MockitoJUnitRunner.class)
-public class CalculateParamsTest {
- @Mock
- private Task mTask;
- private ActivityInfo.WindowLayout mLayout = new ActivityInfo.WindowLayout(
- /* width= */ 1280, /* widthFraction= */ 0.5f,
- /* height= */ 800, /* heightFraction= */ 1.0f,
- /* gravity= */ Gravity.CENTER, /* minWidth= */ 400, /* minHeight= */ 300);
- @Mock
- private ActivityRecord mActvity;
- @Mock
- private ActivityRecord mSource;
- private ActivityOptions mOptions = ActivityOptions.makeBasic();
- private ActivityStarter.Request mRequest = new ActivityStarter.Request();
- private int mPhase = LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
- private LaunchParams mCurrentParams = new LaunchParams();
- private LaunchParams mOutParms = new LaunchParams();
- boolean mSupportsMultiDisplay = true;
-
- @Test
- public void createReturnsCalculateParams() {
- mCurrentParams.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
- mOutParms.mWindowingMode = WINDOWING_MODE_MULTI_WINDOW;
- CalculateParams params = CalculateParams.create(mTask,mLayout, mActvity, mSource, mOptions,
- mRequest, mPhase, mCurrentParams, mOutParms, mSupportsMultiDisplay);
- // Current toString() of Wrappers are using toString() of the underlying object
- // except LaunchParams.
- assertThat(params.getTask().toString()).isEqualTo(mTask.toString());
- assertThat(params.getWindowLayout().toString()).isEqualTo(mLayout.toString());
- assertThat(params.getActivity().getActivityRecord()).isSameInstanceAs(mActvity);
- assertThat(params.getSource().getActivityRecord()).isSameInstanceAs(mSource);
- assertThat(params.getCurrentParams().getWindowingMode())
- .isEqualTo(WINDOWING_MODE_FULLSCREEN);
- assertThat(params.getOutParams().getWindowingMode()).isEqualTo(WINDOWING_MODE_MULTI_WINDOW);
- assertThat(params.supportsMultiDisplay()).isEqualTo(mSupportsMultiDisplay);
- }
-}
diff --git a/builtInServices/tests/src/com/android/server/wm/LaunchParamsWrapperTest.java b/builtInServices/tests/src/com/android/server/wm/LaunchParamsWrapperTest.java
deleted file mode 100644
index 3a19199..0000000
--- a/builtInServices/tests/src/com/android/server/wm/LaunchParamsWrapperTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import org.junit.Test;
-
-/**
- * This class contains unit tests for the {@link LaunchParamsWrapper}.
- */
-public final class LaunchParamsWrapperTest {
- @Test
- public void create_returnsLaunchParamsWrapper() {
- LaunchParamsController.LaunchParams params = new LaunchParamsController.LaunchParams();
- LaunchParamsWrapper wrapper = LaunchParamsWrapper.create(params);
- assertThat(wrapper).isNotNull();
- }
-
- @Test
- public void create_returnsNull() {
- LaunchParamsWrapper wrapper = LaunchParamsWrapper.create(null);
- assertThat(wrapper).isNull();
- }
-}
\ No newline at end of file
diff --git a/builtInServices/tests/src/com/android/server/wm/RequestWrapperTest.java b/builtInServices/tests/src/com/android/server/wm/RequestWrapperTest.java
deleted file mode 100644
index 7e81390..0000000
--- a/builtInServices/tests/src/com/android/server/wm/RequestWrapperTest.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import org.junit.Test;
-
-/**
- * This class contains unit tests for the {@link RequestWrapper}.
- */
-public final class RequestWrapperTest {
- @Test
- public void create_returnsActivityOptionWrapper() {
- ActivityStarter.Request request = new ActivityStarter.Request();
- RequestWrapper wrapper = RequestWrapper.create(request);
- assertThat(wrapper).isNotNull();
- assertThat(wrapper.getRequest()).isSameInstanceAs(request);
- assertThat(wrapper.toString()).isEqualTo(request.toString());
- }
-
- @Test
- public void create_returnsNull() {
- RequestWrapper wrapper = RequestWrapper.create(null);
- assertThat(wrapper).isNull();
- }
-}
diff --git a/builtInServices/tests/src/com/android/server/wm/TaskDisplayAreaWrapperTest.java b/builtInServices/tests/src/com/android/server/wm/TaskDisplayAreaWrapperTest.java
deleted file mode 100644
index 53c100f..0000000
--- a/builtInServices/tests/src/com/android/server/wm/TaskDisplayAreaWrapperTest.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-/**
- * This class contains unit tests for the {@link TaskDisplayAreaWrapper}.
- */
-@RunWith(MockitoJUnitRunner.class)
-public final class TaskDisplayAreaWrapperTest {
- @Mock
- private TaskDisplayArea mTaskDisplayArea;
-
- @Test
- public void create_returnsActivityOptionWrapper() {
- TaskDisplayAreaWrapper wrapper = TaskDisplayAreaWrapper.create(mTaskDisplayArea);
- assertThat(wrapper).isNotNull();
- assertThat(wrapper.getTaskDisplayArea()).isSameInstanceAs(mTaskDisplayArea);
- assertThat(wrapper.toString()).isEqualTo(mTaskDisplayArea.toString());
- }
-
- @Test
- public void create_returnsNull() {
- TaskDisplayAreaWrapper wrapper = TaskDisplayAreaWrapper.create(null);
- assertThat(wrapper).isNull();
- }
-}
diff --git a/builtInServices/tests/src/com/android/server/wm/TaskWrapperTest.java b/builtInServices/tests/src/com/android/server/wm/TaskWrapperTest.java
deleted file mode 100644
index ce29cd6..0000000
--- a/builtInServices/tests/src/com/android/server/wm/TaskWrapperTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-/**
- * This class contains unit tests for the {@link TaskWrapper}.
- */
-@RunWith(MockitoJUnitRunner.class)
-public final class TaskWrapperTest {
- @Mock
- private Task mTask;
-
- @Test
- public void create_returnsActivityOptionWrapper() {
- TaskWrapper wrapper = TaskWrapper.create(mTask);
- assertThat(wrapper).isNotNull();
- assertThat(wrapper.toString()).isEqualTo(mTask.toString());
- }
-
- @Test
- public void create_returnsNull() {
- TaskWrapper wrapper = TaskWrapper.create(null);
- assertThat(wrapper).isNull();
- }
-}
diff --git a/builtInServices/tests/src/com/android/server/wm/WindowLayoutWrapperTest.java b/builtInServices/tests/src/com/android/server/wm/WindowLayoutWrapperTest.java
deleted file mode 100644
index 0d04d69..0000000
--- a/builtInServices/tests/src/com/android/server/wm/WindowLayoutWrapperTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.pm.ActivityInfo;
-import android.view.Gravity;
-
-import org.junit.Test;
-
-/**
- * This class contains unit tests for the {@link WindowLayoutWrapper}.
- */
-public final class WindowLayoutWrapperTest {
- @Test
- public void create_returnsActivityOptionWrapper() {
- ActivityInfo.WindowLayout layout = new ActivityInfo.WindowLayout(
- /* width= */ 1280, /* widthFraction= */ 0.5f,
- /* height= */ 800, /* heightFraction= */ 1.0f,
- /* gravity= */ Gravity.CENTER, /* minWidth= */ 400, /* minHeight= */ 300);
- WindowLayoutWrapper wrapper = WindowLayoutWrapper.create(layout);
- assertThat(wrapper).isNotNull();
- assertThat(wrapper.toString()).isEqualTo(layout.toString());
- }
-
- @Test
- public void create_returnsNull() {
- WindowLayoutWrapper wrapper = WindowLayoutWrapper.create(null);
- assertThat(wrapper).isNull();
- }
-}
diff --git a/builtInServices/src/com/android/internal/car/CarDevicePolicySafetyChecker.java b/src/com/android/internal/car/CarDevicePolicySafetyChecker.java
similarity index 98%
rename from builtInServices/src/com/android/internal/car/CarDevicePolicySafetyChecker.java
rename to src/com/android/internal/car/CarDevicePolicySafetyChecker.java
index 2ae2e63..0bc0c21 100644
--- a/builtInServices/src/com/android/internal/car/CarDevicePolicySafetyChecker.java
+++ b/src/com/android/internal/car/CarDevicePolicySafetyChecker.java
@@ -35,12 +35,12 @@
import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
import android.app.admin.DevicePolicyManagerLiteInternal;
import android.app.admin.DevicePolicySafetyChecker;
+import android.util.IndentingPrintWriter;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
-import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -48,8 +48,6 @@
/**
* Integrates {@link android.app.admin.DevicePolicyManager} operations with car UX restrictions.
- *
- * @hide
*/
final class CarDevicePolicySafetyChecker {
@@ -125,7 +123,7 @@
return mSafe.get();
}
- void dump(@NonNull PrintWriter pw) {
+ void dump(@NonNull IndentingPrintWriter pw) {
pw.printf("Safe to run device policy operations: %b\n", mSafe.get());
pw.printf("Unsafe operations: %s\n", Arrays.stream(UNSAFE_OPERATIONS)
.mapToObj(o -> operationToString(o)).collect(Collectors.toList()));
diff --git a/src/com/android/internal/car/CarServiceHelperService.java b/src/com/android/internal/car/CarServiceHelperService.java
new file mode 100644
index 0000000..8e82316
--- /dev/null
+++ b/src/com/android/internal/car/CarServiceHelperService.java
@@ -0,0 +1,796 @@
+/*
+ * Copyright (C) 2017 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.internal.car;
+
+import static com.android.car.internal.SystemConstants.ICAR_SYSTEM_SERVER_CLIENT;
+import static com.android.car.internal.common.CommonConstants.CAR_SERVICE_INTERFACE;
+import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STARTING;
+import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
+import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STOPPING;
+import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
+import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED;
+import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
+import android.app.admin.DevicePolicyManager.OperationSafetyReason;
+import android.app.admin.DevicePolicySafetyChecker;
+import android.automotive.watchdog.internal.ICarWatchdogMonitor;
+import android.automotive.watchdog.internal.PowerCycle;
+import android.automotive.watchdog.internal.StateType;
+import android.car.watchdoglib.CarWatchdogDaemonHelper;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.UserInfo;
+import android.hidl.manager.V1_0.IServiceManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.EventLog;
+import android.util.IndentingPrintWriter;
+import android.util.TimeUtils;
+
+import com.android.car.internal.ICarServiceHelper;
+import com.android.car.internal.ICarSystemServerClient;
+import com.android.car.internal.common.CommonConstants.UserLifecycleEventType;
+import com.android.car.internal.common.EventLogTags;
+import com.android.car.internal.common.UserHelperLite;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.IResultReceiver;
+import com.android.server.Dumpable;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.Watchdog;
+import com.android.server.am.ActivityManagerService;
+import com.android.server.pm.UserManagerInternal;
+import com.android.server.pm.UserManagerInternal.UserLifecycleListener;
+import com.android.server.utils.Slogf;
+import com.android.server.utils.TimingsTraceAndSlog;
+import com.android.server.wm.CarLaunchParamsModifier;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * System service side companion service for CarService. Starts car service and provide necessary
+ * API for CarService. Only for car product.
+ */
+public class CarServiceHelperService extends SystemService
+ implements Dumpable, DevicePolicySafetyChecker {
+
+ private static final String TAG = "CarServiceHelper";
+
+ // TODO(b/154033860): STOPSHIP if they're still true
+ private static final boolean DBG = true;
+ private static final boolean VERBOSE = true;
+
+ private static final String PROP_RESTART_RUNTIME = "ro.car.recovery.restart_runtime.enabled";
+
+ private static final List<String> CAR_HAL_INTERFACES_OF_INTEREST = Arrays.asList(
+ "android.hardware.automotive.vehicle@2.0::IVehicle",
+ "android.hardware.automotive.audiocontrol@1.0::IAudioControl",
+ "android.hardware.automotive.audiocontrol@2.0::IAudioControl"
+ );
+
+ // Message ID representing post-processing of process dumping.
+ private static final int WHAT_POST_PROCESS_DUMPING = 1;
+ // Message ID representing process killing.
+ private static final int WHAT_PROCESS_KILL = 2;
+ // Message ID representing service unresponsiveness.
+ private static final int WHAT_SERVICE_UNRESPONSIVE = 3;
+
+ private static final long CAR_SERVICE_BINDER_CALL_TIMEOUT = 15_000;
+
+ private static final long LIFECYCLE_TIMESTAMP_IGNORE = 0;
+
+ private final ICarServiceHelperImpl mHelper = new ICarServiceHelperImpl();
+ private final Context mContext;
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private IBinder mCarServiceBinder;
+ @GuardedBy("mLock")
+ private boolean mSystemBootCompleted;
+
+ private final CarLaunchParamsModifier mCarLaunchParamsModifier;
+
+ private final Handler mHandler;
+ private final HandlerThread mHandlerThread = new HandlerThread("CarServiceHelperService");
+
+ private final ProcessTerminator mProcessTerminator = new ProcessTerminator();
+ private final CarServiceConnectedCallback mCarServiceConnectedCallback =
+ new CarServiceConnectedCallback();
+ private final CarServiceProxy mCarServiceProxy;
+
+ /**
+ * End-to-end time (from process start) for unlocking the first non-system user.
+ */
+ private long mFirstUnlockedUserDuration;
+
+ private final CarWatchdogDaemonHelper mCarWatchdogDaemonHelper;
+ private final ICarWatchdogMonitorImpl mCarWatchdogMonitor = new ICarWatchdogMonitorImpl(this);
+ private final CarWatchdogDaemonHelper.OnConnectionChangeListener mConnectionListener =
+ (connected) -> {
+ if (connected) {
+ registerMonitorToWatchdogDaemon();
+ }
+ };
+
+ private final ServiceConnection mCarServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
+ if (DBG) {
+ Slogf.d(TAG, "onServiceConnected: %s", iBinder);
+ }
+ handleCarServiceConnection(iBinder);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName componentName) {
+ handleCarServiceCrash();
+ }
+ };
+
+ private final BroadcastReceiver mShutdownEventReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // Skip immediately if intent is not relevant to device shutdown.
+ // FLAG_RECEIVER_FOREGROUND is checked to ignore the intent from UserController when
+ // a user is stopped.
+ if ((!intent.getAction().equals(Intent.ACTION_REBOOT)
+ && !intent.getAction().equals(Intent.ACTION_SHUTDOWN))
+ || (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) == 0) {
+ return;
+ }
+ int powerCycle = PowerCycle.POWER_CYCLE_SHUTDOWN_ENTER;
+ try {
+ mCarWatchdogDaemonHelper.notifySystemStateChange(StateType.POWER_CYCLE,
+ powerCycle, /* arg2= */ 0);
+ if (DBG) {
+ Slogf.d(TAG, "Notified car watchdog daemon of power cycle(%d)", powerCycle);
+ }
+ } catch (RemoteException | RuntimeException e) {
+ Slogf.w(TAG, "Notifying power cycle state change failed: %s", e);
+ }
+ }
+ };
+
+ private final CarDevicePolicySafetyChecker mCarDevicePolicySafetyChecker;
+
+ public CarServiceHelperService(Context context) {
+ this(context,
+ new CarLaunchParamsModifier(context),
+ new CarWatchdogDaemonHelper(TAG),
+ null
+ );
+ }
+
+ @VisibleForTesting
+ CarServiceHelperService(
+ Context context,
+ CarLaunchParamsModifier carLaunchParamsModifier,
+ CarWatchdogDaemonHelper carWatchdogDaemonHelper,
+ CarServiceProxy carServiceOperationManager) {
+ super(context);
+
+ mContext = context;
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+ mCarLaunchParamsModifier = carLaunchParamsModifier;
+ mCarWatchdogDaemonHelper = carWatchdogDaemonHelper;
+ mCarServiceProxy =
+ carServiceOperationManager == null ? new CarServiceProxy(this)
+ : carServiceOperationManager;
+ UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
+ if (umi != null) {
+ umi.addUserLifecycleListener(new UserLifecycleListener() {
+ @Override
+ public void onUserCreated(UserInfo user, Object token) {
+ if (DBG) Slogf.d(TAG, "onUserCreated(): %s", user.toFullString());
+ }
+ @Override
+ public void onUserRemoved(UserInfo user) {
+ if (DBG) Slogf.d(TAG, "onUserRemoved(): $s", user.toFullString());
+ mCarServiceProxy.onUserRemoved(user);
+ }
+ });
+ } else {
+ Slogf.e(TAG, "UserManagerInternal not available - should only happen on unit tests");
+ }
+ mCarDevicePolicySafetyChecker = new CarDevicePolicySafetyChecker(this);
+ }
+ @Override
+ public void onBootPhase(int phase) {
+ EventLog.writeEvent(EventLogTags.CAR_HELPER_BOOT_PHASE, phase);
+ if (DBG) Slogf.d(TAG, "onBootPhase: %d", phase);
+
+ TimingsTraceAndSlog t = newTimingsTraceAndSlog();
+ if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+ t.traceBegin("onBootPhase.3pApps");
+ mCarLaunchParamsModifier.init();
+ setupAndStartUsers(t);
+ t.traceEnd();
+ } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
+ t.traceBegin("onBootPhase.completed");
+ synchronized (mLock) {
+ mSystemBootCompleted = true;
+ }
+ try {
+ mCarWatchdogDaemonHelper.notifySystemStateChange(
+ StateType.BOOT_PHASE, phase, /* arg2= */ 0);
+ } catch (RemoteException | RuntimeException e) {
+ Slogf.w(TAG, "Failed to notify boot phase change: %s", e);
+ }
+ t.traceEnd();
+ }
+ }
+
+ @Override
+ public void onStart() {
+ EventLog.writeEvent(EventLogTags.CAR_HELPER_START);
+
+ IntentFilter filter = new IntentFilter(Intent.ACTION_REBOOT);
+ filter.addAction(Intent.ACTION_SHUTDOWN);
+ mContext.registerReceiverForAllUsers(mShutdownEventReceiver, filter, null, null);
+ mCarWatchdogDaemonHelper.addOnConnectionChangeListener(mConnectionListener);
+ mCarWatchdogDaemonHelper.connect();
+ Intent intent = new Intent();
+ intent.setPackage("com.android.car");
+ intent.setAction(CAR_SERVICE_INTERFACE);
+ if (!mContext.bindServiceAsUser(intent, mCarServiceConnection, Context.BIND_AUTO_CREATE,
+ mHandler, UserHandle.SYSTEM)) {
+ Slogf.wtf(TAG, "cannot start car service");
+ }
+ loadNativeLibrary();
+ }
+
+ @Override
+ public void dump(IndentingPrintWriter pw, String[] args) {
+ if (args == null || args.length == 0 || args[0].equals("-a")) {
+ pw.printf("System boot completed: %b\n", mSystemBootCompleted);
+ pw.print("First unlocked user duration: ");
+ TimeUtils.formatDuration(mFirstUnlockedUserDuration, pw); pw.println();
+ pw.printf("Queued tasks: %d\n", mProcessTerminator.mQueuedTask);
+ mCarServiceProxy.dump(pw);
+ mCarDevicePolicySafetyChecker.dump(pw);
+ return;
+ }
+
+ if ("--user-metrics-only".equals(args[0])) {
+ mCarServiceProxy.dumpUserMetrics(pw);
+ return;
+ }
+
+ if ("--is-operation-safe".equals(args[0]) & args.length > 1) {
+ String arg1 = args[1];
+ int operation = 0;
+ try {
+ operation = Integer.parseInt(arg1);
+ } catch (Exception e) {
+ pw.printf("Invalid operation type: %s\n", arg1);
+ return;
+
+ }
+ int reason = getUnsafeOperationReason(operation);
+ boolean safe = reason == DevicePolicyManager.OPERATION_SAFETY_REASON_NONE;
+ pw.printf("Operation %s is %s. Reason: %s\n",
+ DevicePolicyManager.operationToString(operation),
+ safe ? "SAFE" : "UNSAFE",
+ DevicePolicyManager.operationSafetyReasonToString(reason));
+ return;
+ }
+ pw.printf("Invalid args: %s\n", Arrays.toString(args));
+ }
+
+ @Override
+ public String getDumpableName() {
+ return "CarServiceHelper";
+ }
+
+ @Override
+ public void onUserUnlocking(@NonNull TargetUser user) {
+ if (isPreCreated(user, USER_LIFECYCLE_EVENT_TYPE_UNLOCKING)) return;
+ EventLog.writeEvent(EventLogTags.CAR_HELPER_USER_UNLOCKING, user.getUserIdentifier());
+ if (DBG) Slogf.d(TAG, "onUserUnlocking(%s)", user);
+
+ sendUserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING, user);
+ }
+
+ @Override
+ public void onUserUnlocked(@NonNull TargetUser user) {
+ if (isPreCreated(user, USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)) return;
+ int userId = user.getUserIdentifier();
+ EventLog.writeEvent(EventLogTags.CAR_HELPER_USER_UNLOCKED, userId);
+ if (DBG) Slogf.d(TAG, "onUserUnlocked(%s)", user);
+
+ if (mFirstUnlockedUserDuration == 0 && !UserHelperLite.isHeadlessSystemUser(userId)) {
+ mFirstUnlockedUserDuration = SystemClock.elapsedRealtime()
+ - Process.getStartElapsedRealtime();
+ Slogf.i(TAG, "Time to unlock 1st user(%s): %s", user,
+ TimeUtils.formatDuration(mFirstUnlockedUserDuration));
+ }
+ sendUserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, user);
+ }
+
+ @Override
+ public void onUserStarting(@NonNull TargetUser user) {
+ if (isPreCreated(user, USER_LIFECYCLE_EVENT_TYPE_STARTING)) return;
+ EventLog.writeEvent(EventLogTags.CAR_HELPER_USER_STARTING, user.getUserIdentifier());
+ if (DBG) Slogf.d(TAG, "onUserStarting(%s)", user);
+
+ sendUserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING, user);
+ }
+
+ @Override
+ public void onUserStopping(@NonNull TargetUser user) {
+ if (isPreCreated(user, USER_LIFECYCLE_EVENT_TYPE_STOPPING)) return;
+ EventLog.writeEvent(EventLogTags.CAR_HELPER_USER_STOPPING, user.getUserIdentifier());
+ if (DBG) Slogf.d(TAG, "onUserStopping(%s)", user);
+
+ sendUserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPING, user);
+ int userId = user.getUserIdentifier();
+ mCarLaunchParamsModifier.handleUserStopped(userId);
+ }
+
+ @Override
+ public void onUserStopped(@NonNull TargetUser user) {
+ if (isPreCreated(user, USER_LIFECYCLE_EVENT_TYPE_STOPPED)) return;
+ EventLog.writeEvent(EventLogTags.CAR_HELPER_USER_STOPPED, user.getUserIdentifier());
+ if (DBG) Slogf.d(TAG, "onUserStopped(%s)", user);
+
+ sendUserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STOPPED, user);
+ }
+
+ @Override
+ public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+ if (isPreCreated(to, USER_LIFECYCLE_EVENT_TYPE_SWITCHING)) return;
+ EventLog.writeEvent(EventLogTags.CAR_HELPER_USER_SWITCHING,
+ from == null ? UserHandle.USER_NULL : from.getUserIdentifier(),
+ to.getUserIdentifier());
+ if (DBG) Slogf.d(TAG, "onUserSwitching(%s>>%s)", from, to);
+
+ mCarServiceProxy.sendUserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING,
+ from, to);
+ int userId = to.getUserIdentifier();
+ mCarLaunchParamsModifier.handleCurrentUserSwitching(userId);
+ }
+
+ @Override // from DevicePolicySafetyChecker
+ @OperationSafetyReason
+ public int getUnsafeOperationReason(@DevicePolicyOperation int operation) {
+ return mCarDevicePolicySafetyChecker.isDevicePolicyOperationSafe(operation)
+ ? DevicePolicyManager.OPERATION_SAFETY_REASON_NONE
+ : DevicePolicyManager.OPERATION_SAFETY_REASON_DRIVING_DISTRACTION;
+ }
+
+ @Override // from DevicePolicySafetyChecker
+ public boolean isSafeOperation(@OperationSafetyReason int reason) {
+ return mCarDevicePolicySafetyChecker.isSafe();
+ }
+
+ @Override // from DevicePolicySafetyChecker
+ public void onFactoryReset(IResultReceiver callback) {
+ if (DBG) Slogf.d(TAG, "onFactoryReset: %s", callback);
+
+ mCarServiceProxy.onFactoryReset(callback);
+ }
+
+ @VisibleForTesting
+ void loadNativeLibrary() {
+ System.loadLibrary("car-framework-service-jni");
+ }
+
+ private boolean isPreCreated(@NonNull TargetUser user, @UserLifecycleEventType int eventType) {
+ if (!user.isPreCreated()) return false;
+
+ if (DBG) {
+ Slogf.d(TAG, "Ignoring event of type %d for pre-created user %s", eventType, user);
+ }
+ return true;
+ }
+
+ @VisibleForTesting
+ void handleCarServiceConnection(IBinder iBinder) {
+ synchronized (mLock) {
+ if (mCarServiceBinder == iBinder) {
+ return; // already connected.
+ }
+ Slogf.i(TAG, "car service binder changed, was %s new: %s", mCarServiceBinder, iBinder);
+ mCarServiceBinder = iBinder;
+ Slogf.i(TAG, "**CarService connected**");
+ }
+
+ sendSetSystemServerConnectionsCall();
+
+ mHandler.removeMessages(WHAT_SERVICE_UNRESPONSIVE);
+ mHandler.sendMessageDelayed(
+ obtainMessage(CarServiceHelperService::handleCarServiceUnresponsive, this)
+ .setWhat(WHAT_SERVICE_UNRESPONSIVE), CAR_SERVICE_BINDER_CALL_TIMEOUT);
+ }
+
+ private TimingsTraceAndSlog newTimingsTraceAndSlog() {
+ return new TimingsTraceAndSlog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
+
+ private void setupAndStartUsers(@NonNull TimingsTraceAndSlog t) {
+ // TODO(b/156263735): decide if it should return in case the device's on Retail Mode
+ t.traceBegin("setupAndStartUsers");
+ mCarServiceProxy.initBootUser();
+ t.traceEnd();
+ }
+
+ private void handleCarServiceUnresponsive() {
+ // This should not happen. Calling this method means ICarSystemServerClient binder is not
+ // returned after service connection. and CarService has not connected in the given time.
+ Slogf.w(TAG, "*** CARHELPER KILLING SYSTEM PROCESS: CarService unresponsive.");
+ Slogf.w(TAG, "*** GOODBYE!");
+ Process.killProcess(Process.myPid());
+ System.exit(10);
+ }
+
+ private void sendSetSystemServerConnectionsCall() {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(CAR_SERVICE_INTERFACE);
+ data.writeStrongBinder(mHelper.asBinder());
+ data.writeStrongBinder(mCarServiceConnectedCallback.asBinder());
+ IBinder binder;
+ synchronized (mLock) {
+ binder = mCarServiceBinder;
+ }
+ int code = IBinder.FIRST_CALL_TRANSACTION;
+ try {
+ if (VERBOSE) Slogf.v(TAG, "calling one-way binder transaction with code %d", code);
+ // oneway void setSystemServerConnections(in IBinder helper, in IBinder receiver) = 0;
+ binder.transact(code, data, null, Binder.FLAG_ONEWAY);
+ if (VERBOSE) Slogf.v(TAG, "finished one-way binder transaction with code %d", code);
+ } catch (RemoteException e) {
+ Slogf.w(TAG, "RemoteException from car service", e);
+ handleCarServiceCrash();
+ } catch (RuntimeException e) {
+ Slogf.wtf(TAG, e, "Exception calling binder transaction (real code: %d)", code);
+ throw e;
+ } finally {
+ data.recycle();
+ }
+ }
+
+ private void sendUserLifecycleEvent(@UserLifecycleEventType int eventType,
+ @NonNull TargetUser user) {
+ mCarServiceProxy.sendUserLifecycleEvent(eventType, /* from= */ null, user);
+ }
+
+ // Adapted from frameworks/base/services/core/java/com/android/server/Watchdog.java
+ // TODO(b/131861630) use implementation common with Watchdog.java
+ //
+ private static ArrayList<Integer> getInterestingHalPids() {
+ try {
+ IServiceManager serviceManager = IServiceManager.getService();
+ ArrayList<IServiceManager.InstanceDebugInfo> dump =
+ serviceManager.debugDump();
+ HashSet<Integer> pids = new HashSet<>();
+ for (IServiceManager.InstanceDebugInfo info : dump) {
+ if (info.pid == IServiceManager.PidConstant.NO_PID) {
+ continue;
+ }
+
+ if (Watchdog.HAL_INTERFACES_OF_INTEREST.contains(info.interfaceName) ||
+ CAR_HAL_INTERFACES_OF_INTEREST.contains(info.interfaceName)) {
+ pids.add(info.pid);
+ }
+ }
+
+ return new ArrayList<Integer>(pids);
+ } catch (RemoteException e) {
+ return new ArrayList<Integer>();
+ }
+ }
+
+ // Adapted from frameworks/base/services/core/java/com/android/server/Watchdog.java
+ // TODO(b/131861630) use implementation common with Watchdog.java
+ //
+ private static ArrayList<Integer> getInterestingNativePids() {
+ ArrayList<Integer> pids = getInterestingHalPids();
+
+ int[] nativePids = Process.getPidsForCommands(Watchdog.NATIVE_STACKS_OF_INTEREST);
+ if (nativePids != null) {
+ pids.ensureCapacity(pids.size() + nativePids.length);
+ for (int i : nativePids) {
+ pids.add(i);
+ }
+ }
+
+ return pids;
+ }
+
+ // Borrowed from Watchdog.java. Create an ANR file from the call stacks.
+ //
+ private static void dumpServiceStacks() {
+ ArrayList<Integer> pids = new ArrayList<>();
+ pids.add(Process.myPid());
+
+ ActivityManagerService.dumpStackTraces(
+ pids, null, null, getInterestingNativePids(), null);
+ }
+
+ @VisibleForTesting
+ void handleCarServiceCrash() {
+ // Recovery behavior. Kill the system server and reset
+ // everything if enabled by the property.
+ boolean restartOnServiceCrash = SystemProperties.getBoolean(PROP_RESTART_RUNTIME, false);
+
+ mHandler.removeMessages(WHAT_SERVICE_UNRESPONSIVE);
+
+ dumpServiceStacks();
+ if (restartOnServiceCrash) {
+ Slogf.w(TAG, "*** CARHELPER KILLING SYSTEM PROCESS: CarService crash");
+ Slogf.w(TAG, "*** GOODBYE!");
+ Process.killProcess(Process.myPid());
+ System.exit(10);
+ } else {
+ Slogf.w(TAG, "*** CARHELPER ignoring: CarService crash");
+ }
+ }
+
+ private void handleClientsNotResponding(@NonNull int[] pids) {
+ mProcessTerminator.requestTerminateProcess(pids);
+ }
+
+ private void registerMonitorToWatchdogDaemon() {
+ try {
+ mCarWatchdogDaemonHelper.registerMonitor(mCarWatchdogMonitor);
+ } catch (RemoteException | RuntimeException e) {
+ Slogf.w(TAG, "Cannot register to car watchdog daemon: %s", e);
+ }
+ }
+
+ private void killProcessAndReportToMonitor(int pid) {
+ String processName = getProcessName(pid);
+ Process.killProcess(pid);
+ Slogf.w(TAG, "carwatchdog killed %s (pid: %d)", processName, pid);
+ try {
+ mCarWatchdogDaemonHelper.tellDumpFinished(mCarWatchdogMonitor, pid);
+ } catch (RemoteException | RuntimeException e) {
+ Slogf.w(TAG, "Cannot report monitor result to car watchdog daemon: %s", e);
+ }
+ }
+
+ private static String getProcessName(int pid) {
+ String unknownProcessName = "unknown process";
+ String filename = "/proc/" + pid + "/cmdline";
+ try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
+ String line = reader.readLine().replace('\0', ' ').trim();
+ int index = line.indexOf(' ');
+ if (index != -1) {
+ line = line.substring(0, index);
+ }
+ return Paths.get(line).getFileName().toString();
+ } catch (IOException e) {
+ Slogf.w(TAG, "Cannot read %s", filename);
+ return unknownProcessName;
+ }
+ }
+
+ private static native int nativeForceSuspend(int timeoutMs);
+
+ // TODO(b/173664653): it's missing unit tests (for example, to make sure that
+ // when its setSafetyMode() is called, mCarDevicePolicySafetyChecker is updated).
+ private class ICarServiceHelperImpl extends ICarServiceHelper.Stub {
+ /**
+ * Force device to suspend
+ */
+ @Override // Binder call
+ public int forceSuspend(int timeoutMs) {
+ int retVal;
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ retVal = nativeForceSuspend(timeoutMs);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ return retVal;
+ }
+
+ @Override
+ public void setDisplayAllowlistForUser(@UserIdInt int userId, int[] displayIds) {
+ mCarLaunchParamsModifier.setDisplayAllowListForUser(userId, displayIds);
+ }
+
+ @Override
+ public void setPassengerDisplays(int[] displayIdsForPassenger) {
+ mCarLaunchParamsModifier.setPassengerDisplays(displayIdsForPassenger);
+ }
+
+ @Override
+ public void setSourcePreferredComponents(boolean enableSourcePreferred,
+ @Nullable List<ComponentName> sourcePreferredComponents) {
+ mCarLaunchParamsModifier.setSourcePreferredComponents(
+ enableSourcePreferred, sourcePreferredComponents);
+ }
+
+ @Override
+ public void setSafetyMode(boolean safe) {
+ mCarDevicePolicySafetyChecker.setSafe(safe);
+ }
+
+ @Override
+ public UserInfo createUserEvenWhenDisallowed(String name, String userType, int flags) {
+ if (DBG) {
+ Slogf.d(TAG, "createUserEvenWhenDisallowed(): name=%s, type=%s, flags=%s",
+ UserHelperLite.safeName(name), userType, UserInfo.flagsToString(flags));
+ }
+ UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
+ try {
+ UserInfo user = umi.createUserEvenWhenDisallowed(name, userType, flags,
+ /* disallowedPackages= */ null, /* token= */ null);
+ if (DBG) {
+ Slogf.d(TAG, "User created: %s", (user == null ? "null" : user.toFullString()));
+ }
+ // TODO(b/172691310): decide if user should be affiliated when DeviceOwner is set
+ return user;
+ } catch (UserManager.CheckedUserOperationException e) {
+ Slogf.e(TAG, "Error creating user", e);
+ return null;
+ }
+ }
+ }
+
+ private class ICarWatchdogMonitorImpl extends ICarWatchdogMonitor.Stub {
+ private final WeakReference<CarServiceHelperService> mService;
+
+ private ICarWatchdogMonitorImpl(CarServiceHelperService service) {
+ mService = new WeakReference<>(service);
+ }
+
+ @Override
+ public void onClientsNotResponding(int[] pids) {
+ CarServiceHelperService service = mService.get();
+ if (service == null || pids == null || pids.length == 0) {
+ return;
+ }
+ service.handleClientsNotResponding(pids);
+ }
+ }
+
+ private final class ProcessTerminator {
+
+ private static final long ONE_SECOND_MS = 1_000L;
+
+ private final Object mProcessLock = new Object();
+ private ExecutorService mExecutor;
+ @GuardedBy("mProcessLock")
+ private int mQueuedTask;
+
+ public void requestTerminateProcess(@NonNull int[] pids) {
+ synchronized (mProcessLock) {
+ // If there is a running thread, we re-use it instead of starting a new thread.
+ if (mExecutor == null) {
+ mExecutor = Executors.newSingleThreadExecutor();
+ }
+ mQueuedTask++;
+ }
+ mExecutor.execute(() -> {
+ for (int pid : pids) {
+ dumpAndKillProcess(pid);
+ }
+ // mExecutor will be stopped from the main thread, if there is no queued task.
+ mHandler.sendMessage(obtainMessage(ProcessTerminator::postProcessing, this)
+ .setWhat(WHAT_POST_PROCESS_DUMPING));
+ });
+ }
+
+ private void postProcessing() {
+ synchronized (mProcessLock) {
+ mQueuedTask--;
+ if (mQueuedTask == 0) {
+ mExecutor.shutdown();
+ mExecutor = null;
+ }
+ }
+ }
+
+ private void dumpAndKillProcess(int pid) {
+ if (DBG) {
+ Slogf.d(TAG, "Dumping and killing process(pid: %d)", pid);
+ }
+ ArrayList<Integer> javaPids = new ArrayList<>(1);
+ ArrayList<Integer> nativePids = new ArrayList<>();
+ try {
+ if (isJavaApp(pid)) {
+ javaPids.add(pid);
+ } else {
+ nativePids.add(pid);
+ }
+ } catch (IOException e) {
+ Slogf.w(TAG, "Cannot get process information: %s", e);
+ return;
+ }
+ nativePids.addAll(getInterestingNativePids());
+ long startDumpTime = SystemClock.uptimeMillis();
+ ActivityManagerService.dumpStackTraces(javaPids, null, null, nativePids, null);
+ long dumpTime = SystemClock.uptimeMillis() - startDumpTime;
+ if (DBG) {
+ Slogf.d(TAG, "Dumping process took %dms", dumpTime);
+ }
+ // To give clients a chance of wrapping up before the termination.
+ if (dumpTime < ONE_SECOND_MS) {
+ mHandler.sendMessageDelayed(obtainMessage(
+ CarServiceHelperService::killProcessAndReportToMonitor,
+ CarServiceHelperService.this, pid).setWhat(WHAT_PROCESS_KILL),
+ ONE_SECOND_MS - dumpTime);
+ } else {
+ killProcessAndReportToMonitor(pid);
+ }
+ }
+
+ private boolean isJavaApp(int pid) throws IOException {
+ Path exePath = new File("/proc/" + pid + "/exe").toPath();
+ String target = Files.readSymbolicLink(exePath).toString();
+ // Zygote's target exe is also /system/bin/app_process32 or /system/bin/app_process64.
+ // But, we can be very sure that Zygote will not be the client of car watchdog daemon.
+ return target == "/system/bin/app_process32" || target == "/system/bin/app_process64";
+ }
+ }
+
+ private final class CarServiceConnectedCallback extends IResultReceiver.Stub {
+ @Override
+ public void send(int resultCode, Bundle resultData) {
+ mHandler.removeMessages(WHAT_SERVICE_UNRESPONSIVE);
+
+ IBinder binder;
+ if (resultData == null
+ || (binder = resultData.getBinder(ICAR_SYSTEM_SERVER_CLIENT)) == null) {
+ Slogf.wtf(TAG, "setSystemServerConnections return NULL Binder.");
+ handleCarServiceUnresponsive();
+ return;
+ }
+
+ ICarSystemServerClient carService = ICarSystemServerClient.Stub.asInterface(binder);
+ mCarServiceProxy.handleCarServiceConnection(carService);
+ }
+ }
+}
diff --git a/updatableServices/src/com/android/internal/car/updatable/CarServiceProxy.java b/src/com/android/internal/car/CarServiceProxy.java
similarity index 65%
rename from updatableServices/src/com/android/internal/car/updatable/CarServiceProxy.java
rename to src/com/android/internal/car/CarServiceProxy.java
index 0824755..42c344b 100644
--- a/updatableServices/src/com/android/internal/car/updatable/CarServiceProxy.java
+++ b/src/com/android/internal/car/CarServiceProxy.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.car.updatable;
+package com.android.internal.car;
import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STARTING;
import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
@@ -27,22 +27,23 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.car.ICarResultReceiver;
-import android.car.builtin.os.UserManagerHelper;
-import android.car.builtin.util.Slogf;
-import android.car.builtin.util.TimingsTraceLog;
+import android.content.pm.UserInfo;
import android.os.RemoteException;
+import android.os.Trace;
import android.os.UserHandle;
+import android.util.DebugUtils;
+import android.util.IndentingPrintWriter;
+import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import com.android.car.internal.ICarSystemServerClient;
import com.android.car.internal.common.CommonConstants.UserLifecycleEventType;
-import com.android.car.internal.util.DebugUtils;
-import com.android.car.internal.util.IndentingPrintWriter;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.IResultReceiver;
import com.android.internal.util.Preconditions;
+import com.android.server.SystemService.TargetUser;
+import com.android.server.utils.TimingsTraceAndSlog;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -88,13 +89,10 @@
@Retention(RetentionPolicy.SOURCE)
public @interface PendingOperationId{}
- @VisibleForTesting
- static final String TAG = CarServiceProxy.class.getSimpleName();
-
- private static final long TRACE_TAG_SYSTEM_SERVER = 1L << 19;
private static final boolean DBG = false;
+ private static final String TAG = CarServiceProxy.class.getSimpleName();
- private static final int USER_SYSTEM = UserHandle.SYSTEM.getIdentifier();
+ private static final long LIFECYCLE_TIMESTAMP_IGNORE = 0;
private final Object mLock = new Object();
@@ -102,10 +100,10 @@
private boolean mCarServiceCrashed;
@UserIdInt
@GuardedBy("mLock")
- private int mLastSwitchedUser = UserManagerHelper.USER_NULL;
+ private int mLastSwitchedUser = UserHandle.USER_NULL;
@UserIdInt
@GuardedBy("mLock")
- private int mPreviousUserOfLastSwitchedUser = UserManagerHelper.USER_NULL;
+ private int mPreviousUserOfLastSwitchedUser = UserHandle.USER_NULL;
// Key: user id, value: life-cycle
@GuardedBy("mLock")
private final SparseIntArray mLastUserLifecycle = new SparseIntArray();
@@ -116,21 +114,19 @@
@GuardedBy("mLock")
private ICarSystemServerClient mCarService;
- private final CarServiceHelperServiceUpdatableImpl mCarServiceHelperServiceUpdatableImpl;
+ private final CarServiceHelperService mCarServiceHelperService;
private final UserMetrics mUserMetrics = new UserMetrics();
- @GuardedBy("mLock")
- private UserHandle mInitialUser;
- CarServiceProxy(CarServiceHelperServiceUpdatableImpl carServiceHelperServiceUpdatableImpl) {
- mCarServiceHelperServiceUpdatableImpl = carServiceHelperServiceUpdatableImpl;
+ CarServiceProxy(CarServiceHelperService carServiceHelperService) {
+ mCarServiceHelperService = carServiceHelperService;
}
/**
* Handles new CarService Connection.
*/
void handleCarServiceConnection(ICarSystemServerClient carService) {
- Slogf.i(TAG, "CarService connected.");
- TimingsTraceLog t = newTimingsTraceLog();
+ Slog.i(TAG, "CarService connected.");
+ TimingsTraceAndSlog t = newTimingsTraceAndSlog();
t.traceBegin("handleCarServiceConnection");
synchronized (mLock) {
mCarService = carService;
@@ -140,37 +136,9 @@
runQueuedOperationLocked(PO_ON_FACTORY_RESET);
}
sendLifeCycleEvents();
- sendInitialUser();
t.traceEnd();
}
- private void sendInitialUser() {
- UserHandle initialUser;
- ICarSystemServerClient carService;
- synchronized (mLock) {
- initialUser = mInitialUser;
- carService = mCarService;
- }
- if (initialUser != null && carService != null) {
- try {
- carService.setInitialUser(initialUser);
- } catch (RemoteException e) {
- Slogf.w(TAG, "RemoteException from car service while calling setInitialUser.", e);
- }
- } else {
- Slogf.i(TAG, "Didn't send Initial User, User: %s, CarService: %s", initialUser,
- carService);
- }
- }
-
- void saveInitialUser(UserHandle user) {
- synchronized (mLock) {
- if (user != null || user.getIdentifier() != UserManagerHelper.USER_NULL) {
- mInitialUser = user;
- }
- }
- }
-
@GuardedBy("mLock")
private void runQueuedOperationLocked(@PendingOperationId int operationId) {
PendingOperation pendingOperation = mPendingOperations.get(operationId);
@@ -179,7 +147,7 @@
return;
}
if (DBG) {
- Slogf.d(TAG, "No queued operation of type " + pendingOperationToString(operationId));
+ Slog.d(TAG, "No queued operation of type " + pendingOperationToString(operationId));
}
}
@@ -193,14 +161,13 @@
}
// Send user0 events first
- int user0Lifecycle = lastUserLifecycle.get(USER_SYSTEM);
- boolean user0IsCurrent = lastSwitchedUser == USER_SYSTEM;
+ int user0Lifecycle = lastUserLifecycle.get(UserHandle.USER_SYSTEM);
+ boolean user0IsCurrent = lastSwitchedUser == UserHandle.USER_SYSTEM;
// If user0Lifecycle is 0, then no life-cycle event received yet.
if (user0Lifecycle != 0) {
- sendAllLifecyleToUser(USER_SYSTEM, user0Lifecycle,
- user0IsCurrent);
+ sendAllLifecyleToUser(UserHandle.USER_SYSTEM, user0Lifecycle, user0IsCurrent);
}
- lastUserLifecycle.delete(USER_SYSTEM);
+ lastUserLifecycle.delete(UserHandle.USER_SYSTEM);
// Send current user events next
if (!user0IsCurrent) {
@@ -225,28 +192,28 @@
private void sendAllLifecyleToUser(@UserIdInt int userId, int lifecycle,
boolean isCurrentUser) {
if (DBG) {
- Slogf.d(TAG, "sendAllLifecyleToUser, user:" + userId + " lifecycle:" + lifecycle);
+ Slog.d(TAG, "sendAllLifecyleToUser, user:" + userId + " lifecycle:" + lifecycle);
}
if (lifecycle >= USER_LIFECYCLE_EVENT_TYPE_STARTING) {
- sendUserLifecycleEventInternal(USER_LIFECYCLE_EVENT_TYPE_STARTING,
- UserManagerHelper.USER_NULL, userId);
+ sendUserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_STARTING, UserHandle.USER_NULL,
+ userId);
}
- if (isCurrentUser && userId != USER_SYSTEM) {
+ if (isCurrentUser && userId != UserHandle.USER_SYSTEM) {
synchronized (mLock) {
- sendUserLifecycleEventInternal(USER_LIFECYCLE_EVENT_TYPE_SWITCHING,
+ sendUserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_SWITCHING,
mPreviousUserOfLastSwitchedUser, userId);
}
}
if (lifecycle >= USER_LIFECYCLE_EVENT_TYPE_UNLOCKING) {
- sendUserLifecycleEventInternal(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING,
- UserManagerHelper.USER_NULL, userId);
+ sendUserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING, UserHandle.USER_NULL,
+ userId);
}
if (lifecycle >= USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) {
- sendUserLifecycleEventInternal(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED,
- UserManagerHelper.USER_NULL, userId);
+ sendUserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED, UserHandle.USER_NULL,
+ userId);
}
}
@@ -254,7 +221,7 @@
* Initializes boot user.
*/
void initBootUser() {
- if (DBG) Slogf.d(TAG, "initBootUser()");
+ if (DBG) Slog.d(TAG, "initBootUser()");
saveOrRun(PO_INIT_BOOT_USER);
}
@@ -263,8 +230,8 @@
/**
* Callback to indifcate the given user was removed.
*/
- void onUserRemoved(@NonNull UserHandle user) {
- if (DBG) Slogf.d(TAG, "onUserRemoved(): " + user);
+ void onUserRemoved(@NonNull UserInfo user) {
+ if (DBG) Slog.d(TAG, "onUserRemoved(): " + user.toFullString());
saveOrRun(PO_ON_USER_REMOVED, user);
}
@@ -273,8 +240,8 @@
/**
* Callback to ask user to confirm if it's ok to factory reset the device.
*/
- void onFactoryReset(@NonNull ICarResultReceiver callback) {
- if (DBG) Slogf.d(TAG, "onFactoryReset(): " + callback);
+ void onFactoryReset(@NonNull IResultReceiver callback) {
+ if (DBG) Slog.d(TAG, "onFactoryReset(): " + callback);
saveOrRun(PO_ON_FACTORY_RESET, callback);
}
@@ -287,7 +254,7 @@
synchronized (mLock) {
if (mCarService == null) {
if (DBG) {
- Slogf.d(TAG, "CarService null. Operation "
+ Slog.d(TAG, "CarService null. Operation "
+ pendingOperationToString(operationId)
+ (value == null ? "" : "(" + value + ")") + " deferred.");
}
@@ -305,22 +272,20 @@
@GuardedBy("mLock")
private void runLocked(@PendingOperationId int operationId, @Nullable Object value) {
- if (DBG) {
- Slogf.d(TAG, "runLocked(): " + pendingOperationToString(operationId) + "/" + value);
- }
+ if (DBG) Slog.d(TAG, "runLocked(): " + pendingOperationToString(operationId) + "/" + value);
try {
if (isServiceCrashedLoggedLocked(operationId)) {
return;
}
sendCarServiceActionLocked(operationId, value);
if (operationId == PO_ON_FACTORY_RESET) {
- if (DBG) Slogf.d(TAG, "NOT removing " + pendingOperationToString(operationId));
+ if (DBG) Slog.d(TAG, "NOT removing " + pendingOperationToString(operationId));
return;
}
- if (DBG) Slogf.d(TAG, "removing " + pendingOperationToString(operationId));
+ if (DBG) Slog.d(TAG, "removing " + pendingOperationToString(operationId));
mPendingOperations.delete(operationId);
} catch (RemoteException e) {
- Slogf.w(TAG, "RemoteException from car service", e);
+ Slog.w(TAG, "RemoteException from car service", e);
handleCarServiceCrash();
}
}
@@ -332,22 +297,22 @@
if (pendingOperation == null) {
pendingOperation = new PendingOperation(operationId, value);
- if (DBG) Slogf.d(TAG, "Created " + pendingOperation);
+ if (DBG) Slog.d(TAG, "Created " + pendingOperation);
mPendingOperations.put(operationId, pendingOperation);
return;
}
switch (operationId) {
case PO_ON_USER_REMOVED:
- Preconditions.checkArgument((value instanceof UserHandle),
+ Preconditions.checkArgument((value instanceof UserInfo),
"invalid value passed to ON_USER_REMOVED", value);
if (pendingOperation.value instanceof ArrayList) {
- if (DBG) Slogf.d(TAG, "Adding " + value + " to existing " + pendingOperation);
+ if (DBG) Slog.d(TAG, "Adding " + value + " to existing " + pendingOperation);
((ArrayList) pendingOperation.value).add(value);
- } else if (pendingOperation.value instanceof UserHandle) {
+ } else if (pendingOperation.value instanceof UserInfo) {
ArrayList<Object> list = new ArrayList<>(2);
list.add(pendingOperation.value);
list.add(value);
- if (DBG) Slogf.d(TAG, "Converting " + pendingOperation.value + " to " + list);
+ if (DBG) Slog.d(TAG, "Converting " + pendingOperation.value + " to " + list);
pendingOperation.value = list;
} else {
throw new IllegalStateException("Invalid value for ON_USER_REMOVED: " + value);
@@ -355,12 +320,12 @@
break;
case PO_ON_FACTORY_RESET:
PendingOperation newOperation = new PendingOperation(operationId, value);
- if (DBG) Slogf.d(TAG, "Replacing " + pendingOperation + " by " + newOperation);
+ if (DBG) Slog.d(TAG, "Replacing " + pendingOperation + " by " + newOperation);
mPendingOperations.put(operationId, newOperation);
break;
default:
if (DBG) {
- Slogf.d(TAG, "Already saved operation of type "
+ Slog.d(TAG, "Already saved operation of type "
+ pendingOperationToString(operationId));
}
}
@@ -370,7 +335,7 @@
private void sendCarServiceActionLocked(@PendingOperationId int operationId,
@Nullable Object value) throws RemoteException {
if (DBG) {
- Slogf.d(TAG, "sendCarServiceActionLocked: Operation "
+ Slog.d(TAG, "sendCarServiceActionLocked: Operation "
+ pendingOperationToString(operationId));
}
switch (operationId) {
@@ -380,7 +345,7 @@
case PO_ON_USER_REMOVED:
if (value instanceof ArrayList) {
ArrayList<Object> list = (ArrayList<Object>) value;
- if (DBG) Slogf.d(TAG, "Sending " + list.size() + " onUserRemoved() calls");
+ if (DBG) Slog.d(TAG, "Sending " + list.size() + " onUserRemoved() calls");
for (Object user: list) {
onUserRemovedLocked(user);
}
@@ -389,56 +354,58 @@
}
break;
case PO_ON_FACTORY_RESET:
- mCarService.onFactoryReset((ICarResultReceiver) value);
+ mCarService.onFactoryReset((IResultReceiver) value);
break;
default:
- Slogf.wtf(TAG, "Invalid Operation. OperationId -" + operationId);
+ Slog.wtf(TAG, "Invalid Operation. OperationId -" + operationId);
}
}
@GuardedBy("mLock")
private void onUserRemovedLocked(@NonNull Object value) throws RemoteException {
- Preconditions.checkArgument((value instanceof UserHandle),
+ Preconditions.checkArgument((value instanceof UserInfo),
"Invalid value for ON_USER_REMOVED: %s", value);
- UserHandle user = (UserHandle) value;
- if (DBG) Slogf.d(TAG, "Sending onUserRemoved(): " + user);
+ UserInfo user = (UserInfo) value;
+ if (DBG) Slog.d(TAG, "Sending onUserRemoved(): " + user.toFullString());
mCarService.onUserRemoved(user);
}
/**
* Sends user life-cycle events to CarService.
*/
- void sendUserLifecycleEvent(@UserLifecycleEventType int eventType, @UserIdInt int fromId,
- @UserIdInt int toId) {
+ void sendUserLifecycleEvent(@UserLifecycleEventType int eventType, @Nullable TargetUser from,
+ @NonNull TargetUser to) {
long now = System.currentTimeMillis();
+ int fromId = from == null ? UserHandle.USER_NULL : from.getUserIdentifier();
+ int toId = to.getUserIdentifier();
mUserMetrics.onEvent(eventType, now, fromId, toId);
synchronized (mLock) {
if (eventType == USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
- mLastSwitchedUser = toId;
- mPreviousUserOfLastSwitchedUser = fromId;
- mLastUserLifecycle.put(toId, eventType);
+ mLastSwitchedUser = to.getUserIdentifier();
+ mPreviousUserOfLastSwitchedUser = from.getUserIdentifier();
+ mLastUserLifecycle.put(to.getUserIdentifier(), eventType);
} else if (eventType == USER_LIFECYCLE_EVENT_TYPE_STOPPING
|| eventType == USER_LIFECYCLE_EVENT_TYPE_STOPPED) {
- mLastUserLifecycle.delete(toId);
+ mLastUserLifecycle.delete(to.getUserIdentifier());
} else {
- mLastUserLifecycle.put(toId, eventType);
+ mLastUserLifecycle.put(to.getUserIdentifier(), eventType);
}
if (mCarService == null) {
if (DBG) {
- Slogf.d(TAG, "CarService null. sendUserLifecycleEvent() deferred for lifecycle"
- + " event " + eventType + " for user " + toId);
+ Slog.d(TAG, "CarService null. sendUserLifecycleEvent() deferred for lifecycle"
+ + " event " + eventType + " for user " + to);
}
return;
}
}
- sendUserLifecycleEventInternal(eventType, fromId, toId);
+ sendUserLifecycleEvent(eventType, fromId, toId);
}
- private void sendUserLifecycleEventInternal(@UserLifecycleEventType int eventType,
+ private void sendUserLifecycleEvent(@UserLifecycleEventType int eventType,
@UserIdInt int fromId, @UserIdInt int toId) {
if (DBG) {
- Slogf.d(TAG, "sendUserLifecycleEvent():" + " eventType=" + eventType + ", fromId="
+ Slog.d(TAG, "sendUserLifecycleEvent():" + " eventType=" + eventType + ", fromId="
+ fromId + ", toId=" + toId);
}
try {
@@ -447,7 +414,7 @@
mCarService.onUserLifecycleEvent(eventType, fromId, toId);
}
} catch (RemoteException e) {
- Slogf.w(TAG, "RemoteException from car service", e);
+ Slog.w(TAG, "RemoteException from car service", e);
handleCarServiceCrash();
}
}
@@ -457,12 +424,12 @@
mCarServiceCrashed = true;
mCarService = null;
}
- Slogf.w(TAG, "CarServiceCrashed. No more car service calls before reconnection.");
- mCarServiceHelperServiceUpdatableImpl.handleCarServiceCrash();
+ Slog.w(TAG, "CarServiceCrashed. No more car service calls before reconnection.");
+ mCarServiceHelperService.handleCarServiceCrash();
}
- private TimingsTraceLog newTimingsTraceLog() {
- return new TimingsTraceLog(TAG, TRACE_TAG_SYSTEM_SERVER);
+ private TimingsTraceAndSlog newTimingsTraceAndSlog() {
+ return new TimingsTraceAndSlog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
}
@GuardedBy("mLock")
@@ -473,8 +440,7 @@
@GuardedBy("mLock")
private boolean isServiceCrashedLoggedLocked(@NonNull String operation) {
if (mCarServiceCrashed) {
- Slogf.w(TAG, "CarServiceCrashed. " + operation + " will be executed after "
- + "reconnection");
+ Slog.w(TAG, "CarServiceCrashed. " + operation + " will be executed after reconnection");
return true;
}
return false;
@@ -484,37 +450,33 @@
* Dump
*/
void dump(IndentingPrintWriter writer) {
- // Do not change the next line, Used in cts test: testCarServiceHelperServiceDump
writer.println("CarServiceProxy");
writer.increaseIndent();
- synchronized (mLock) {
- writer.printf("mLastSwitchedUser=%s\n", mLastSwitchedUser);
- writer.printf("mInitialUser=%s\n", mInitialUser);
- writer.printf("mLastUserLifecycle:\n");
- int user0Lifecycle = mLastUserLifecycle.get(USER_SYSTEM, 0);
- if (user0Lifecycle != 0) {
- writer.printf("SystemUser Lifecycle Event:%s\n", user0Lifecycle);
- } else {
- writer.println("SystemUser not initialized");
- }
+ writer.printf("mLastSwitchedUser=%s\n", mLastSwitchedUser);
+ writer.printf("mLastUserLifecycle:\n");
+ int user0Lifecycle = mLastUserLifecycle.get(UserHandle.USER_SYSTEM, 0);
+ if (user0Lifecycle != 0) {
+ writer.printf("SystemUser Lifecycle Event:%s\n", user0Lifecycle);
+ } else {
+ writer.println("SystemUser not initialized");
+ }
- int lastUserLifecycle = mLastUserLifecycle.get(mLastSwitchedUser, 0);
- if (mLastSwitchedUser != USER_SYSTEM && user0Lifecycle != 0) {
- writer.printf("last user (%s) Lifecycle Event:%s\n",
- mLastSwitchedUser, lastUserLifecycle);
- }
+ int lastUserLifecycle = mLastUserLifecycle.get(mLastSwitchedUser, 0);
+ if (mLastSwitchedUser != UserHandle.USER_SYSTEM && user0Lifecycle != 0) {
+ writer.printf("last user (%s) Lifecycle Event:%s\n",
+ mLastSwitchedUser, lastUserLifecycle);
+ }
- int size = mPendingOperations.size();
- if (size == 0) {
- writer.println("No pending operations");
- } else {
- writer.printf("%d pending operation%s:\n", size, size == 1 ? "" : "s");
- writer.increaseIndent();
- for (int i = 0; i < size; i++) {
- writer.println(mPendingOperations.valueAt(i));
- }
- writer.decreaseIndent();
+ int size = mPendingOperations.size();
+ if (size == 0) {
+ writer.println("No pending operations");
+ } else {
+ writer.printf("%d pending operation%s:\n", size, size == 1 ? "" : "s");
+ writer.increaseIndent();
+ for (int i = 0; i < size; i++) {
+ writer.println(mPendingOperations.valueAt(i));
}
+ writer.decreaseIndent();
}
writer.decreaseIndent();
dumpUserMetrics(writer);
diff --git a/updatableServices/src/com/android/internal/car/updatable/UserMetrics.java b/src/com/android/internal/car/UserMetrics.java
similarity index 94%
rename from updatableServices/src/com/android/internal/car/updatable/UserMetrics.java
rename to src/com/android/internal/car/UserMetrics.java
index 31a4bfd..ff5fa75 100644
--- a/updatableServices/src/com/android/internal/car/updatable/UserMetrics.java
+++ b/src/com/android/internal/car/UserMetrics.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.car.updatable;
+package com.android.internal.car;
import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STARTING;
import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
@@ -26,13 +26,13 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.car.builtin.util.Slogf;
-import android.car.builtin.util.TimeUtils;
+import android.util.IndentingPrintWriter;
+import android.util.LocalLog;
+import android.util.Slog;
import android.util.SparseArray;
+import android.util.TimeUtils;
import com.android.car.internal.common.CommonConstants.UserLifecycleEventType;
-import com.android.car.internal.util.IndentingPrintWriter;
-import com.android.car.internal.util.LocalLog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -105,7 +105,7 @@
onUserStoppedEventLocked(timestampMs, toUserId);
return;
default:
- Slogf.w(TAG, "Invalid event: " + eventType);
+ Slog.w(TAG, "Invalid event: " + eventType);
}
}
}
@@ -131,7 +131,7 @@
UserStartingMetric existingMetrics = mUserStartingMetrics.get(userId);
if (existingMetrics != null) {
- Slogf.w(TAG, "user re-started: " + existingMetrics);
+ Slog.w(TAG, "user re-started: " + existingMetrics);
finishUserStartingLocked(existingMetrics, /* removeMetric= */ false);
}
@@ -169,7 +169,7 @@
}
UserStoppingMetric existingMetrics = mUserStoppingMetrics.get(userId);
if (existingMetrics != null) {
- Slogf.w(TAG, "user re-stopped: " + existingMetrics);
+ Slog.w(TAG, "user re-stopped: " + existingMetrics);
finishUserStoppingLocked(existingMetrics, /* removeMetric= */ false);
}
mUserStoppingMetrics.put(userId, new UserStoppingMetric(userId, timestampMs));
@@ -187,15 +187,14 @@
private <T extends BaseUserMetric> T getExistingMetricsLocked(
@NonNull SparseArray<? extends BaseUserMetric> metrics, @UserIdInt int userId) {
if (metrics == null) {
- Slogf.w(TAG, "getExistingMetricsLocked() should not pass null metrics, except on "
- + "tests");
+ Slog.w(TAG, "getExistingMetricsLocked() should not pass null metrics, except on tests");
return null;
}
@SuppressWarnings("unchecked")
T metric = (T) metrics.get(userId);
if (metric == null) {
String name = metrics == mUserStartingMetrics ? "starting" : "stopping";
- Slogf.w(TAG, "no " + name + " metrics for user " + userId);
+ Slog.w(TAG, "no " + name + " metrics for user " + userId);
}
return metric;
}
diff --git a/src/com/android/server/wm/CarLaunchParamsModifier.java b/src/com/android/server/wm/CarLaunchParamsModifier.java
new file mode 100644
index 0000000..0997ff2
--- /dev/null
+++ b/src/com/android/server/wm/CarLaunchParamsModifier.java
@@ -0,0 +1,490 @@
+/*
+ * 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.wm;
+
+import static com.android.server.wm.ActivityStarter.Request;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityOptions;
+import android.app.ActivityTaskManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.util.Slog;
+import android.util.SparseIntArray;
+import android.view.Display;
+import android.window.WindowContainerToken;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Class to control the assignment of a display for Car while launching a Activity.
+ *
+ * <p>This one controls which displays users are allowed to launch.
+ * The policy should be passed from car service through
+ * {@link com.android.internal.car.ICarServiceHelper} binder interfaces. If no policy is set,
+ * this module will not change anything for launch process.</p>
+ *
+ * <p> The policy can only affect which display passenger users can use. Current user, assumed
+ * to be a driver user, is allowed to launch any display always.</p>
+ */
+public final class CarLaunchParamsModifier implements LaunchParamsController.LaunchParamsModifier {
+
+ private static final String TAG = "CAR.LAUNCH";
+ private static final boolean DBG = false;
+
+ private final Context mContext;
+
+ private DisplayManager mDisplayManager; // set only from init()
+ private ActivityTaskManagerService mAtm; // set only from init()
+
+ private final Object mLock = new Object();
+
+ // Always start with USER_SYSTEM as the timing of handleCurrentUserSwitching(USER_SYSTEM) is not
+ // guaranteed to be earler than 1st Activity launch.
+ @GuardedBy("mLock")
+ private int mCurrentDriverUser = UserHandle.USER_SYSTEM;
+
+ // TODO: Switch from tracking displays to tracking display areas instead
+ /**
+ * This one is for holding all passenger (=profile user) displays which are mostly static unless
+ * displays are added / removed. Note that {@link #mDisplayToProfileUserMapping} can be empty
+ * while user is assigned and that cannot always tell if specific display is for driver or not.
+ */
+ @GuardedBy("mLock")
+ private final ArrayList<Integer> mPassengerDisplays = new ArrayList<>();
+
+ /** key: display id, value: profile user id */
+ @GuardedBy("mLock")
+ private final SparseIntArray mDisplayToProfileUserMapping = new SparseIntArray();
+
+ /** key: profile user id, value: display id */
+ @GuardedBy("mLock")
+ private final SparseIntArray mDefaultDisplayForProfileUser = new SparseIntArray();
+
+ @GuardedBy("mLock")
+ private boolean mIsSourcePreferred;
+
+ @GuardedBy("mLock")
+ private List<ComponentName> mSourcePreferredComponents;
+
+
+ @VisibleForTesting
+ final DisplayManager.DisplayListener mDisplayListener =
+ new DisplayManager.DisplayListener() {
+ @Override
+ public void onDisplayAdded(int displayId) {
+ // ignore. car service should update whiltelist.
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ synchronized (mLock) {
+ mPassengerDisplays.remove(Integer.valueOf(displayId));
+ updateProfileUserConfigForDisplayRemovalLocked(displayId);
+ }
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ // ignore
+ }
+ };
+
+ private void updateProfileUserConfigForDisplayRemovalLocked(int displayId) {
+ mDisplayToProfileUserMapping.delete(displayId);
+ int i = mDefaultDisplayForProfileUser.indexOfValue(displayId);
+ if (i >= 0) {
+ mDefaultDisplayForProfileUser.removeAt(i);
+ }
+ }
+
+ /** Constructor. Can be constructed any time. */
+ public CarLaunchParamsModifier(Context context) {
+ // This can be very early stage. So postpone interaction with other system until init.
+ mContext = context;
+ }
+
+ /**
+ * Initializes all internal stuffs. This should be called only after ATMS, DisplayManagerService
+ * are ready.
+ */
+ public void init() {
+ mAtm = (ActivityTaskManagerService) ActivityTaskManager.getService();
+ LaunchParamsController controller = mAtm.mTaskSupervisor.getLaunchParamsController();
+ controller.registerModifier(this);
+ mDisplayManager = mContext.getSystemService(DisplayManager.class);
+ mDisplayManager.registerDisplayListener(mDisplayListener,
+ new Handler(Looper.getMainLooper()));
+ }
+
+ /**
+ * Sets sourcePreferred configuration. When sourcePreferred is enabled and there is no pre-
+ * assigned display for the Activity, CarLauncherParamsModifier will launch the Activity in
+ * the display of the source. When sourcePreferredComponents isn't null the sourcePreferred
+ * is applied for the sourcePreferredComponents only.
+ *
+ * @param enableSourcePreferred whether to enable sourcePreferred mode
+ * @param sourcePreferredComponents null for all components, or the list of components to apply
+ */
+ public void setSourcePreferredComponents(boolean enableSourcePreferred,
+ @Nullable List<ComponentName> sourcePreferredComponents) {
+ synchronized (mLock) {
+ mIsSourcePreferred = enableSourcePreferred;
+ mSourcePreferredComponents = sourcePreferredComponents;
+ if (mSourcePreferredComponents != null) {
+ Collections.sort(mSourcePreferredComponents);
+ }
+ }
+ }
+
+ /** Notifies user switching. */
+ public void handleCurrentUserSwitching(int newUserId) {
+ synchronized (mLock) {
+ mCurrentDriverUser = newUserId;
+ mDefaultDisplayForProfileUser.clear();
+ mDisplayToProfileUserMapping.clear();
+ }
+ }
+
+ private void removeUserFromAllowlistsLocked(int userId) {
+ for (int i = mDisplayToProfileUserMapping.size() - 1; i >= 0; i--) {
+ if (mDisplayToProfileUserMapping.valueAt(i) == userId) {
+ mDisplayToProfileUserMapping.removeAt(i);
+ }
+ }
+ mDefaultDisplayForProfileUser.delete(userId);
+ }
+
+ /** Notifies user stopped. */
+ public void handleUserStopped(int stoppedUser) {
+ // Note that the current user is never stopped. It always takes switching into
+ // non-current user before stopping the user.
+ synchronized (mLock) {
+ removeUserFromAllowlistsLocked(stoppedUser);
+ }
+ }
+
+ /**
+ * Sets display allowlist for the userId. For passenger user, activity will be always launched
+ * to a display in the allowlist. If requested display is not in the allowlist, the 1st display
+ * in the allowlist will be selected as target display.
+ *
+ * <p>The allowlist is kept only for profile user. Assigning the current user unassigns users
+ * for the given displays.
+ */
+ public void setDisplayAllowListForUser(int userId, int[] displayIds) {
+ if (DBG) {
+ Slog.d(TAG, "setDisplayAllowlistForUser userId:" + userId
+ + " displays:" + displayIds);
+ }
+ synchronized (mLock) {
+ for (int displayId : displayIds) {
+ if (!mPassengerDisplays.contains(displayId)) {
+ Slog.w(TAG, "setDisplayAllowlistForUser called with display:" + displayId
+ + " not in passenger display list:" + mPassengerDisplays);
+ continue;
+ }
+ if (userId == mCurrentDriverUser) {
+ mDisplayToProfileUserMapping.delete(displayId);
+ } else {
+ mDisplayToProfileUserMapping.put(displayId, userId);
+ }
+ // now the display cannot be a default display for other user
+ int i = mDefaultDisplayForProfileUser.indexOfValue(displayId);
+ if (i >= 0) {
+ mDefaultDisplayForProfileUser.removeAt(i);
+ }
+ }
+ if (displayIds.length > 0) {
+ mDefaultDisplayForProfileUser.put(userId, displayIds[0]);
+ } else {
+ removeUserFromAllowlistsLocked(userId);
+ }
+ }
+ }
+
+ /**
+ * Sets displays assigned to passenger. All other displays will be treated as assigned to
+ * driver.
+ *
+ * <p>The 1st display in the array will be considered as a default display to assign
+ * for any non-driver user if there is no display assigned for the user. </p>
+ */
+ public void setPassengerDisplays(int[] displayIdsForPassenger) {
+ if (DBG) {
+ Slog.d(TAG, "setPassengerDisplays displays:" + displayIdsForPassenger);
+ }
+ synchronized (mLock) {
+ for (int id : displayIdsForPassenger) {
+ mPassengerDisplays.remove(Integer.valueOf(id));
+ }
+ // handle removed displays
+ for (int i = 0; i < mPassengerDisplays.size(); i++) {
+ int displayId = mPassengerDisplays.get(i);
+ updateProfileUserConfigForDisplayRemovalLocked(displayId);
+ }
+ mPassengerDisplays.clear();
+ mPassengerDisplays.ensureCapacity(displayIdsForPassenger.length);
+ for (int id : displayIdsForPassenger) {
+ mPassengerDisplays.add(id);
+ }
+ }
+ }
+
+ /**
+ * Decides display to assign while an Activity is launched.
+ *
+ * <p>For current user (=driver), launching to any display is allowed as long as system
+ * allows it.</p>
+ *
+ * <p>For private display, do not change anything as private display has its own logic.</p>
+ *
+ * <p>For passenger displays, only run in allowed displays. If requested display is not
+ * allowed, change to the 1st allowed display.</p>
+ */
+ @Override
+ @Result
+ public int onCalculate(@Nullable Task task, @Nullable ActivityInfo.WindowLayout layout,
+ @Nullable ActivityRecord activity, @Nullable ActivityRecord source,
+ ActivityOptions options, @Nullable Request request, int phase,
+ LaunchParamsController.LaunchParams currentParams,
+ LaunchParamsController.LaunchParams outParams) {
+ int userId;
+ if (task != null) {
+ userId = task.mUserId;
+ } else if (activity != null) {
+ userId = activity.mUserId;
+ } else {
+ Slog.w(TAG, "onCalculate, cannot decide user");
+ return RESULT_SKIP;
+ }
+ // DisplayArea where user wants to launch the Activity.
+ TaskDisplayArea originalDisplayArea = currentParams.mPreferredTaskDisplayArea;
+ // DisplayArea where CarLaunchParamsModifier targets to launch the Activity.
+ TaskDisplayArea targetDisplayArea = null;
+ if (DBG) {
+ Slog.d(TAG, "onCalculate, userId:" + userId
+ + " original displayArea:" + originalDisplayArea
+ + " ActivityOptions:" + options);
+ }
+ // If originalDisplayArea is set, respect that before ActivityOptions check.
+ if (originalDisplayArea == null) {
+ if (options != null) {
+ WindowContainerToken daToken = options.getLaunchTaskDisplayArea();
+ if (daToken != null) {
+ originalDisplayArea = (TaskDisplayArea) WindowContainer.fromBinder(
+ daToken.asBinder());
+ } else {
+ int originalDisplayId = options.getLaunchDisplayId();
+ if (originalDisplayId != Display.INVALID_DISPLAY) {
+ originalDisplayArea = getDefaultTaskDisplayAreaOnDisplay(originalDisplayId);
+ }
+ }
+ }
+ }
+ decision:
+ synchronized (mLock) {
+ if (originalDisplayArea == null // No specified DisplayArea to launch the Activity
+ && mIsSourcePreferred && source != null
+ && (mSourcePreferredComponents == null || Collections.binarySearch(
+ mSourcePreferredComponents, activity.info.getComponentName()) >= 0)) {
+ targetDisplayArea = source.noDisplay ? source.mHandoverTaskDisplayArea
+ : source.getDisplayArea();
+ } else if (originalDisplayArea == null
+ && task == null // launching as a new task
+ && source != null && !source.getDisplayContent().isTrusted()
+ && ((activity.info.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0)) {
+ if (DBG) {
+ Slog.d(TAG, "Disallow launch on virtual display for not-embedded activity.");
+ }
+ targetDisplayArea = getDefaultTaskDisplayAreaOnDisplay(Display.DEFAULT_DISPLAY);
+ }
+ if (userId == mCurrentDriverUser) {
+ // Respect the existing DisplayArea.
+ break decision;
+ }
+ if (userId == UserHandle.USER_SYSTEM) {
+ // This will be only allowed if it has FLAG_SHOW_FOR_ALL_USERS.
+ // The flag is not immediately accessible here so skip the check.
+ // But other WM policy will enforce it.
+ break decision;
+ }
+ // Now user is a passenger.
+ if (mPassengerDisplays.isEmpty()) {
+ // No displays for passengers. This could be old user and do not do anything.
+ break decision;
+ }
+ if (targetDisplayArea == null) {
+ if (originalDisplayArea != null) {
+ targetDisplayArea = originalDisplayArea;
+ } else {
+ targetDisplayArea = getDefaultTaskDisplayAreaOnDisplay(Display.DEFAULT_DISPLAY);
+ }
+ }
+ Display display = targetDisplayArea.mDisplayContent.getDisplay();
+ if ((display.getFlags() & Display.FLAG_PRIVATE) != 0) {
+ // private display should follow its own restriction rule.
+ break decision;
+ }
+ if (display.getType() == Display.TYPE_VIRTUAL) {
+ // TODO(b/132903422) : We need to update this after the bug is resolved.
+ // For now, don't change anything.
+ break decision;
+ }
+ int userForDisplay = mDisplayToProfileUserMapping.get(display.getDisplayId(),
+ UserHandle.USER_NULL);
+ if (userForDisplay == userId) {
+ break decision;
+ }
+ targetDisplayArea = getAlternativeDisplayAreaForPassengerLocked(
+ userId, activity, request);
+ }
+ if (targetDisplayArea != null && originalDisplayArea != targetDisplayArea) {
+ Slog.i(TAG, "Changed launching display, user:" + userId
+ + " requested display area:" + originalDisplayArea
+ + " target display area:" + targetDisplayArea);
+ outParams.mPreferredTaskDisplayArea = targetDisplayArea;
+ return RESULT_DONE;
+ } else {
+ return RESULT_SKIP;
+ }
+ }
+
+ @Nullable
+ private TaskDisplayArea getAlternativeDisplayAreaForPassengerLocked(int userId,
+ @NonNull ActivityRecord activityRecord, @Nullable Request request) {
+ TaskDisplayArea sourceDisplayArea = sourceDisplayArea(userId, activityRecord, request);
+
+ return sourceDisplayArea != null ? sourceDisplayArea : fallbackDisplayArea(userId);
+ }
+
+ @VisibleForTesting
+ @Nullable
+ TaskDisplayArea getDefaultTaskDisplayAreaOnDisplay(int displayId) {
+ DisplayContent dc = mAtm.mRootWindowContainer.getDisplayContentOrCreate(displayId);
+ if (dc == null) {
+ return null;
+ }
+ return dc.getDefaultTaskDisplayArea();
+ }
+
+ /**
+ * Calculates the {@link TaskDisplayArea} for the source of the request. The source is
+ * calculated implicitly from the request or the activity record.
+ *
+ * @param userId ID of the current active user
+ * @param activityRecord {@link ActivityRecord} that is to be shown
+ * @param request {@link Request} data for showing the {@link ActivityRecord}
+ * @return {@link TaskDisplayArea} First non {@code null} candidate display area that is allowed
+ * for the user. It is allowed if the display has been added to the profile mapping.
+ */
+ @Nullable
+ private TaskDisplayArea sourceDisplayArea(int userId, @NonNull ActivityRecord activityRecord,
+ @Nullable Request request) {
+ List<WindowProcessController> candidateControllers = candidateControllers(activityRecord,
+ request);
+
+ for (int i = 0; i < candidateControllers.size(); i++) {
+ WindowProcessController controller = candidateControllers.get(i);
+ TaskDisplayArea candidate = controller.getTopActivityDisplayArea();
+ int displayId = candidate != null ? candidate.getDisplayId() : Display.INVALID_DISPLAY;
+ int userForDisplay = mDisplayToProfileUserMapping.get(displayId, UserHandle.USER_NULL);
+ if (userForDisplay == userId) {
+ return candidate;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Calculates a list of {@link WindowProcessController} that can calculate the
+ * {@link TaskDisplayArea} to house the {@link ActivityRecord}. Controllers are calculated since
+ * calculating the display can be expensive. The list is ordered in the
+ * following way
+ * <ol>
+ * <li>Controller for the activity record from the process name and app uid</li>
+ * <li>Controller for the activity that is launching the given record</li>
+ * <li>Controller for the actual process that is launching the record</li>
+ * </ol>
+ *
+ * @param activityRecord {@link ActivityRecord} that is to be shown
+ * @param request {@link Request} data for showing the {@link ActivityRecord}
+ * @return {@link List} of {@link WindowProcessController} ordered by preference to be shown
+ */
+ private List<WindowProcessController> candidateControllers(
+ @NonNull ActivityRecord activityRecord, @Nullable Request request) {
+ WindowProcessController firstController = mAtm.getProcessController(
+ activityRecord.getProcessName(), activityRecord.getUid());
+
+ WindowProcessController secondController = mAtm.getProcessController(
+ activityRecord.getLaunchedFromPid(), activityRecord.getLaunchedFromUid());
+
+ WindowProcessController thirdController = request == null ? null :
+ mAtm.getProcessController(request.realCallingPid, request.realCallingUid);
+
+ List<WindowProcessController> candidates = new ArrayList<>(3);
+
+ if (firstController != null) {
+ candidates.add(firstController);
+ }
+ if (secondController != null) {
+ candidates.add(secondController);
+ }
+ if (thirdController != null) {
+ candidates.add(thirdController);
+ }
+
+ return candidates;
+ }
+
+ /**
+ * Return a {@link TaskDisplayArea} that can be used if a source display area is not found.
+ * First check the default display for the user. If it is absent select the first passenger
+ * display if present. If both are absent return {@code null}
+ *
+ * @param userId ID of the active user
+ * @return {@link TaskDisplayArea} that is recommended when a display area is not specified
+ */
+ @Nullable
+ private TaskDisplayArea fallbackDisplayArea(int userId) {
+ int displayIdForUserProfile = mDefaultDisplayForProfileUser.get(userId,
+ Display.INVALID_DISPLAY);
+ if (displayIdForUserProfile != Display.INVALID_DISPLAY) {
+ int displayId = mDefaultDisplayForProfileUser.get(userId);
+ return getDefaultTaskDisplayAreaOnDisplay(displayId);
+ }
+
+ if (!mPassengerDisplays.isEmpty()) {
+ int displayId = mPassengerDisplays.get(0);
+ return getDefaultTaskDisplayAreaOnDisplay(displayId);
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/jni/com_android_internal_car_CarServiceHelperService.cpp b/src/jni/com_android_internal_car_CarServiceHelperService.cpp
new file mode 100644
index 0000000..3942b77
--- /dev/null
+++ b/src/jni/com_android_internal_car_CarServiceHelperService.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#define LOG_TAG "CarServiceHelperService-JNI"
+
+//#define LOG_NDEBUG 0
+
+#include "jni.h"
+
+#include <nativehelper/JNIHelp.h>
+#include <suspend/autosuspend.h>
+#include <utils/Log.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static jint nativeForceSuspend(JNIEnv* /* env */, jclass /* clazz */, jint timeoutMs) {
+ jint ret = autosuspend_force_suspend(timeoutMs);
+ ALOGD("nativeForceSuspend returned %d", ret);
+ return ret;
+}
+
+// ----------------------------------------------------------------------------
+
+static const JNINativeMethod gCarServiceHelperServiceMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeForceSuspend", "(I)I",
+ (void*) nativeForceSuspend },
+};
+
+int register_android_internal_car_CarServiceHelperService(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, "com/android/internal/car/CarServiceHelperService",
+ gCarServiceHelperServiceMethods, NELEM(gCarServiceHelperServiceMethods));
+ (void) res; // Faked use when LOG_NDEBUG.
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+ return 0;
+}
+
+} /* namespace android */
+
+
+using namespace android;
+
+extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
+{
+ JNIEnv* env = NULL;
+ jint result = -1;
+
+ if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+ ALOGE("GetEnv failed!");
+ return result;
+ }
+ ALOG_ASSERT(env, "Could not retrieve the env!");
+
+ register_android_internal_car_CarServiceHelperService(env);
+ return JNI_VERSION_1_4;
+}
diff --git a/builtInServices/tests/Android.mk b/tests/Android.mk
similarity index 88%
rename from builtInServices/tests/Android.mk
rename to tests/Android.mk
index c9eee58..1cf4dcc 100644
--- a/builtInServices/tests/Android.mk
+++ b/tests/Android.mk
@@ -8,7 +8,7 @@
$(call all-java-files-under, ../src) \
$(call all-Iaidl-files-under, ../src)
-LOCAL_PACKAGE_NAME := FrameworkOptCarServicesTest
+LOCAL_PACKAGE_NAME := CarServicesTest
LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
LOCAL_LICENSE_CONDITIONS := notice
LOCAL_PRIVATE_PLATFORM_APIS := true
@@ -23,21 +23,21 @@
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_JAVA_LIBRARIES += \
- android.car \
android.test.runner \
android.test.base \
android.hardware.automotive.vehicle-V2.0-java \
+ com.android.car.internal.common
LOCAL_STATIC_JAVA_LIBRARIES := \
android.car.test.utils \
android.car.watchdoglib \
androidx.test.ext.junit \
androidx.test.rules \
+ com.android.car.internal.system \
mockito-target-extended-minus-junit4 \
services.core \
testng \
- truth-prebuilt \
- android.car.builtin \
+ truth-prebuilt
# mockito-target-extended dependencies
LOCAL_JNI_SHARED_LIBRARIES := \
diff --git a/builtInServices/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
similarity index 94%
rename from builtInServices/tests/AndroidManifest.xml
rename to tests/AndroidManifest.xml
index edce0fd..ff050df 100644
--- a/builtInServices/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -22,7 +22,7 @@
android:targetPackage="com.android.internal.car"
android:label="Unit Tests for Car Framework Services"/>
- <application android:label="FrameworkOptCarServicesTest"
+ <application android:label="CarServicesTest"
android:debuggable="true">
<uses-library android:name="android.test.runner" />
</application>
diff --git a/builtInServices/tests/src/com/android/internal/car/CarDevicePolicySafetyCheckerTest.java b/tests/src/com/android/internal/car/CarDevicePolicySafetyCheckerTest.java
similarity index 100%
rename from builtInServices/tests/src/com/android/internal/car/CarDevicePolicySafetyCheckerTest.java
rename to tests/src/com/android/internal/car/CarDevicePolicySafetyCheckerTest.java
diff --git a/builtInServices/tests/src/com/android/internal/car/CarServiceHelperServiceTest.java b/tests/src/com/android/internal/car/CarServiceHelperServiceTest.java
similarity index 69%
rename from builtInServices/tests/src/com/android/internal/car/CarServiceHelperServiceTest.java
rename to tests/src/com/android/internal/car/CarServiceHelperServiceTest.java
index 552a27a..a2da2a5 100644
--- a/builtInServices/tests/src/com/android/internal/car/CarServiceHelperServiceTest.java
+++ b/tests/src/com/android/internal/car/CarServiceHelperServiceTest.java
@@ -16,19 +16,23 @@
package com.android.internal.car;
-import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED;
+import static com.android.car.internal.common.CommonConstants.CAR_SERVICE_INTERFACE;
import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STARTING;
import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STOPPING;
import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_UNLOCKING;
-import static com.android.server.SystemService.UserCompletedEventType.newUserCompletedEventTypeForTest;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -36,16 +40,18 @@
import android.car.test.mocks.AbstractExtendedMockitoTestCase;
import android.car.watchdoglib.CarWatchdogDaemonHelper;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageManager;
+import android.os.Binder;
import android.os.IBinder;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
-import android.os.SystemProperties.Handle;
+
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.server.SystemService;
import com.android.server.SystemService.TargetUser;
-import com.android.server.SystemService.UserCompletedEventType;
import com.android.server.wm.CarLaunchParamsModifier;
import org.junit.Before;
@@ -59,6 +65,9 @@
@RunWith(AndroidJUnit4.class)
public class CarServiceHelperServiceTest extends AbstractExtendedMockitoTestCase {
+ private static final String TAG = CarServiceHelperServiceTest.class.getSimpleName();
+
+ private CarServiceHelperService mHelperSpy;
private CarServiceHelperService mHelper;
@Mock
@@ -72,14 +81,7 @@
@Mock
private IBinder mICarBinder;
@Mock
- private CarServiceHelperServiceUpdatable mCarServiceHelperServiceUpdatable;
-
- @Mock
- private CarDevicePolicySafetyChecker mCarDevicePolicySafetyChecker;
-
- public CarServiceHelperServiceTest() {
- super(CarServiceHelperService.TAG);
- }
+ private CarServiceProxy mCarServiceProxy;
/**
* Initialize objects and setup testing environment.
@@ -95,18 +97,40 @@
mMockContext,
mCarLaunchParamsModifier,
mCarWatchdogDaemonHelper,
- mCarServiceHelperServiceUpdatable,
- mCarDevicePolicySafetyChecker);
+ mCarServiceProxy);
+ mHelperSpy = spy(mHelper);
when(mMockContext.getPackageManager()).thenReturn(mPackageManager);
}
@Test
+ public void testCarServiceLaunched() throws Exception {
+ mockRegisterReceiver();
+ mockBindService();
+ mockLoadLibrary();
+
+ mHelperSpy.onStart();
+
+ verifyBindService();
+ }
+
+ @Test
+ public void testHandleCarServiceCrash() throws Exception {
+ mockHandleCarServiceCrash();
+ mockCarServiceException();
+
+ mHelperSpy.handleCarServiceConnection(mICarBinder);
+
+ verify(mHelperSpy).handleCarServiceCrash();
+ }
+
+ @Test
public void testOnUserStarting_notifiesICar() throws Exception {
int userId = 10;
mHelper.onUserStarting(newTargetUser(userId));
- verifyICarOnUserLifecycleEventCalled(USER_LIFECYCLE_EVENT_TYPE_STARTING, userId);
+ verifyICarOnUserLifecycleEventCalled(USER_LIFECYCLE_EVENT_TYPE_STARTING,
+ UserHandle.USER_NULL, userId);
}
@Test
@@ -141,7 +165,8 @@
mHelper.onUserUnlocking(newTargetUser(userId));
- verifyICarOnUserLifecycleEventCalled(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING, userId);
+ verifyICarOnUserLifecycleEventCalled(USER_LIFECYCLE_EVENT_TYPE_UNLOCKING,
+ UserHandle.USER_NULL, userId);
}
@Test
@@ -157,7 +182,8 @@
mHelper.onUserStopping(newTargetUser(userId));
- verifyICarOnUserLifecycleEventCalled(USER_LIFECYCLE_EVENT_TYPE_STOPPING, userId);
+ verifyICarOnUserLifecycleEventCalled(USER_LIFECYCLE_EVENT_TYPE_STOPPING,
+ UserHandle.USER_NULL, userId);
}
@Test
@@ -173,7 +199,8 @@
mHelper.onUserStopped(newTargetUser(userId));
- verifyICarOnUserLifecycleEventCalled(USER_LIFECYCLE_EVENT_TYPE_STOPPED, userId);
+ verifyICarOnUserLifecycleEventCalled(USER_LIFECYCLE_EVENT_TYPE_STOPPED,
+ UserHandle.USER_NULL, userId);
}
@Test
@@ -190,29 +217,6 @@
verifyInitBootUser();
}
- @Test
- public void testOnUserCompletedEvent_notifiesPostUnlockedEvent() throws Exception {
- int userId = 10;
-
- mHelper.onUserCompletedEvent(newTargetUser(userId), newUserCompletedEventTypeForTest(
- UserCompletedEventType.EVENT_TYPE_USER_UNLOCKED));
-
- verifyICarOnUserLifecycleEventCalled(USER_LIFECYCLE_EVENT_TYPE_POST_UNLOCKED, userId);
- }
-
- @Test
- public void testOnUserCompletedEvent_preCreatedUserDoesNotNotifyICar() throws Exception {
- UserCompletedEventType userCompletedEventType = newUserCompletedEventTypeForTest(
- UserCompletedEventType.EVENT_TYPE_USER_STARTING
- | UserCompletedEventType.EVENT_TYPE_USER_SWITCHING
- | UserCompletedEventType.EVENT_TYPE_USER_UNLOCKED);
-
- mHelper.onUserCompletedEvent(newTargetUser(10, /* preCreated= */true),
- userCompletedEventType);
-
- verifyICarOnUserLifecycleEventNeverCalled();
- }
-
private TargetUser newTargetUser(int userId) {
return newTargetUser(userId, /* preCreated= */ false);
}
@@ -220,11 +224,40 @@
private TargetUser newTargetUser(int userId, boolean preCreated) {
TargetUser targetUser = mock(TargetUser.class);
when(targetUser.getUserIdentifier()).thenReturn(userId);
- when(targetUser.getUserHandle()).thenReturn(UserHandle.of(userId));
when(targetUser.isPreCreated()).thenReturn(preCreated);
return targetUser;
}
+ private void verifyBindService() throws Exception {
+ verify(mMockContext).bindServiceAsUser(
+ argThat(intent -> intent.getAction().equals(CAR_SERVICE_INTERFACE)),
+ any(), eq(Context.BIND_AUTO_CREATE), any(), eq(UserHandle.SYSTEM));
+ }
+
+ private void mockRegisterReceiver() {
+ when(mMockContext.registerReceiverForAllUsers(any(), any(), any(), any()))
+ .thenReturn(new Intent());
+ }
+
+ private void mockBindService() {
+ when(mMockContext.bindServiceAsUser(any(), any(),
+ eq(Context.BIND_AUTO_CREATE), any(), eq(UserHandle.SYSTEM)))
+ .thenReturn(true);
+ }
+
+ private void mockLoadLibrary() {
+ doNothing().when(mHelperSpy).loadNativeLibrary();
+ }
+
+ private void mockCarServiceException() throws Exception {
+ when(mICarBinder.transact(anyInt(), notNull(), isNull(), eq(Binder.FLAG_ONEWAY)))
+ .thenThrow(new RemoteException("mock car service Crash"));
+ }
+
+ private void mockHandleCarServiceCrash() throws Exception {
+ doNothing().when(mHelperSpy).handleCarServiceCrash();
+ }
+
enum InitialUserInfoAction {
DEFAULT,
DEFAULT_WITH_LOCALE,
@@ -239,22 +272,21 @@
private void verifyICarOnUserLifecycleEventCalled(int eventType,
@UserIdInt int fromId, @UserIdInt int toId) throws Exception {
- verify(mCarServiceHelperServiceUpdatable).sendUserLifecycleEvent(eventType,
- UserHandle.of(fromId), UserHandle.of(toId));
+ verify(mCarServiceProxy).sendUserLifecycleEvent(eq(eventType),
+ isTargetUser(fromId), isTargetUser(toId));
}
- private void verifyICarOnUserLifecycleEventCalled(int eventType,
- @UserIdInt int userId) throws Exception {
- verify(mCarServiceHelperServiceUpdatable).sendUserLifecycleEvent(eventType,
- null, UserHandle.of(userId));
+ private static TargetUser isTargetUser(@UserIdInt int userId) {
+ return argThat((user) -> {
+ return user == null || user.getUserIdentifier() == userId;
+ });
}
private void verifyICarOnUserLifecycleEventNeverCalled() throws Exception {
- verify(mCarServiceHelperServiceUpdatable, never()).sendUserLifecycleEvent(anyInt(), any(),
- any());
+ verify(mCarServiceProxy, never()).sendUserLifecycleEvent(anyInt(), any(), any());
}
private void verifyInitBootUser() throws Exception {
- verify(mCarServiceHelperServiceUpdatable).initBootUser();
+ verify(mCarServiceProxy).initBootUser();
}
}
diff --git a/updatableServices/tests/src/com/android/internal/car/updatable/CarServiceProxyTest.java b/tests/src/com/android/internal/car/CarServiceProxyTest.java
similarity index 84%
rename from updatableServices/tests/src/com/android/internal/car/updatable/CarServiceProxyTest.java
rename to tests/src/com/android/internal/car/CarServiceProxyTest.java
index 714cf55..74bc8b0 100644
--- a/updatableServices/tests/src/com/android/internal/car/updatable/CarServiceProxyTest.java
+++ b/tests/src/com/android/internal/car/CarServiceProxyTest.java
@@ -13,7 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.internal.car.updatable;
+
+
+package com.android.internal.car;
import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_SWITCHING;
@@ -22,13 +24,13 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
-import android.car.ICarResultReceiver;
import android.car.test.mocks.AbstractExtendedMockitoTestCase;
import android.car.test.util.UserTestingHelper.UserInfoBuilder;
import android.content.pm.UserInfo;
import android.os.RemoteException;
import com.android.car.internal.ICarSystemServerClient;
+import com.android.internal.os.IResultReceiver;
import com.android.server.SystemService.TargetUser;
import org.junit.Before;
@@ -38,15 +40,15 @@
public class CarServiceProxyTest extends AbstractExtendedMockitoTestCase {
@Mock
- private CarServiceHelperServiceUpdatableImpl mCarServiceHelperServiceUpdatableImpl;
+ private CarServiceHelperService mCarServiceHelperService;
@Mock
private ICarSystemServerClient mCarService;
@Mock
- private ICarResultReceiver mFactoryResetCallback1;
+ private IResultReceiver mFactoryResetCallback1;
@Mock
- private ICarResultReceiver mFactoryResetCallback2;
+ private IResultReceiver mFactoryResetCallback2;
private final TargetUser mFromUser = new TargetUser(new UserInfo(101, "fromUser", 0));
private final TargetUser mToUser = new TargetUser(new UserInfo(102, "toUser", 0));
@@ -57,13 +59,9 @@
private CarServiceProxy mCarServiceProxy;
- public CarServiceProxyTest() {
- super(CarServiceProxy.TAG);
- }
-
@Before
public void setUpMocks() {
- mCarServiceProxy = new CarServiceProxy(mCarServiceHelperServiceUpdatableImpl);
+ mCarServiceProxy = new CarServiceProxy(mCarServiceHelperService);
}
@Test
@@ -172,17 +170,16 @@
}
private void callSendLifecycleEvent(int eventType) {
- mCarServiceProxy.sendUserLifecycleEvent(eventType, mFromUser.getUserIdentifier(),
- mToUser.getUserIdentifier());
+ mCarServiceProxy.sendUserLifecycleEvent(eventType, mFromUser, mToUser);
}
private void callOnUserRemoved() {
- mCarServiceProxy.onUserRemoved(mRemovedUser1.getUserHandle());
- mCarServiceProxy.onUserRemoved(mRemovedUser2.getUserHandle());
- mCarServiceProxy.onUserRemoved(mRemovedUser3.getUserHandle());
+ mCarServiceProxy.onUserRemoved(mRemovedUser1);
+ mCarServiceProxy.onUserRemoved(mRemovedUser2);
+ mCarServiceProxy.onUserRemoved(mRemovedUser3);
}
- private void callOnFactoryReset(ICarResultReceiver callback) {
+ private void callOnFactoryReset(IResultReceiver callback) {
mCarServiceProxy.onFactoryReset(callback);
}
@@ -204,20 +201,20 @@
}
private void verifyOnUserRemovedCalled() throws RemoteException {
- verify(mCarService).onUserRemoved(mRemovedUser1.getUserHandle());
- verify(mCarService).onUserRemoved(mRemovedUser2.getUserHandle());
- verify(mCarService).onUserRemoved(mRemovedUser3.getUserHandle());
+ verify(mCarService).onUserRemoved(mRemovedUser1);
+ verify(mCarService).onUserRemoved(mRemovedUser2);
+ verify(mCarService).onUserRemoved(mRemovedUser3);
}
private void verifyOnUserRemovedNeverCalled() throws RemoteException {
verify(mCarService, never()).onUserRemoved(any());
}
- private void verifyOnFactoryResetCalled(ICarResultReceiver callback) throws RemoteException {
+ private void verifyOnFactoryResetCalled(IResultReceiver callback) throws RemoteException {
verify(mCarService).onFactoryReset(callback);
}
- private void verifyOnFactoryResetNotCalled(ICarResultReceiver callback) throws RemoteException {
+ private void verifyOnFactoryResetNotCalled(IResultReceiver callback) throws RemoteException {
verify(mCarService, never()).onFactoryReset(callback);
}
diff --git a/updatableServices/tests/src/com/android/internal/car/updatable/UserMetricsTest.java b/tests/src/com/android/internal/car/UserMetricsTest.java
similarity index 97%
rename from updatableServices/tests/src/com/android/internal/car/updatable/UserMetricsTest.java
rename to tests/src/com/android/internal/car/UserMetricsTest.java
index b778de4..67ed9f9 100644
--- a/updatableServices/tests/src/com/android/internal/car/updatable/UserMetricsTest.java
+++ b/tests/src/com/android/internal/car/UserMetricsTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.car.updatable;
+package com.android.internal.car;
import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STARTING;
import static com.android.car.internal.common.CommonConstants.USER_LIFECYCLE_EVENT_TYPE_STOPPED;
@@ -31,8 +31,8 @@
import android.os.SystemClock;
import android.util.SparseArray;
-import com.android.internal.car.updatable.UserMetrics.UserStartingMetric;
-import com.android.internal.car.updatable.UserMetrics.UserStoppingMetric;
+import com.android.internal.car.UserMetrics.UserStartingMetric;
+import com.android.internal.car.UserMetrics.UserStoppingMetric;
import org.junit.Test;
diff --git a/updatableServices/tests/src/com/android/server/wm/CarLaunchParamsModifierUpdatableTest.java b/tests/src/com/android/server/wm/CarLaunchParamsModifierTest.java
similarity index 73%
rename from updatableServices/tests/src/com/android/server/wm/CarLaunchParamsModifierUpdatableTest.java
rename to tests/src/com/android/server/wm/CarLaunchParamsModifierTest.java
index 13dc733..d641cff 100644
--- a/updatableServices/tests/src/com/android/server/wm/CarLaunchParamsModifierUpdatableTest.java
+++ b/tests/src/com/android/server/wm/CarLaunchParamsModifierTest.java
@@ -25,46 +25,33 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
-import static org.testng.Assert.assertThrows;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
-import android.car.app.CarActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.ServiceSpecificException;
import android.os.UserHandle;
import android.view.Display;
import android.view.SurfaceControl;
-import android.window.DisplayAreaOrganizer;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.internal.policy.AttributeCache;
import com.android.server.LocalServices;
import com.android.server.display.color.ColorDisplayService;
-import com.android.server.input.InputManagerService;
-import com.android.server.policy.WindowManagerPolicy;
import org.junit.After;
import org.junit.Before;
@@ -75,30 +62,24 @@
import org.mockito.quality.Strictness;
import java.util.Arrays;
-import java.util.function.Function;
/**
* Tests for {@link CarLaunchParamsModifier}
* Build/Install/Run:
- * atest FrameworkOptCarServicesUpdatableTest:CarLaunchParamsModifierUpdatableTest
+ * atest CarServicesTest:CarLaunchParamsModifierTest
*/
@RunWith(AndroidJUnit4.class)
-public class CarLaunchParamsModifierUpdatableTest {
+public class CarLaunchParamsModifierTest {
private static final int PASSENGER_DISPLAY_ID_10 = 10;
private static final int PASSENGER_DISPLAY_ID_11 = 11;
private static final int VIRTUAL_DISPLAY_ID_2 = 2;
- private static final int FEATURE_MAP_ID = 1111;
private MockitoSession mMockingSession;
private CarLaunchParamsModifier mModifier;
- private CarLaunchParamsModifierUpdatableImpl mUpdatable;
- private CarLaunchParamsModifierInterface mBuiltin;
+ @Mock
private Context mContext;
- private WindowManagerService mWindowManagerService;
- private final WindowManagerGlobalLock mWindowManagerGlobalLock = new WindowManagerGlobalLock();
-
@Mock
private DisplayManager mDisplayManager;
@Mock
@@ -108,15 +89,13 @@
@Mock
private RecentTasks mRecentTasks;
@Mock
+ private WindowManagerService mWindowManagerService;
+ @Mock
private ColorDisplayService.ColorDisplayServiceInternal mColorDisplayServiceInternal;
@Mock
private RootWindowContainer mRootWindowContainer;
@Mock
private LaunchParamsController mLaunchParamsController;
- @Mock
- private PackageConfigPersister mPackageConfigPersister;
- @Mock
- private InputManagerService mInputManagerService;
@Mock
private Display mDisplay0ForDriver;
@@ -138,7 +117,6 @@
private Display mDisplay2Virtual;
@Mock
private TaskDisplayArea mDisplayArea2Virtual;
- private TaskDisplayArea mMapTaskDisplayArea;
// All mocks from here before CarLaunchParamsModifier are arguments for
// LaunchParamsModifier.onCalculate() call.
@@ -167,7 +145,6 @@
// Return the same id as the display for simplicity
DisplayContent dc = mock(DisplayContent.class);
defaultTaskDisplayArea.mDisplayContent = dc;
- when(defaultTaskDisplayArea.getDisplayContent()).thenReturn(dc);
when(mRootWindowContainer.getDisplayContentOrCreate(displayId)).thenReturn(dc);
when(dc.getDisplay()).thenReturn(display);
when(dc.getDefaultTaskDisplayArea()).thenReturn(defaultTaskDisplayArea);
@@ -181,46 +158,21 @@
.mockStatic(ActivityTaskManager.class)
.strictness(Strictness.LENIENT)
.startMocking();
- mContext = getInstrumentation().getTargetContext();
- spyOn(mContext);
- doReturn(mDisplayManager).when(mContext).getSystemService(eq(DisplayManager.class));
-
+ when(mContext.getSystemService(DisplayManager.class)).thenReturn(mDisplayManager);
doReturn(mActivityTaskManagerService).when(() -> ActivityTaskManager.getService());
mActivityTaskManagerService.mTaskSupervisor = mActivityTaskSupervisor;
when(mActivityTaskSupervisor.getLaunchParamsController()).thenReturn(
mLaunchParamsController);
- mActivityTaskManagerService.mSupportsMultiDisplay = true;
mActivityTaskManagerService.mRootWindowContainer = mRootWindowContainer;
- mActivityTaskManagerService.mPackageConfigPersister = mPackageConfigPersister;
- mActivityTaskManagerService.mWindowOrganizerController =
- new WindowOrganizerController(mActivityTaskManagerService);
- when(mActivityTaskManagerService.getTransitionController()).thenCallRealMethod();
- when(mActivityTaskManagerService.getRecentTasks()).thenReturn(mRecentTasks);
- when(mActivityTaskManagerService.getGlobalLock()).thenReturn(mWindowManagerGlobalLock);
-
- mWindowManagerService = WindowManagerService.main(
- mContext, mInputManagerService, /* showBootMsgs= */ false, /* onlyCore= */ false,
- /* policy= */ null, mActivityTaskManagerService,
- /* displayWindowSettingsProvider= */ null, () -> new SurfaceControl.Transaction(),
- /* surfaceFactory= */ null, /* surfaceControlFactory= */ null);
mActivityTaskManagerService.mWindowManager = mWindowManagerService;
- mRootWindowContainer.mWindowManager = mWindowManagerService;
-
+ when(mActivityTaskManagerService.getRecentTasks()).thenReturn(mRecentTasks);
+ mWindowManagerService.mTransactionFactory = () -> new SurfaceControl.Transaction();
AttributeCache.init(getInstrumentation().getTargetContext());
LocalServices.addService(ColorDisplayService.ColorDisplayServiceInternal.class,
mColorDisplayServiceInternal);
when(mActivityOptions.getLaunchDisplayId()).thenReturn(INVALID_DISPLAY);
mockDisplay(mDisplay0ForDriver, mDisplayArea0ForDriver, DEFAULT_DISPLAY,
FLAG_TRUSTED, /* type= */ 0);
- DisplayContent defaultDC = mRootWindowContainer.getDisplayContentOrCreate(DEFAULT_DISPLAY);
- mMapTaskDisplayArea = new TaskDisplayArea(
- defaultDC, mWindowManagerService, "MapTDA", FEATURE_MAP_ID);
- doAnswer((invocation) -> {
- Function<TaskDisplayArea, TaskDisplayArea> callback = invocation.getArgument(0);
- return callback.apply(mMapTaskDisplayArea);
- }).when(defaultDC).getItemFromTaskDisplayAreas(any());
- when(mActivityRecordSource.getDisplayContent()).thenReturn(defaultDC);
-
mockDisplay(mDisplay10ForPassenger, mDisplayArea10ForPassenger, PASSENGER_DISPLAY_ID_10,
FLAG_TRUSTED, /* type= */ 0);
mockDisplay(mDisplay11ForPassenger, mDisplayArea11ForPassenger, PASSENGER_DISPLAY_ID_11,
@@ -229,26 +181,23 @@
FLAG_TRUSTED | FLAG_PRIVATE, /* type= */ 0);
mockDisplay(mDisplay2Virtual, mDisplayArea2Virtual, VIRTUAL_DISPLAY_ID_2,
FLAG_PRIVATE, /* type= */ 0);
+ DisplayContent defaultDc = mRootWindowContainer.getDisplayContentOrCreate(DEFAULT_DISPLAY);
+ when(mActivityRecordSource.getDisplayContent()).thenReturn(defaultDc);
mModifier = new CarLaunchParamsModifier(mContext);
- mBuiltin = mModifier.getBuiltinInterface();
- mUpdatable = new CarLaunchParamsModifierUpdatableImpl(mBuiltin);
- mModifier.setUpdatable(mUpdatable);
mModifier.init();
}
@After
public void tearDown() {
- LocalServices.removeServiceForTest(WindowManagerInternal.class);
- LocalServices.removeServiceForTest(WindowManagerPolicy.class);
LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class);
mMockingSession.finishMocking();
}
private void assertDisplayIsAllowed(@UserIdInt int userId, Display display) {
mTask.mUserId = userId;
- mCurrentParams.mPreferredTaskDisplayArea = mBuiltin.getDefaultTaskDisplayAreaOnDisplay(
- display.getDisplayId()).getTaskDisplayArea();
+ mCurrentParams.mPreferredTaskDisplayArea = mModifier
+ .getDefaultTaskDisplayAreaOnDisplay(display.getDisplayId());
assertThat(mModifier.onCalculate(mTask, mWindowLayout, mActivityRecordActivity,
mActivityRecordSource, mActivityOptions, null /* request */, 0, mCurrentParams,
mOutParams))
@@ -259,10 +208,10 @@
Display displayAssigned) {
assertThat(displayRequested.getDisplayId()).isNotEqualTo(displayAssigned.getDisplayId());
mTask.mUserId = userId;
- TaskDisplayArea requestedTaskDisplayArea = mBuiltin.getDefaultTaskDisplayAreaOnDisplay(
- displayRequested.getDisplayId()).getTaskDisplayArea();
- TaskDisplayArea assignedTaskDisplayArea = mBuiltin.getDefaultTaskDisplayAreaOnDisplay(
- displayAssigned.getDisplayId()).getTaskDisplayArea();
+ TaskDisplayArea requestedTaskDisplayArea = mModifier
+ .getDefaultTaskDisplayAreaOnDisplay(displayRequested.getDisplayId());
+ TaskDisplayArea assignedTaskDisplayArea = mModifier
+ .getDefaultTaskDisplayAreaOnDisplay(displayAssigned.getDisplayId());
mCurrentParams.mPreferredTaskDisplayArea = requestedTaskDisplayArea;
assertThat(mModifier.onCalculate(mTask, mWindowLayout, mActivityRecordActivity,
mActivityRecordSource, mActivityOptions, null /* request */, 0, mCurrentParams,
@@ -306,14 +255,9 @@
return new ActivityRecord.Builder(mActivityTaskManagerService)
.setIntent(intent)
.setActivityInfo(info)
- .setConfiguration(new Configuration())
.build();
}
- private ActivityRecord buildActivityRecord(ComponentName componentName) {
- return buildActivityRecord(componentName.getPackageName(), componentName.getClassName());
- }
-
@Test
public void testNoPolicySet() {
final int randomUserId = 1000;
@@ -336,7 +280,7 @@
@Test
public void testAllowAllForDriverDuringBoot() {
- mUpdatable.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
+ mModifier.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
mDisplay10ForPassenger.getDisplayId()});
// USER_SYSTEM should be allowed always
@@ -345,7 +289,7 @@
@Test
public void testAllowAllForDriverAfterUserSwitching() {
- mUpdatable.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
+ mModifier.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
mDisplay10ForPassenger.getDisplayId()});
final int driver1 = 10;
@@ -361,11 +305,11 @@
@Test
public void testPassengerAllowed() {
- mUpdatable.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
+ mModifier.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
mDisplay11ForPassenger.getDisplayId()});
final int passengerUserId = 100;
- mUpdatable.setDisplayAllowListForUser(passengerUserId,
+ mModifier.setDisplayAllowListForUser(passengerUserId,
new int[]{mDisplay10ForPassenger.getDisplayId()});
assertDisplayIsAllowed(passengerUserId, mDisplay10ForPassenger);
@@ -373,17 +317,17 @@
@Test
public void testPassengerChange() {
- mUpdatable.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
+ mModifier.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
mDisplay11ForPassenger.getDisplayId()});
int passengerUserId1 = 100;
- mUpdatable.setDisplayAllowListForUser(passengerUserId1,
+ mModifier.setDisplayAllowListForUser(passengerUserId1,
new int[]{mDisplay11ForPassenger.getDisplayId()});
assertDisplayIsAllowed(passengerUserId1, mDisplay11ForPassenger);
int passengerUserId2 = 101;
- mUpdatable.setDisplayAllowListForUser(passengerUserId2,
+ mModifier.setDisplayAllowListForUser(passengerUserId2,
new int[]{mDisplay11ForPassenger.getDisplayId()});
assertDisplayIsAllowed(passengerUserId2, mDisplay11ForPassenger);
@@ -393,11 +337,11 @@
@Test
public void testPassengerNotAllowed() {
- mUpdatable.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
+ mModifier.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
mDisplay11ForPassenger.getDisplayId()});
final int passengerUserId = 100;
- mUpdatable.setDisplayAllowListForUser(
+ mModifier.setDisplayAllowListForUser(
passengerUserId, new int[]{mDisplay10ForPassenger.getDisplayId()});
assertDisplayIsReassigned(passengerUserId, mDisplay0ForDriver, mDisplay10ForPassenger);
@@ -406,11 +350,11 @@
@Test
public void testPassengerNotAllowedAfterUserSwitch() {
- mUpdatable.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
+ mModifier.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
mDisplay11ForPassenger.getDisplayId()});
int passengerUserId = 100;
- mUpdatable.setDisplayAllowListForUser(
+ mModifier.setDisplayAllowListForUser(
passengerUserId, new int[]{mDisplay11ForPassenger.getDisplayId()});
assertDisplayIsAllowed(passengerUserId, mDisplay11ForPassenger);
@@ -422,15 +366,15 @@
@Test
public void testPassengerNotAllowedAfterAssigningCurrentUser() {
- mUpdatable.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
+ mModifier.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
mDisplay11ForPassenger.getDisplayId()});
int passengerUserId = 100;
- mUpdatable.setDisplayAllowListForUser(
+ mModifier.setDisplayAllowListForUser(
passengerUserId, new int[]{mDisplay11ForPassenger.getDisplayId()});
assertDisplayIsAllowed(passengerUserId, mDisplay11ForPassenger);
- mUpdatable.setDisplayAllowListForUser(
+ mModifier.setDisplayAllowListForUser(
UserHandle.USER_SYSTEM, new int[]{mDisplay11ForPassenger.getDisplayId()});
assertDisplayIsReassigned(passengerUserId, mDisplay0ForDriver, mDisplay10ForPassenger);
@@ -439,18 +383,18 @@
@Test
public void testPassengerDisplayRemoved() {
- mUpdatable.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
+ mModifier.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
mDisplay11ForPassenger.getDisplayId()});
final int passengerUserId = 100;
- mUpdatable.setDisplayAllowListForUser(passengerUserId,
+ mModifier.setDisplayAllowListForUser(passengerUserId,
new int[]{mDisplay10ForPassenger.getDisplayId(),
mDisplay11ForPassenger.getDisplayId()});
assertDisplayIsAllowed(passengerUserId, mDisplay10ForPassenger);
assertDisplayIsAllowed(passengerUserId, mDisplay11ForPassenger);
- mUpdatable.getDisplayListener().onDisplayRemoved(mDisplay11ForPassenger.getDisplayId());
+ mModifier.mDisplayListener.onDisplayRemoved(mDisplay11ForPassenger.getDisplayId());
assertDisplayIsAllowed(passengerUserId, mDisplay10ForPassenger);
assertDisplayIsReassigned(passengerUserId, mDisplay11ForPassenger, mDisplay10ForPassenger);
@@ -458,18 +402,18 @@
@Test
public void testPassengerDisplayRemovedFromSetPassengerDisplays() {
- mUpdatable.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
+ mModifier.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
mDisplay11ForPassenger.getDisplayId()});
final int passengerUserId = 100;
- mUpdatable.setDisplayAllowListForUser(passengerUserId,
+ mModifier.setDisplayAllowListForUser(passengerUserId,
new int[]{mDisplay10ForPassenger.getDisplayId(),
mDisplay11ForPassenger.getDisplayId()});
assertDisplayIsAllowed(passengerUserId, mDisplay10ForPassenger);
assertDisplayIsAllowed(passengerUserId, mDisplay11ForPassenger);
- mUpdatable.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId()});
+ mModifier.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId()});
assertDisplayIsAllowed(passengerUserId, mDisplay10ForPassenger);
assertDisplayIsReassigned(passengerUserId, mDisplay11ForPassenger, mDisplay10ForPassenger);
@@ -477,11 +421,11 @@
@Test
public void testIgnorePrivateDisplay() {
- mUpdatable.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
+ mModifier.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
mDisplay11ForPassenger.getDisplayId()});
final int passengerUserId = 100;
- mUpdatable.setDisplayAllowListForUser(passengerUserId,
+ mModifier.setDisplayAllowListForUser(passengerUserId,
new int[]{mDisplay10ForPassenger.getDisplayId(),
mDisplay10ForPassenger.getDisplayId()});
@@ -490,13 +434,13 @@
@Test
public void testDriverPassengerSwap() {
- mUpdatable.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
+ mModifier.setPassengerDisplays(new int[]{mDisplay10ForPassenger.getDisplayId(),
mDisplay11ForPassenger.getDisplayId()});
final int wasDriver = 10;
final int wasPassenger = 11;
mModifier.handleCurrentUserSwitching(wasDriver);
- mUpdatable.setDisplayAllowListForUser(wasPassenger,
+ mModifier.setDisplayAllowListForUser(wasPassenger,
new int[]{mDisplay10ForPassenger.getDisplayId(),
mDisplay11ForPassenger.getDisplayId()});
@@ -510,7 +454,7 @@
final int driver = wasPassenger;
final int passenger = wasDriver;
mModifier.handleCurrentUserSwitching(driver);
- mUpdatable.setDisplayAllowListForUser(passenger,
+ mModifier.setDisplayAllowListForUser(passenger,
new int[]{mDisplay10ForPassenger.getDisplayId(),
mDisplay11ForPassenger.getDisplayId()});
@@ -529,23 +473,22 @@
// When no sourcePreferredComponents is set, it doesn't set the display for system user.
assertNoDisplayIsAssigned(UserHandle.USER_SYSTEM);
- mUpdatable.setSourcePreferredComponents(true, null);
+ mModifier.setSourcePreferredComponents(true, null);
assertDisplayIsAssigned(UserHandle.USER_SYSTEM, mDisplayArea0ForDriver);
}
@Test
public void testPreferSourceForPassenger() {
- mUpdatable.setPassengerDisplays(
- new int[]{PASSENGER_DISPLAY_ID_10, PASSENGER_DISPLAY_ID_11});
+ mModifier.setPassengerDisplays(new int[]{PASSENGER_DISPLAY_ID_10, PASSENGER_DISPLAY_ID_11});
int passengerUserId = 100;
- mUpdatable.setDisplayAllowListForUser(passengerUserId,
+ mModifier.setDisplayAllowListForUser(passengerUserId,
new int[]{PASSENGER_DISPLAY_ID_10, PASSENGER_DISPLAY_ID_11});
when(mActivityRecordSource.getDisplayArea()).thenReturn(mDisplayArea11ForPassenger);
// When no sourcePreferredComponents is set, it returns the default passenger display.
assertDisplayIsAssigned(passengerUserId, mDisplayArea10ForPassenger);
- mUpdatable.setSourcePreferredComponents(true, null);
+ mModifier.setSourcePreferredComponents(true, null);
assertDisplayIsAssigned(passengerUserId, mDisplayArea11ForPassenger);
}
@@ -554,7 +497,7 @@
when(mActivityOptions.getLaunchDisplayId()).thenReturn(PASSENGER_DISPLAY_ID_10);
when(mActivityRecordSource.getDisplayArea()).thenReturn(mDisplayArea0ForDriver);
- mUpdatable.setSourcePreferredComponents(true, null);
+ mModifier.setSourcePreferredComponents(true, null);
assertNoDisplayIsAssigned(UserHandle.USER_SYSTEM);
}
@@ -562,7 +505,7 @@
public void testPreferSourceForSpecifiedActivity() {
when(mActivityRecordSource.getDisplayArea()).thenReturn(mDisplayArea0ForDriver);
mActivityRecordActivity = buildActivityRecord("testPackage", "testActivity");
- mUpdatable.setSourcePreferredComponents(true,
+ mModifier.setSourcePreferredComponents(true,
Arrays.asList(new ComponentName("testPackage", "testActivity")));
assertDisplayIsAssigned(UserHandle.USER_SYSTEM, mDisplayArea0ForDriver);
@@ -572,7 +515,7 @@
public void testPreferSourceDoNotAssignDisplayForNonSpecifiedActivity() {
when(mActivityRecordSource.getDisplayArea()).thenReturn(mDisplayArea0ForDriver);
mActivityRecordActivity = buildActivityRecord("placeholderPackage", "placeholderActivity");
- mUpdatable.setSourcePreferredComponents(true,
+ mModifier.setSourcePreferredComponents(true,
Arrays.asList(new ComponentName("testPackage", "testActivity")));
assertNoDisplayIsAssigned(UserHandle.USER_SYSTEM);
@@ -622,9 +565,9 @@
.thenReturn(processName);
when(mActivityRecordActivity.getUid())
.thenReturn(processUid);
- mUpdatable.setPassengerDisplays(new int[]{mDisplay11ForPassenger.getDisplayId(),
+ mModifier.setPassengerDisplays(new int[]{mDisplay11ForPassenger.getDisplayId(),
mDisplay10ForPassenger.getDisplayId()});
- mUpdatable.setDisplayAllowListForUser(userId,
+ mModifier.setDisplayAllowListForUser(userId,
new int[]{mDisplay10ForPassenger.getDisplayId()});
WindowProcessController controller = mock(WindowProcessController.class);
when(mActivityTaskManagerService.getProcessController(processName, processUid))
@@ -650,9 +593,9 @@
.thenReturn(launchedFromPid);
when(mActivityRecordActivity.getLaunchedFromUid())
.thenReturn(launchedFromUid);
- mUpdatable.setPassengerDisplays(new int[]{mDisplay11ForPassenger.getDisplayId(),
+ mModifier.setPassengerDisplays(new int[]{mDisplay11ForPassenger.getDisplayId(),
mDisplay10ForPassenger.getDisplayId()});
- mUpdatable.setDisplayAllowListForUser(userId,
+ mModifier.setDisplayAllowListForUser(userId,
new int[]{mDisplay10ForPassenger.getDisplayId()});
WindowProcessController controller = mock(WindowProcessController.class);
when(mActivityTaskManagerService.getProcessController(launchedFromPid, launchedFromUid))
@@ -673,9 +616,9 @@
public void testSourceDisplayFromCallingDisplayIfAvailable() {
int userId = 10;
ActivityStarter.Request request = fakeRequest();
- mUpdatable.setPassengerDisplays(new int[]{mDisplay11ForPassenger.getDisplayId(),
+ mModifier.setPassengerDisplays(new int[]{mDisplay11ForPassenger.getDisplayId(),
mDisplay10ForPassenger.getDisplayId()});
- mUpdatable.setDisplayAllowListForUser(userId,
+ mModifier.setDisplayAllowListForUser(userId,
new int[]{mDisplay10ForPassenger.getDisplayId()});
WindowProcessController controller = mock(WindowProcessController.class);
when(mActivityTaskManagerService.getProcessController(request.realCallingPid,
@@ -696,7 +639,7 @@
@Test
public void testSourceDisplayIgnoredIfNotInAllowList() {
ActivityStarter.Request request = fakeRequest();
- mUpdatable.setPassengerDisplays(new int[]{mDisplay11ForPassenger.getDisplayId(),
+ mModifier.setPassengerDisplays(new int[]{mDisplay11ForPassenger.getDisplayId(),
mDisplay10ForPassenger.getDisplayId()});
WindowProcessController controller = mock(WindowProcessController.class);
when(mActivityTaskManagerService.getProcessController(anyString(), anyInt()))
@@ -715,64 +658,7 @@
.isEqualTo(mDisplayArea11ForPassenger);
}
- @Test
- public void testSetPersistentActivityThrowsExceptionForInvalidDisplayId() {
- ComponentName mapActivity = new ComponentName("testMapPkg", "mapActivity");
- int invalidDisplayId = 999990;
-
- assertThrows(IllegalArgumentException.class,
- () -> mUpdatable.setPersistentActivity(mapActivity,
- invalidDisplayId, DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER));
- }
-
- @Test
- public void testSetPersistentActivityThrowsExceptionForInvalidFeatureId() {
- ComponentName mapActivity = new ComponentName("testMapPkg", "mapActivity");
- int invalidFeatureId = 999990;
-
- assertThrows(IllegalArgumentException.class,
- () -> mUpdatable.setPersistentActivity(mapActivity,
- DEFAULT_DISPLAY, invalidFeatureId));
- }
-
- @Test
- public void testPersistentActivityOverridesTDA() {
- ComponentName mapActivityName = new ComponentName("testMapPkg", "mapActivity");
- mActivityRecordActivity = buildActivityRecord(mapActivityName);
-
- int ret = mUpdatable.setPersistentActivity(
- mapActivityName, DEFAULT_DISPLAY, FEATURE_MAP_ID);
- assertThat(ret).isEqualTo(CarActivityManager.RESULT_SUCCESS);
-
- assertDisplayIsAssigned(UserHandle.USER_SYSTEM, mMapTaskDisplayArea);
- }
-
- @Test
- public void testRemovePersistentActivity() {
- ComponentName mapActivityName = new ComponentName("testMapPkg", "mapActivity");
- mActivityRecordActivity = buildActivityRecord(mapActivityName);
-
- int ret = mUpdatable.setPersistentActivity(
- mapActivityName, DEFAULT_DISPLAY, FEATURE_MAP_ID);
- assertThat(ret).isEqualTo(CarActivityManager.RESULT_SUCCESS);
- // Removes the existing persistent Activity assignment.
- ret = mUpdatable.setPersistentActivity(mapActivityName, DEFAULT_DISPLAY,
- DisplayAreaOrganizer.FEATURE_UNDEFINED);
- assertThat(ret).isEqualTo(CarActivityManager.RESULT_SUCCESS);
-
- assertNoDisplayIsAssigned(UserHandle.USER_SYSTEM);
- }
-
- @Test
- public void testRemoveUnknownPersistentActivityThrowsException() {
- ComponentName mapActivity = new ComponentName("testMapPkg", "mapActivity");
-
- assertThrows(ServiceSpecificException.class,
- () -> mUpdatable.setPersistentActivity(mapActivity, DEFAULT_DISPLAY,
- DisplayAreaOrganizer.FEATURE_UNDEFINED));
- }
-
- private static ActivityStarter.Request fakeRequest() {
+ private ActivityStarter.Request fakeRequest() {
ActivityStarter.Request request = new ActivityStarter.Request();
request.realCallingPid = 1324;
request.realCallingUid = 235;
diff --git a/updatableServices/Android.bp b/updatableServices/Android.bp
deleted file mode 100644
index 2adcba7..0000000
--- a/updatableServices/Android.bp
+++ /dev/null
@@ -1,31 +0,0 @@
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-java_library {
- name: "car-frameworks-service-module",
- installable: true,
- libs: [
- "android.car",
- "android.car.builtin",
- "car-frameworks-service",
- "framework-annotations-lib",
- "modules-utils-preconditions",
- ],
- srcs: [
- "src/**/*.java",
- ],
-
- sdk_version: "module_current",
- min_sdk_version: "31",
- apex_available: [
- "//apex_available:platform",
- "com.android.car.framework"
- ],
- product_variables: {
- pdk: {
- enabled: false,
- },
- },
-}
-
diff --git a/updatableServices/src/com/android/internal/car/updatable/CarServiceHelperServiceUpdatableImpl.java b/updatableServices/src/com/android/internal/car/updatable/CarServiceHelperServiceUpdatableImpl.java
deleted file mode 100644
index 0b3b094..0000000
--- a/updatableServices/src/com/android/internal/car/updatable/CarServiceHelperServiceUpdatableImpl.java
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2021 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.internal.car.updatable;
-
-import static com.android.car.internal.SystemConstants.ICAR_SYSTEM_SERVER_CLIENT;
-import static com.android.car.internal.common.CommonConstants.CAR_SERVICE_INTERFACE;
-
-import android.annotation.Nullable;
-import android.car.ICar;
-import android.car.ICarResultReceiver;
-import android.car.builtin.os.UserManagerHelper;
-import android.car.builtin.util.EventLogHelper;
-import android.car.builtin.util.Slogf;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.SystemProperties;
-import android.os.UserHandle;
-
-import com.android.car.internal.ICarServiceHelper;
-import com.android.car.internal.ICarSystemServerClient;
-import com.android.car.internal.util.IndentingPrintWriter;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.car.CarServiceHelperInterface;
-import com.android.internal.car.CarServiceHelperServiceUpdatable;
-import java.io.File;
-import com.android.server.wm.CarLaunchParamsModifierInterface;
-import com.android.server.wm.CarLaunchParamsModifierUpdatable;
-import com.android.server.wm.CarLaunchParamsModifierUpdatableImpl;
-
-import java.io.PrintWriter;
-import java.util.List;
-import java.util.concurrent.Executor;
-import java.util.function.BiConsumer;
-
-/**
- * Implementation of the abstract class CarServiceHelperUpdatable
- */
-public final class CarServiceHelperServiceUpdatableImpl
- implements CarServiceHelperServiceUpdatable, Executor {
-
- @VisibleForTesting
- static final String TAG = "CarServiceHelper";
-
- private static final boolean DBG = false;
-
- private static final String PROP_RESTART_RUNTIME = "ro.car.recovery.restart_runtime.enabled";
-
- private static final long CAR_SERVICE_BINDER_CALL_TIMEOUT_MS = 15_000;
-
- private final Runnable mCallbackForCarServiceUnresponsiveness;
-
- // exit code for
- private static final int STATUS_CODE_To_EXIT = 10;
-
- private static final String CAR_SERVICE_PACKAGE = "com.android.car";
-
- private final Context mContext;
- private final Object mLock = new Object();
- @GuardedBy("mLock")
- private ICar mCarServiceBinder;
-
- private final Handler mHandler;
- private final HandlerThread mHandlerThread = new HandlerThread(
- CarServiceHelperServiceUpdatableImpl.class.getSimpleName());
-
- private final ICarServiceHelperImpl mHelper = new ICarServiceHelperImpl();
-
- private final CarServiceConnectedCallback mCarServiceConnectedCallback =
- new CarServiceConnectedCallback();
-
- private final CarServiceProxy mCarServiceProxy;
-
- private final CarServiceHelperInterface mCarServiceHelperInterface;
-
- private final CarLaunchParamsModifierUpdatableImpl mCarLaunchParamsModifierUpdatable;
-
- public CarServiceHelperServiceUpdatableImpl(Context context,
- CarServiceHelperInterface carServiceHelperInterface,
- CarLaunchParamsModifierInterface carLaunchParamsModifierInterface) {
- this(context, carServiceHelperInterface, carLaunchParamsModifierInterface,
- /* carServiceProxy= */ null);
- }
-
- @VisibleForTesting
- CarServiceHelperServiceUpdatableImpl(Context context,
- CarServiceHelperInterface carServiceHelperInterface,
- CarLaunchParamsModifierInterface carLaunchParamsModifierInterface,
- @Nullable CarServiceProxy carServiceProxy) {
- mContext = context;
- mHandlerThread.start();
- mHandler = new Handler(mHandlerThread.getLooper());
- mCarServiceHelperInterface = carServiceHelperInterface;
- mCarLaunchParamsModifierUpdatable = new CarLaunchParamsModifierUpdatableImpl(
- carLaunchParamsModifierInterface);
- // carServiceProxy is Nullable because it is not possible to construct carServiceProxy with
- // "this" object in the previous constructor as CarServiceHelperServiceUpdatableImpl has
- // not been fully constructed.
- mCarServiceProxy = carServiceProxy == null ? new CarServiceProxy(this) : carServiceProxy;
- mCallbackForCarServiceUnresponsiveness = () -> handleCarServiceUnresponsive();
- }
-
- private final ServiceConnection mCarServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
- if (DBG) Slogf.d(TAG, "onServiceConnected: %s", iBinder);
- handleCarServiceConnection(iBinder);
- }
-
- @Override
- public void onServiceDisconnected(ComponentName componentName) {
- handleCarServiceCrash();
- }
- };
-
- @Override
- public void onStart() {
- Intent intent = new Intent(CAR_SERVICE_INTERFACE).setPackage(CAR_SERVICE_PACKAGE);
- Context userContext = mContext.createContextAsUser(UserHandle.SYSTEM, /* flags= */ 0);
- if (!userContext.bindService(intent, Context.BIND_AUTO_CREATE, this,
- mCarServiceConnection)) {
- Slogf.wtf(TAG, "cannot start car service");
- }
- }
-
- @Override // From Executor
- public void execute(Runnable command) {
- mHandler.post(command);
- }
-
- @Override
- public void onUserRemoved(UserHandle user) {
- mCarServiceProxy.onUserRemoved(user);
- }
-
- @Override
- public void onFactoryReset(BiConsumer<Integer, Bundle> callback) {
- ICarResultReceiver resultReceiver = new ICarResultReceiver.Stub() {
- @Override
- public void send(int resultCode, Bundle resultData) throws RemoteException {
- callback.accept(resultCode, resultData);
-
- }
- };
- mCarServiceProxy.onFactoryReset(resultReceiver);
- }
-
- @Override
- public void initBootUser() {
- mCarServiceProxy.initBootUser();
- }
-
- @Override
- public CarLaunchParamsModifierUpdatable getCarLaunchParamsModifierUpdatable() {
- return mCarLaunchParamsModifierUpdatable;
- }
-
- @VisibleForTesting
- void handleCarServiceConnection(IBinder iBinder) {
- synchronized (mLock) {
- if (mCarServiceBinder == ICar.Stub.asInterface(iBinder)) {
- return; // already connected.
- }
- if (DBG) {
- Slogf.d(TAG, "car service binder changed, was %s new: %s", mCarServiceBinder,
- iBinder);
- }
- mCarServiceBinder = ICar.Stub.asInterface(iBinder);
- Slogf.i(TAG, "**CarService connected**");
- }
-
- EventLogHelper.writeCarHelperServiceConnected();
-
- // Post mCallbackForCarServiceUnresponsiveness before setting system server connection
- // because CarService may respond before the sendSetSystemServerConnectionsCall call
- // returns and try to remove mCallbackForCarServiceUnresponsiveness from the handler.
- // Thus, posting this callback after setting system server connection may result in a race
- // condition where the callback is never removed from the handler.
- mHandler.removeCallbacks(mCallbackForCarServiceUnresponsiveness);
- mHandler.postDelayed(mCallbackForCarServiceUnresponsiveness,
- CAR_SERVICE_BINDER_CALL_TIMEOUT_MS);
-
- sendSetSystemServerConnectionsCall();
- }
-
- @VisibleForTesting
- void handleCarServiceCrash() {
- // Recovery behavior. Kill the system server and reset
- // everything if enabled by the property.
- boolean restartOnServiceCrash = SystemProperties.getBoolean(PROP_RESTART_RUNTIME, false);
- mHandler.removeCallbacks(mCallbackForCarServiceUnresponsiveness);
-
- mCarServiceHelperInterface.dumpServiceStacks();
- if (restartOnServiceCrash) {
- Slogf.w(TAG, "*** CARHELPER KILLING SYSTEM PROCESS: CarService crash");
- Slogf.w(TAG, "*** GOODBYE!");
- Process.killProcess(Process.myPid());
- System.exit(STATUS_CODE_To_EXIT);
- } else {
- Slogf.w(TAG, "*** CARHELPER ignoring: CarService crash");
- }
- }
-
- private void sendSetSystemServerConnectionsCall() {
- ICar binder;
- synchronized (mLock) {
- binder = mCarServiceBinder;
- }
- try {
- binder.setSystemServerConnections(mHelper, mCarServiceConnectedCallback);
- } catch (RemoteException e) {
- Slogf.w(TAG, e, "RemoteException from car service");
- handleCarServiceCrash();
- } catch (RuntimeException e) {
- Slogf.wtf(TAG, e, "Exception calling setSystemServerConnections");
- throw e;
- }
- }
-
- private void handleCarServiceUnresponsive() {
- // This should not happen. Calling this method means ICarSystemServerClient binder is not
- // returned after service connection. and CarService has not connected in the given time.
- Slogf.w(TAG, "*** CARHELPER KILLING SYSTEM PROCESS: CarService unresponsive.");
- Slogf.w(TAG, "*** GOODBYE!");
- Process.killProcess(Process.myPid());
- System.exit(STATUS_CODE_To_EXIT);
- }
-
- @Override
- public void sendUserLifecycleEvent(int eventType, UserHandle userFrom, UserHandle userTo) {
- mCarServiceProxy.sendUserLifecycleEvent(eventType,
- userFrom == null ? UserManagerHelper.USER_NULL : userFrom.getIdentifier(),
- userTo.getIdentifier());
- }
-
- @Override
- public void dump(PrintWriter writer, String[] args) {
- if (args != null && args.length > 0 && "--user-metrics-only".equals(args[0])) {
- mCarServiceProxy.dumpUserMetrics(new IndentingPrintWriter(writer));
- return;
- }
-
- if (args != null && args.length > 0 && "--dump-service-stacks".equals(args[0])) {
- File file = mCarServiceHelperInterface.dumpServiceStacks();
- if (file != null) {
- writer.printf("dumpServiceStacks ANR file path=%s\n", file.getAbsolutePath());
- } else {
- writer.printf("dumpServiceStacks no ANR file.\n");
- }
- return;
- }
-
- mCarServiceProxy.dump(new IndentingPrintWriter(writer));
- }
-
- private final class ICarServiceHelperImpl extends ICarServiceHelper.Stub {
-
- @Override
- public void setDisplayAllowlistForUser(int userId, int[] displayIds) {
- mCarLaunchParamsModifierUpdatable.setDisplayAllowListForUser(userId, displayIds);
- }
-
- @Override
- public void setPassengerDisplays(int[] displayIdsForPassenger) {
- mCarLaunchParamsModifierUpdatable.setPassengerDisplays(displayIdsForPassenger);
- }
-
- @Override
- public void setSourcePreferredComponents(boolean enableSourcePreferred,
- @Nullable List<ComponentName> sourcePreferredComponents) {
- mCarLaunchParamsModifierUpdatable.setSourcePreferredComponents(
- enableSourcePreferred, sourcePreferredComponents);
- }
-
- @Override
- public int setPersistentActivity(ComponentName activity, int displayId, int featureId) {
- return mCarLaunchParamsModifierUpdatable.setPersistentActivity(
- activity, displayId, featureId);
- }
-
- @Override
- public void setSafetyMode(boolean safe) {
- mCarServiceHelperInterface.setSafetyMode(safe);
- }
-
- @Override
- public UserHandle createUserEvenWhenDisallowed(String name, String userType, int flags) {
- return mCarServiceHelperInterface.createUserEvenWhenDisallowed(name, userType, flags);
- }
-
- @Override
- public void sendInitialUser(UserHandle user) {
- mCarServiceProxy.saveInitialUser(user);
- }
- }
-
- private final class CarServiceConnectedCallback extends ICarResultReceiver.Stub {
- @Override
- public void send(int resultCode, Bundle resultData) {
- mHandler.removeCallbacks(mCallbackForCarServiceUnresponsiveness);
-
- IBinder binder;
- if (resultData == null
- || (binder = resultData.getBinder(ICAR_SYSTEM_SERVER_CLIENT)) == null) {
- Slogf.wtf(TAG, "setSystemServerConnections return NULL data or Binder.");
- handleCarServiceUnresponsive();
- return;
- }
-
- ICarSystemServerClient carService = ICarSystemServerClient.Stub.asInterface(binder);
- mCarServiceProxy.handleCarServiceConnection(carService);
- }
- }
-}
diff --git a/updatableServices/src/com/android/server/wm/CarLaunchParamsModifierUpdatableImpl.java b/updatableServices/src/com/android/server/wm/CarLaunchParamsModifierUpdatableImpl.java
deleted file mode 100644
index d836c03..0000000
--- a/updatableServices/src/com/android/server/wm/CarLaunchParamsModifierUpdatableImpl.java
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.annotation.UserIdInt;
-import android.car.app.CarActivityManager;
-import android.car.builtin.os.UserManagerHelper;
-import android.car.builtin.util.Slogf;
-import android.car.builtin.view.DisplayHelper;
-import android.car.builtin.window.DisplayAreaOrganizerHelper;
-import android.content.ComponentName;
-import android.hardware.display.DisplayManager;
-import android.os.ServiceSpecificException;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.SparseIntArray;
-import android.view.Display;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Implementation of {@link CarLaunchParamsModifierUpdatable}.
- *
- * @hide
- */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public final class CarLaunchParamsModifierUpdatableImpl
- implements CarLaunchParamsModifierUpdatable {
- private static final String TAG = "CAR.LAUNCH";
- private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
-
- private final CarLaunchParamsModifierInterface mBuiltin;
- private final Object mLock = new Object();
-
- // Always start with USER_SYSTEM as the timing of handleCurrentUserSwitching(USER_SYSTEM) is not
- // guaranteed to be earler than 1st Activity launch.
- @GuardedBy("mLock")
- private int mCurrentDriverUser = UserManagerHelper.USER_SYSTEM;
-
- // TODO: Switch from tracking displays to tracking display areas instead
- /**
- * This one is for holding all passenger (=profile user) displays which are mostly static unless
- * displays are added / removed. Note that {@link #mDisplayToProfileUserMapping} can be empty
- * while user is assigned and that cannot always tell if specific display is for driver or not.
- */
- @GuardedBy("mLock")
- private final ArrayList<Integer> mPassengerDisplays = new ArrayList<>();
-
- /** key: display id, value: profile user id */
- @GuardedBy("mLock")
- private final SparseIntArray mDisplayToProfileUserMapping = new SparseIntArray();
-
- /** key: profile user id, value: display id */
- @GuardedBy("mLock")
- private final SparseIntArray mDefaultDisplayForProfileUser = new SparseIntArray();
-
- @GuardedBy("mLock")
- private boolean mIsSourcePreferred;
-
- @GuardedBy("mLock")
- private List<ComponentName> mSourcePreferredComponents;
-
- /** key: Activity, value: TaskDisplayAreaWrapper */
- @GuardedBy("mLock")
- private final ArrayMap<ComponentName, TaskDisplayAreaWrapper> mPersistentActivities =
- new ArrayMap<>();
-
- public CarLaunchParamsModifierUpdatableImpl(CarLaunchParamsModifierInterface builtin) {
- mBuiltin = builtin;
- }
-
- public DisplayManager.DisplayListener getDisplayListener() {
- return mDisplayListener;
- }
-
- private final DisplayManager.DisplayListener mDisplayListener =
- new DisplayManager.DisplayListener() {
- @Override
- public void onDisplayAdded(int displayId) {
- // ignore. car service should update whiltelist.
- }
-
- @Override
- public void onDisplayRemoved(int displayId) {
- synchronized (mLock) {
- mPassengerDisplays.remove(Integer.valueOf(displayId));
- updateProfileUserConfigForDisplayRemovalLocked(displayId);
- }
- }
-
- @Override
- public void onDisplayChanged(int displayId) {
- // ignore
- }
- };
-
- @GuardedBy("mLock")
- private void updateProfileUserConfigForDisplayRemovalLocked(int displayId) {
- mDisplayToProfileUserMapping.delete(displayId);
- int i = mDefaultDisplayForProfileUser.indexOfValue(displayId);
- if (i >= 0) {
- mDefaultDisplayForProfileUser.removeAt(i);
- }
- }
-
- /**
- * Sets {@code sourcePreferred} configuration. When {@code sourcePreferred} is enabled and
- * there is no pre-assigned display for the Activity, CarLauncherParamsModifier will launch
- * the Activity in the display of the source. When {@code sourcePreferredComponents} isn't null
- * the {@code sourcePreferred} is applied for the {@code sourcePreferredComponents} only.
- *
- * @param enableSourcePreferred whether to enable sourcePreferred mode
- * @param sourcePreferredComponents null for all components, or the list of components to apply
- */
- public void setSourcePreferredComponents(boolean enableSourcePreferred,
- @Nullable List<ComponentName> sourcePreferredComponents) {
- synchronized (mLock) {
- mIsSourcePreferred = enableSourcePreferred;
- mSourcePreferredComponents = sourcePreferredComponents;
- if (mSourcePreferredComponents != null) {
- Collections.sort(mSourcePreferredComponents);
- }
- }
- }
-
- /** Notifies user starting. */
- public void handleUserStarting(int startingUser) {
- // Do nothing
- }
-
- /** Notifies user switching. */
- public void handleCurrentUserSwitching(@UserIdInt int newUserId) {
- synchronized (mLock) {
- mCurrentDriverUser = newUserId;
- mDefaultDisplayForProfileUser.clear();
- mDisplayToProfileUserMapping.clear();
- }
- }
-
- @GuardedBy("mLock")
- private void removeUserFromAllowlistsLocked(int userId) {
- for (int i = mDisplayToProfileUserMapping.size() - 1; i >= 0; i--) {
- if (mDisplayToProfileUserMapping.valueAt(i) == userId) {
- mDisplayToProfileUserMapping.removeAt(i);
- }
- }
- mDefaultDisplayForProfileUser.delete(userId);
- }
-
- /** Notifies user stopped. */
- public void handleUserStopped(@UserIdInt int stoppedUser) {
- // Note that the current user is never stopped. It always takes switching into
- // non-current user before stopping the user.
- synchronized (mLock) {
- removeUserFromAllowlistsLocked(stoppedUser);
- }
- }
-
- /**
- * Sets display allowlist for the {@code userId}. For passenger user, activity will be always
- * launched to a display in the allowlist. If requested display is not in the allowlist, the 1st
- * display in the allowlist will be selected as target display.
- *
- * <p>The allowlist is kept only for profile user. Assigning the current user unassigns users
- * for the given displays.
- */
- public void setDisplayAllowListForUser(@UserIdInt int userId, int[] displayIds) {
- if (DBG) {
- Slogf.d(TAG, "setDisplayAllowlistForUser userId:%d displays:%s",
- userId, Arrays.toString(displayIds));
- }
- synchronized (mLock) {
- for (int displayId : displayIds) {
- if (!mPassengerDisplays.contains(displayId)) {
- Slogf.w(TAG, "setDisplayAllowlistForUser called with display:%d"
- + " not in passenger display list:%s", displayId, mPassengerDisplays);
- continue;
- }
- if (userId == mCurrentDriverUser) {
- mDisplayToProfileUserMapping.delete(displayId);
- } else {
- mDisplayToProfileUserMapping.put(displayId, userId);
- }
- // now the display cannot be a default display for other user
- int i = mDefaultDisplayForProfileUser.indexOfValue(displayId);
- if (i >= 0) {
- mDefaultDisplayForProfileUser.removeAt(i);
- }
- }
- if (displayIds.length > 0) {
- mDefaultDisplayForProfileUser.put(userId, displayIds[0]);
- } else {
- removeUserFromAllowlistsLocked(userId);
- }
- }
- }
-
- /**
- * Sets displays assigned to passenger. All other displays will be treated as assigned to
- * driver.
- *
- * <p>The 1st display in the array will be considered as a default display to assign
- * for any non-driver user if there is no display assigned for the user. </p>
- */
- public void setPassengerDisplays(int[] displayIdsForPassenger) {
- if (DBG) {
- Slogf.d(TAG, "setPassengerDisplays displays:%s",
- Arrays.toString(displayIdsForPassenger));
- }
- synchronized (mLock) {
- for (int id : displayIdsForPassenger) {
- mPassengerDisplays.remove(Integer.valueOf(id));
- }
- // handle removed displays
- for (int i = 0; i < mPassengerDisplays.size(); i++) {
- int displayId = mPassengerDisplays.get(i);
- updateProfileUserConfigForDisplayRemovalLocked(displayId);
- }
- mPassengerDisplays.clear();
- mPassengerDisplays.ensureCapacity(displayIdsForPassenger.length);
- for (int id : displayIdsForPassenger) {
- mPassengerDisplays.add(id);
- }
- }
- }
-
- /**
- * Calculates {@code outParams} based on the given arguments.
- * See {@code LaunchParamsController.LaunchParamsModifier.onCalculate()} for the detail.
- */
- public int calculate(CalculateParams params) {
- TaskWrapper task = params.getTask();
- ActivityRecordWrapper activity = params.getActivity();
- ActivityRecordWrapper source = params.getSource();
- ActivityOptionsWrapper options = params.getOptions();
- RequestWrapper request = params.getRequest();
- LaunchParamsWrapper currentParams = params.getCurrentParams();
- LaunchParamsWrapper outParams = params.getOutParams();
-
- int userId;
- if (task != null) {
- userId = task.getUserId();
- } else if (activity != null) {
- userId = activity.getUserId();
- } else {
- Slogf.w(TAG, "onCalculate, cannot decide user");
- return LaunchParamsWrapper.RESULT_SKIP;
- }
- // DisplayArea where user wants to launch the Activity.
- TaskDisplayAreaWrapper originalDisplayArea = currentParams.getPreferredTaskDisplayArea();
- // DisplayArea where CarLaunchParamsModifier targets to launch the Activity.
- TaskDisplayAreaWrapper targetDisplayArea = null;
- if (DBG) {
- Slogf.d(TAG, "onCalculate, userId:%d original displayArea:%s ActivityOptions:%s",
- userId, originalDisplayArea, options);
- }
- ComponentName activityName = activity.getComponentName();
- decision:
- synchronized (mLock) {
- // If originalDisplayArea is set, respect that before ActivityOptions check.
- if (originalDisplayArea == null) {
- if (options != null) {
- originalDisplayArea = options.getLaunchTaskDisplayArea();
- if (originalDisplayArea == null) {
- originalDisplayArea = mBuiltin.getDefaultTaskDisplayAreaOnDisplay(
- options.getOptions().getLaunchDisplayId());
- }
- }
- }
- if (mPersistentActivities.containsKey(activityName)) {
- targetDisplayArea = mPersistentActivities.get(activityName);
- } else if (originalDisplayArea == null // No specified DA to launch the Activity
- && mIsSourcePreferred && source != null
- && (mSourcePreferredComponents == null || Collections.binarySearch(
- mSourcePreferredComponents, activityName) >= 0)) {
- targetDisplayArea = source.isNoDisplay() ? source.getHandoverTaskDisplayArea()
- : source.getDisplayArea();
- } else if (originalDisplayArea == null
- && task == null // launching as a new task
- && source != null && !source.isDisplayTrusted()
- && !source.allowingEmbedded()) {
- if (DBG) {
- Slogf.d(TAG, "Disallow launch on virtual display for not-embedded activity.");
- }
- targetDisplayArea = mBuiltin.getDefaultTaskDisplayAreaOnDisplay(
- Display.DEFAULT_DISPLAY);
- }
- if (userId == mCurrentDriverUser) {
- // Respect the existing DisplayArea.
- break decision;
- }
- if (userId == UserManagerHelper.USER_SYSTEM) {
- // This will be only allowed if it has FLAG_SHOW_FOR_ALL_USERS.
- // The flag is not immediately accessible here so skip the check.
- // But other WM policy will enforce it.
- break decision;
- }
- // Now user is a passenger.
- if (mPassengerDisplays.isEmpty()) {
- // No displays for passengers. This could be old user and do not do anything.
- break decision;
- }
- if (targetDisplayArea == null) {
- if (originalDisplayArea != null) {
- targetDisplayArea = originalDisplayArea;
- } else {
- targetDisplayArea = mBuiltin.getDefaultTaskDisplayAreaOnDisplay(
- Display.DEFAULT_DISPLAY);
- }
- }
- Display display = targetDisplayArea.getDisplay();
- if ((display.getFlags() & Display.FLAG_PRIVATE) != 0) {
- // private display should follow its own restriction rule.
- break decision;
- }
- if (DisplayHelper.getType(display) == DisplayHelper.TYPE_VIRTUAL) {
- // TODO(b/132903422) : We need to update this after the bug is resolved.
- // For now, don't change anything.
- break decision;
- }
- int userForDisplay = mDisplayToProfileUserMapping.get(display.getDisplayId(),
- UserManagerHelper.USER_NULL);
- if (userForDisplay == userId) {
- break decision;
- }
- targetDisplayArea = getAlternativeDisplayAreaForPassengerLocked(
- userId, activity, request);
- }
- if (targetDisplayArea != null && originalDisplayArea != targetDisplayArea) {
- Slogf.i(TAG, "Changed launching display, user:%d requested display area:%s"
- + " target display area:", userId, originalDisplayArea, targetDisplayArea);
- outParams.setPreferredTaskDisplayArea(targetDisplayArea);
- return LaunchParamsWrapper.RESULT_DONE;
- } else {
- return LaunchParamsWrapper.RESULT_SKIP;
- }
- }
-
- @GuardedBy("mLock")
- @Nullable
- private TaskDisplayAreaWrapper getAlternativeDisplayAreaForPassengerLocked(int userId,
- @NonNull ActivityRecordWrapper activtyRecord, @Nullable RequestWrapper request) {
- List<TaskDisplayAreaWrapper> fallbacks = mBuiltin.getFallbackDisplayAreasForActivity(
- activtyRecord, request);
- for (int i = 0, size = fallbacks.size(); i < size; ++i) {
- TaskDisplayAreaWrapper fallbackTda = fallbacks.get(i);
- int userForDisplay = getUserIdForDisplayLocked(fallbackTda.getDisplay().getDisplayId());
- if (userForDisplay == userId) {
- return fallbackTda;
- }
- }
- return fallbackDisplayAreaForUserLocked(userId);
- }
-
- /**
- * Returns {@code userId} who is allowed to use the given {@code displayId}, or
- * {@code UserHandle.USER_NULL} if the display doesn't exist in the mapping.
- */
- @GuardedBy("mLock")
- private int getUserIdForDisplayLocked(int displayId) {
- return mDisplayToProfileUserMapping.get(displayId, UserManagerHelper.USER_NULL);
- }
-
- /**
- * Return a {@link TaskDisplayAreaWrapper} that can be used if a source display area is
- * not found. First check the default display for the user. If it is absent select
- * the first passenger display if present. If both are absent return {@code null}
- *
- * @param userId ID of the active user
- * @return {@link TaskDisplayAreaWrapper} that is recommended when a display area is
- * not specified
- */
- @GuardedBy("mLock")
- @Nullable
- private TaskDisplayAreaWrapper fallbackDisplayAreaForUserLocked(@UserIdInt int userId) {
- int displayIdForUserProfile = mDefaultDisplayForProfileUser.get(userId,
- Display.INVALID_DISPLAY);
- if (displayIdForUserProfile != Display.INVALID_DISPLAY) {
- int displayId = mDefaultDisplayForProfileUser.get(userId);
- return mBuiltin.getDefaultTaskDisplayAreaOnDisplay(displayId);
- }
- if (!mPassengerDisplays.isEmpty()) {
- int displayId = mPassengerDisplays.get(0);
- return mBuiltin.getDefaultTaskDisplayAreaOnDisplay(displayId);
- }
- return null;
- }
-
- /**
- * See {@link CarActivityManager#setPersistentActivity(android.content.ComponentName,int, int)}
- */
- public int setPersistentActivity(ComponentName activity, int displayId, int featureId) {
- if (DBG) {
- Slogf.d(TAG, "setPersistentActivity: activity=%s, displayId=%d, featureId=%d",
- activity, displayId, featureId);
- }
- if (featureId == DisplayAreaOrganizerHelper.FEATURE_UNDEFINED) {
- synchronized (mLock) {
- TaskDisplayAreaWrapper removed = mPersistentActivities.remove(activity);
- if (removed == null) {
- throw new ServiceSpecificException(
- CarActivityManager.ERROR_CODE_ACTIVITY_NOT_FOUND,
- "Failed to remove " + activity.toShortString());
- }
- return CarActivityManager.RESULT_SUCCESS;
- }
- }
- TaskDisplayAreaWrapper tda = mBuiltin.findTaskDisplayArea(displayId, featureId);
- if (tda == null) {
- throw new IllegalArgumentException("Unknown display=" + displayId
- + " or feature=" + featureId);
- }
- synchronized (mLock) {
- mPersistentActivities.put(activity, tda);
- }
- return CarActivityManager.RESULT_SUCCESS;
- }
-}
\ No newline at end of file
diff --git a/updatableServices/tests/Android.bp b/updatableServices/tests/Android.bp
deleted file mode 100644
index 7d9e971..0000000
--- a/updatableServices/tests/Android.bp
+++ /dev/null
@@ -1,50 +0,0 @@
-package {
- // See: http://go/android-license-faq
- default_applicable_licenses: [
- "Android-Apache-2.0",
- ],
-}
-
-android_test {
- name: "FrameworkOptCarServicesUpdatableTest",
-
- srcs: [
- "src/**/*.java",
- ],
-
- platform_apis: true,
-
- certificate: "platform",
-
- optimize: {
- enabled: false,
- },
-
- libs: [
- "android.car",
- "android.car.builtin",
- "android.test.runner",
- "android.test.base",
- "android.hardware.automotive.vehicle-V2.0-java",
- ],
-
- static_libs: [
- "android.car.test.utils",
- "android.car.watchdoglib",
- "androidx.test.ext.junit",
- "androidx.test.rules",
- "car-frameworks-service.impl",
- "car-frameworks-service-module",
- "mockito-target-extended-minus-junit4",
- "services.core",
- "testng",
- "truth-prebuilt",
- ],
-
- // mockito-target-extended dependencies
- jni_libs: [
- "libdexmakerjvmtiagent",
- "libstaticjvmtiagent",
- ],
-
-}
diff --git a/updatableServices/tests/AndroidManifest.xml b/updatableServices/tests/AndroidManifest.xml
deleted file mode 100644
index 2a3e07f..0000000
--- a/updatableServices/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- package="com.android.internal.car.updatable"
- android:sharedUserId="android.uid.system" >
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.internal.car.updatable"
- android:label="Unit Tests for Car Framework Updatable Services"/>
-
- <application android:label="FrameworkOptCarServicesUpdatableTest"
- android:debuggable="true">
- <uses-library android:name="android.test.runner" />
- </application>
-</manifest>
diff --git a/updatableServices/tests/src/com/android/internal/car/updatable/CarServiceHelperServiceUpdatableImplTest.java b/updatableServices/tests/src/com/android/internal/car/updatable/CarServiceHelperServiceUpdatableImplTest.java
deleted file mode 100644
index 6e5231b..0000000
--- a/updatableServices/tests/src/com/android/internal/car/updatable/CarServiceHelperServiceUpdatableImplTest.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2021 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.internal.car.updatable;
-
-import static com.android.car.internal.common.CommonConstants.CAR_SERVICE_INTERFACE;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doThrow;
-
-import android.car.ICar;
-import android.car.builtin.os.UserManagerHelper;
-import android.car.test.mocks.AbstractExtendedMockitoTestCase;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import com.android.internal.car.CarServiceHelperInterface;
-import com.android.server.wm.CarLaunchParamsModifierInterface;
-
-import java.util.function.BiConsumer;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-
-/**
- * This class contains unit tests for the {@link CarServiceHelperServiceUpdatableImpl}.
- */
-@RunWith(AndroidJUnit4.class)
-public final class CarServiceHelperServiceUpdatableImplTest
- extends AbstractExtendedMockitoTestCase {
-
- @Mock
- private Context mMockContext;
- @Mock
- private CarServiceProxy mCarServiceProxy;
- @Mock
- private CarServiceHelperInterface mCarServiceHelperInterface;
- @Mock
- private CarLaunchParamsModifierInterface mCarLaunchParamsModifierInterface;
- @Mock
- private ICar mICarBinder;
- @Mock
- private IBinder mIBinder;
-
- private CarServiceHelperServiceUpdatableImpl mCarServiceHelperServiceUpdatableImpl;
-
- public CarServiceHelperServiceUpdatableImplTest() {
- super(CarServiceHelperServiceUpdatableImpl.TAG);
- }
-
- @Before
- public void setTestFixtures() {
- mCarServiceHelperServiceUpdatableImpl = new CarServiceHelperServiceUpdatableImpl(
- mMockContext,
- mCarServiceHelperInterface,
- mCarLaunchParamsModifierInterface,
- mCarServiceProxy);
- }
-
- @Test
- public void testCarServiceLaunched() throws Exception {
- mockSystemContext();
- mockBindService();
-
- mCarServiceHelperServiceUpdatableImpl.onStart();
-
- verifyBindService();
- }
-
- @Test
- public void testHandleCarServiceConnection() throws Exception {
- mockICarBinder();
-
- mCarServiceHelperServiceUpdatableImpl.handleCarServiceConnection(mIBinder);
-
- verify(mICarBinder).setSystemServerConnections(any(), any());
- }
-
- @Test
- public void testHandleCarServiceCrash() throws Exception {
- mockICarBinder();
- doThrow(new RemoteException()).when(mICarBinder).setSystemServerConnections(any(), any());
-
- mCarServiceHelperServiceUpdatableImpl.handleCarServiceConnection(mIBinder);
-
- verify(mCarServiceHelperInterface).dumpServiceStacks();
- }
-
- @Test
- public void testOnUserRemoved() throws Exception {
- UserHandle user = UserHandle.of(101);
- mCarServiceHelperServiceUpdatableImpl.onUserRemoved(user);
-
- verify(mCarServiceProxy).onUserRemoved(user);
- }
-
- @Test
- public void testOnFactoryReset() throws Exception {
- BiConsumer<Integer, Bundle> callback = (x, y) -> {};
- mCarServiceHelperServiceUpdatableImpl.onFactoryReset(callback);
-
- verify(mCarServiceProxy).onFactoryReset(any());
- }
-
- @Test
- public void testInitBootUser() throws Exception {
- mCarServiceHelperServiceUpdatableImpl.initBootUser();
-
- verify(mCarServiceProxy).initBootUser();
- }
-
- @Test
- public void testSendUserLifecycleEvent_nullFromUser() throws Exception {
- int eventType = 1;
- UserHandle userFrom = null;
- UserHandle userTo = UserHandle.SYSTEM;
-
- mCarServiceHelperServiceUpdatableImpl.sendUserLifecycleEvent(eventType, userFrom, userTo);
-
- verify(mCarServiceProxy).sendUserLifecycleEvent(eventType, UserManagerHelper.USER_NULL,
- userTo.getIdentifier());
- }
-
- @Test
- public void testSendUserLifecycleEvent() throws Exception {
- int eventType = 1;
- UserHandle userFrom = UserHandle.SYSTEM;
- int userId = 101;
- UserHandle userTo = UserHandle.of(userId);
-
- mCarServiceHelperServiceUpdatableImpl.sendUserLifecycleEvent(eventType, userFrom, userTo);
-
- verify(mCarServiceProxy).sendUserLifecycleEvent(eventType, userFrom.getIdentifier(),
- userTo.getIdentifier());
- }
-
- private void mockICarBinder() {
- when(ICar.Stub.asInterface(mIBinder)).thenReturn(mICarBinder);
- }
-
- private void mockSystemContext() {
- when(mMockContext.createContextAsUser(UserHandle.SYSTEM, /* flags= */ 0))
- .thenReturn(mMockContext);
- }
-
- private void mockBindService() {
- when(mMockContext.bindService(any(), eq(Context.BIND_AUTO_CREATE), any(), any()))
- .thenReturn(true);
- }
-
- private void verifyBindService() throws Exception {
- verify(mMockContext).bindService(
- argThat(intent -> intent.getAction().equals(CAR_SERVICE_INTERFACE)),
- eq(Context.BIND_AUTO_CREATE), any(), any());
- }
-}