aboutsummaryrefslogtreecommitdiff
path: root/experimental
diff options
context:
space:
mode:
authorKeun young Park <keunyoung@google.com>2019-11-15 18:10:47 -0800
committerKeun young Park <keunyoung@google.com>2019-12-02 11:56:02 -0800
commit9a91efbd045df94b6641c6f5f4573e0741cf92c0 (patch)
tree0ead41769d5b59b8f97f4e0d72d624ea6de2445a /experimental
parent565350c61d6d776f22fa56bdd7c95e595f38b1d6 (diff)
downloadCar-9a91efbd045df94b6641c6f5f4573e0741cf92c0.tar.gz
add feature support
- Add optional and experimental feature infra. - Feature is defined as a string name. All Car.*SERVICE used for Car*Manager are features. Additional non-API features are defined in CarFeatures but each API can define its own feature under its own name space. - There can be subfeature with the format of "main_feature_name/sub_feature_name". - Feature can be enabed / disabled using Car.[enable|disable]Feature() call but it will only take effect upon reboot. - Added shell command to test enabling / disabling feature. - Added experimental feature infra under separate package and static API. Experimental feature is for development purpose and will not be included in user build. - Removed old feature related code which are not used anywhere. - Kitchen sink test requires enabling the feature to work: $adb root; adb shell dumpsys car_service enable-feature android.car.experimental.test_demo_experimental_feature_service; adb reboot Bug: 144504820 Test: shell command, run added apitest: android.car.apitest.CarFeatureTest, run ExperimentalFeature in kitchensink - Test through command line $ adb root; adb shell cmd car_service disable-feature com.android.car.user.CarUserNoticeService; adb reboot // user notice service should not show up $ adb root; adb shell cmd car_service enable-feature com.android.car.user.CarUserNoticeService; adb reboot // user notice service should show up - Test experimental feature with kitchensink $ adb root; adb shell cmd car_service enable-feature android.car.experimental.test_demo_experimental_feature_service; adb reboot // Launch kitchensink experimental feature page and check the button works. $ adb root; adb shell cmd car_service disable-feature android.car.experimental.test_demo_experimental_feature_service; adb reboot // Launch kitchensink experimental feature page and check the button not working. Change-Id: I75239193f7efab3a156dfe9f64370f4a5fd673a4
Diffstat (limited to 'experimental')
-rw-r--r--experimental/experimental_api/Android.bp37
-rw-r--r--experimental/experimental_api/src/android/car/experimental/CarTestDemoExperimentalFeatureManager.java59
-rw-r--r--experimental/experimental_api/src/android/car/experimental/ExperimentalCar.java34
-rw-r--r--experimental/experimental_api/src/android/car/experimental/ITestDemoExperimental.aidl22
-rw-r--r--experimental/service/Android.bp55
-rw-r--r--experimental/service/AndroidManifest.xml33
-rw-r--r--experimental/service/proguard.flags3
-rw-r--r--experimental/service/res/values/strings.xml18
-rw-r--r--experimental/service/src/com/android/experimentalcar/ExperimentalCarService.java63
-rw-r--r--experimental/service/src/com/android/experimentalcar/IExperimentalCarImpl.java188
-rw-r--r--experimental/service/src/com/android/experimentalcar/TestDemoExperimentalFeatureService.java50
11 files changed, 562 insertions, 0 deletions
diff --git a/experimental/experimental_api/Android.bp b/experimental/experimental_api/Android.bp
new file mode 100644
index 0000000000..24e9b994cf
--- /dev/null
+++ b/experimental/experimental_api/Android.bp
@@ -0,0 +1,37 @@
+// 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.
+//
+//
+
+// Experimental API backed by Experimental Car service.
+
+java_library {
+
+ name: "car-experimental-api-static-lib",
+
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.aidl"
+ ],
+
+ libs: ["android.car"],
+
+ platform_apis: true,
+
+ product_variables: {
+ pdk: {
+ enabled: false,
+ },
+ },
+}
diff --git a/experimental/experimental_api/src/android/car/experimental/CarTestDemoExperimentalFeatureManager.java b/experimental/experimental_api/src/android/car/experimental/CarTestDemoExperimentalFeatureManager.java
new file mode 100644
index 0000000000..517165ed4a
--- /dev/null
+++ b/experimental/experimental_api/src/android/car/experimental/CarTestDemoExperimentalFeatureManager.java
@@ -0,0 +1,59 @@
+/*
+ * 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 android.car.experimental;
+
+import android.car.Car;
+import android.car.CarManagerBase;
+import android.car.annotation.RequiredFeature;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+/**
+ * Demo CarManager API for demonstrating experimental feature / API usage. This will never go to
+ * production.
+ *
+ * @hide
+ */
+@RequiredFeature(ExperimentalCar.TEST_EXPERIMENTAL_FEATURE_SERVICE)
+public final class CarTestDemoExperimentalFeatureManager extends CarManagerBase {
+
+ private final ITestDemoExperimental mService;
+
+ /**
+ * Constructor parameters should remain this way for Car library to construct this.
+ */
+ public CarTestDemoExperimentalFeatureManager(Car car, IBinder service) {
+ super(car);
+ mService = ITestDemoExperimental.Stub.asInterface(service);
+ }
+
+ /**
+ * Send ping msg service. It will replay back with the same message.
+ */
+ public String ping(String msg) {
+ try {
+ return mService.ping(msg);
+ } catch (RemoteException e) {
+ // For experimental API, we just crash client.
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ protected void onCarDisconnected() {
+ // Nothing to do
+ }
+}
diff --git a/experimental/experimental_api/src/android/car/experimental/ExperimentalCar.java b/experimental/experimental_api/src/android/car/experimental/ExperimentalCar.java
new file mode 100644
index 0000000000..e6921a2729
--- /dev/null
+++ b/experimental/experimental_api/src/android/car/experimental/ExperimentalCar.java
@@ -0,0 +1,34 @@
+/*
+ * 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 android.car.experimental;
+
+import android.car.annotation.ExperimentalFeature;
+
+/**
+ * Top level class for experimental Car features
+ * @hide
+ */
+public final class ExperimentalCar {
+ /**
+ * Service for testing experimental feature
+ *
+ * @hide
+ */
+ @ExperimentalFeature
+ public static final String TEST_EXPERIMENTAL_FEATURE_SERVICE =
+ "android.car.experimental.test_demo_experimental_feature_service";
+}
diff --git a/experimental/experimental_api/src/android/car/experimental/ITestDemoExperimental.aidl b/experimental/experimental_api/src/android/car/experimental/ITestDemoExperimental.aidl
new file mode 100644
index 0000000000..b5ce7e1e37
--- /dev/null
+++ b/experimental/experimental_api/src/android/car/experimental/ITestDemoExperimental.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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 android.car.experimental;
+
+/** @hide */
+interface ITestDemoExperimental {
+ String ping(in String msg);
+} \ No newline at end of file
diff --git a/experimental/service/Android.bp b/experimental/service/Android.bp
new file mode 100644
index 0000000000..f2fba99097
--- /dev/null
+++ b/experimental/service/Android.bp
@@ -0,0 +1,55 @@
+// 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.
+//
+//
+
+// Build the Experimental Car service.
+
+
+android_app {
+ name: "ExperimentalCarService",
+
+ srcs: [
+ "src/**/*.java"
+ ],
+
+ resource_dirs: ["res"],
+
+ platform_apis: true,
+
+ // Each update should be signed by OEMs
+ certificate: "platform",
+ privileged: true,
+
+ optimize: {
+ proguard_flags_files: ["proguard.flags"],
+ enabled: false,
+ },
+
+ libs: ["android.car"],
+
+ static_libs: [
+ "car-service-common-util-static-lib",
+ "car-experimental-api-static-lib",
+ ],
+
+ required: ["privapp_whitelist_com.android.experimentalcar"],
+
+ // Disable build in PDK, missing aidl import breaks build
+ product_variables: {
+ pdk: {
+ enabled: false,
+ },
+ },
+}
diff --git a/experimental/service/AndroidManifest.xml b/experimental/service/AndroidManifest.xml
new file mode 100644
index 0000000000..c28f400d67
--- /dev/null
+++ b/experimental/service/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ package="com.android.experimentalcar"
+ coreApp="true"
+ android:sharedUserId="android.uid.system">
+
+ <original-package android:name="com.android.experimentalcar" />
+
+ <application android:label="@string/app_title"
+ android:directBootAware="true"
+ android:allowBackup="false"
+ android:persistent="false">
+ <service android:name=".ExperimentalCarService"
+ android:singleUser="true">
+ </service>
+ </application>
+</manifest>
diff --git a/experimental/service/proguard.flags b/experimental/service/proguard.flags
new file mode 100644
index 0000000000..22cc22df14
--- /dev/null
+++ b/experimental/service/proguard.flags
@@ -0,0 +1,3 @@
+-verbose
+-keep @com.android.internal.annotations.VisibleForTesting class *
+
diff --git a/experimental/service/res/values/strings.xml b/experimental/service/res/values/strings.xml
new file mode 100644
index 0000000000..8e081cd78f
--- /dev/null
+++ b/experimental/service/res/values/strings.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_title" translatable="false">Experimental Car service</string>
+</resources> \ No newline at end of file
diff --git a/experimental/service/src/com/android/experimentalcar/ExperimentalCarService.java b/experimental/service/src/com/android/experimentalcar/ExperimentalCarService.java
new file mode 100644
index 0000000000..bc40af5b93
--- /dev/null
+++ b/experimental/service/src/com/android/experimentalcar/ExperimentalCarService.java
@@ -0,0 +1,63 @@
+/*
+ * 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.experimentalcar;
+
+import android.app.Service;
+import android.car.Car;
+import android.content.Intent;
+import android.os.IBinder;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Top class to keep all experimental features.
+ */
+public class ExperimentalCarService extends Service {
+
+ private Car mCar;
+ private final IExperimentalCarImpl mIExperimentalCarImpl = new IExperimentalCarImpl(this);
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ // This is for crashing this service when car service crashes.
+ mCar = Car.createCar(this);
+ }
+
+ @Override
+ public void onDestroy() {
+ mIExperimentalCarImpl.release();
+ super.onDestroy();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ // keep it alive.
+ return START_STICKY;
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mIExperimentalCarImpl;
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ mIExperimentalCarImpl.dump(fd, writer, args);
+ }
+}
diff --git a/experimental/service/src/com/android/experimentalcar/IExperimentalCarImpl.java b/experimental/service/src/com/android/experimentalcar/IExperimentalCarImpl.java
new file mode 100644
index 0000000000..14c7f38b21
--- /dev/null
+++ b/experimental/service/src/com/android/experimentalcar/IExperimentalCarImpl.java
@@ -0,0 +1,188 @@
+/*
+ * 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.experimentalcar;
+
+import android.annotation.MainThread;
+import android.annotation.Nullable;
+import android.car.IExperimentalCar;
+import android.car.IExperimentalCarHelper;
+import android.car.experimental.CarTestDemoExperimentalFeatureManager;
+import android.car.experimental.ExperimentalCar;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.car.CarServiceBase;
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Implements IExperimentalCar for experimental features.
+ */
+public final class IExperimentalCarImpl extends IExperimentalCar.Stub {
+
+ private static final String TAG = "CAR.EXPIMPL";
+
+ private static final List<String> ALL_AVAILABLE_FEATURES = Arrays.asList(
+ ExperimentalCar.TEST_EXPERIMENTAL_FEATURE_SERVICE
+ );
+
+ private final Context mContext;
+
+ private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private boolean mReleased;
+
+ @GuardedBy("mLock")
+ private IExperimentalCarHelper mHelper;
+
+ @GuardedBy("mLock")
+ private ArrayList<CarServiceBase> mRunningServices = new ArrayList<>();
+
+ public IExperimentalCarImpl(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public void init(IExperimentalCarHelper helper, List<String> enabledFeatures) {
+ // From car service or unit testing only
+ assertCallingFromSystemProcessOrSelf();
+
+ // dispatch to main thread as release is always done in main.
+ mMainThreadHandler.post(() -> {
+ synchronized (mLock) {
+ if (mReleased) {
+ Log.w(TAG, "init binder call after onDestroy, will ignore");
+ return;
+ }
+ }
+ ArrayList<CarServiceBase> services = new ArrayList<>();
+ ArrayList<String> startedFeatures = new ArrayList<>();
+ ArrayList<String> classNames = new ArrayList<>();
+ ArrayList<IBinder> binders = new ArrayList<>();
+
+ // This cannot address inter-dependency. That requires re-ordering this in dependency
+ // order.
+ // That should be done when we find such needs. For now, each feature inside here should
+ // not have inter-dependency as they are all optional.
+ for (String feature : enabledFeatures) {
+ CarServiceBase service = constructServiceForFeature(feature);
+ if (service == null) {
+ Log.e(TAG, "Failed to construct requested feature:" + feature);
+ continue;
+ }
+ service.init();
+ services.add(service);
+ startedFeatures.add(feature);
+ // If it is not IBinder, then it is internal feature.
+ if (service instanceof IBinder) {
+ binders.add((IBinder) service);
+ } else {
+ binders.add(null);
+ }
+ classNames.add(getClassNameForFeature(feature));
+ }
+ try {
+ helper.onInitComplete(ALL_AVAILABLE_FEATURES, startedFeatures, classNames, binders);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Car service crashed?", e);
+ // will be destroyed soon. Just continue and register services for possible cleanup.
+ }
+ synchronized (mLock) {
+ mHelper = helper;
+ mRunningServices.addAll(services);
+ }
+ });
+ }
+
+ // should be called in Service.onDestroy
+ @MainThread
+ void release() {
+ // Copy to handle call release without lock
+ ArrayList<CarServiceBase> services;
+ synchronized (mLock) {
+ if (mReleased) {
+ return;
+ }
+ mReleased = true;
+ services = new ArrayList<>(mRunningServices);
+ mRunningServices.clear();
+ }
+ for (CarServiceBase service : services) {
+ service.release();
+ }
+ }
+
+ /** dump */
+ public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ ArrayList<CarServiceBase> services;
+ synchronized (mLock) {
+ writer.println("mReleased:" + mReleased);
+ writer.println("ALL_AVAILABLE_FEATURES:" + ALL_AVAILABLE_FEATURES);
+ services = new ArrayList<>(mRunningServices);
+ }
+ writer.println(" Number of running services:" + services.size());
+ int i = 0;
+ for (CarServiceBase service : services) {
+ writer.print(i + ":");
+ service.dump(writer);
+ i++;
+ }
+ }
+
+ @Nullable
+ private String getClassNameForFeature(String featureName) {
+ switch (featureName) {
+ case ExperimentalCar.TEST_EXPERIMENTAL_FEATURE_SERVICE:
+ return CarTestDemoExperimentalFeatureManager.class.getName();
+ default:
+ return null;
+ }
+ }
+
+ @Nullable
+ private CarServiceBase constructServiceForFeature(String featureName) {
+ switch (featureName) {
+ case ExperimentalCar.TEST_EXPERIMENTAL_FEATURE_SERVICE:
+ return new TestDemoExperimentalFeatureService();
+ default:
+ return null;
+ }
+ }
+
+ private static void assertCallingFromSystemProcessOrSelf() {
+ int uid = Binder.getCallingUid();
+ int pid = Binder.getCallingPid();
+ if (uid != Process.SYSTEM_UID && pid != Process.myPid()) {
+ throw new SecurityException("Only allowed from system or self, uid:" + uid
+ + " pid:" + pid);
+ }
+ }
+}
diff --git a/experimental/service/src/com/android/experimentalcar/TestDemoExperimentalFeatureService.java b/experimental/service/src/com/android/experimentalcar/TestDemoExperimentalFeatureService.java
new file mode 100644
index 0000000000..1309dd2907
--- /dev/null
+++ b/experimental/service/src/com/android/experimentalcar/TestDemoExperimentalFeatureService.java
@@ -0,0 +1,50 @@
+/*
+ * 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.experimentalcar;
+
+import android.car.experimental.ITestDemoExperimental;
+
+import com.android.car.CarServiceBase;
+
+import java.io.PrintWriter;
+
+/**
+ * Demo service for testing experimental feature.
+ */
+public final class TestDemoExperimentalFeatureService extends ITestDemoExperimental.Stub
+ implements CarServiceBase {
+
+ @Override
+ public void init() {
+ // Nothing to do
+ }
+
+ @Override
+ public void release() {
+ // Nothing to do
+ }
+
+ @Override
+ public void dump(PrintWriter writer) {
+ writer.println("*TestExperimentalFeatureService*");
+ }
+
+ @Override
+ public String ping(String msg) {
+ return msg;
+ }
+}