Initial implementation of the Auto-Fill Framework classes.

This CL provides the initial, skeleton implementation of the Auto-Fill
Framework classes:

- Defines the system service and app-based
  AIDL (IAutoFillManagerService.aidl and IAutoFillService.aidl respectively).
- Defines the 'adb shell cmd' interface.
- Defines the permission required to access the service.
- Registers the service on SystemServer.
- Adds the code to bind the app-specified service to system_server.
- Defines the service class (AutoFillService) required by providers.
- Implements the initial startSession() method.

This is still a very early, "work-in-progress" change:
- It has many TODOs.
- It does not have unit or CTS tests yet.
- It does not provide a callback method to auto-fill the fields.
- In fact, it has a lot of TODOs.

Despite these adversities, it can be tested by following the steps
below:

1.Create an app with a service extending AutoFillService

2.Implement the onNewSession() method

3.In the manifest:
 - Listen to android.service.autofill.AutoFillService intents.
 - Require the android.permission.BIND_AUTO_FILL permission.

4.Explicitly set the app as an autofill-service by running:
  adb shell settings put secure auto_fill_service MY_APP/.MY_SERVICE

5.Start a session against the top activity:
  adb shell cmd autofill start session

BUG: 31001899
Test: manually built and ran it

Change-Id: I00f4822159b31ddddba8f513e57c4474bc74eb89
diff --git a/Android.mk b/Android.mk
index 6f96803..bd04214 100644
--- a/Android.mk
+++ b/Android.mk
@@ -251,6 +251,8 @@
 	core/java/android/os/storage/IObbActionListener.aidl \
 	core/java/android/security/IKeystoreService.aidl \
 	core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl \
+	core/java/android/service/autofill/IAutoFillManagerService.aidl \
+	core/java/android/service/autofill/IAutoFillService.aidl \
 	core/java/android/service/carrier/ICarrierService.aidl \
 	core/java/android/service/carrier/ICarrierMessagingCallback.aidl \
 	core/java/android/service/carrier/ICarrierMessagingService.aidl \
diff --git a/api/current.txt b/api/current.txt
index f70458b..9a1a4f2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -18,6 +18,7 @@
     field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
     field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
     field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+    field public static final java.lang.String BIND_AUTO_FILL = "android.permission.BIND_AUTO_FILL";
     field public static final deprecated java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
     field public static final java.lang.String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
     field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
@@ -34628,6 +34629,20 @@
 
 }
 
+package android.service.autofill {
+
+  public abstract class AutoFillService extends android.app.Service {
+    ctor public AutoFillService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public void onNewSession(java.lang.String, android.os.Bundle, int, android.app.assist.AssistStructure);
+    method public void onReady();
+    method public void onSessionFinished(java.lang.String);
+    method public void onShutdown();
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
+  }
+
+}
+
 package android.service.carrier {
 
   public class CarrierIdentifier implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index 6622ea5..a41a132 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -28,6 +28,7 @@
     field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
     field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
     field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+    field public static final java.lang.String BIND_AUTO_FILL = "android.permission.BIND_AUTO_FILL";
     field public static final deprecated java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
     field public static final java.lang.String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
     field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
@@ -130,6 +131,7 @@
     field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
     field public static final java.lang.String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS";
     field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
+    field public static final java.lang.String MANAGE_AUTO_FILL = "android.permission.MANAGE_AUTO_FILL";
     field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES";
     field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
     field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
@@ -37396,6 +37398,20 @@
 
 }
 
+package android.service.autofill {
+
+  public abstract class AutoFillService extends android.app.Service {
+    ctor public AutoFillService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public void onNewSession(java.lang.String, android.os.Bundle, int, android.app.assist.AssistStructure);
+    method public void onReady();
+    method public void onSessionFinished(java.lang.String);
+    method public void onShutdown();
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
+  }
+
+}
+
 package android.service.carrier {
 
   public class CarrierIdentifier implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index de57dba..9393e1d 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -18,6 +18,7 @@
     field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
     field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
     field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+    field public static final java.lang.String BIND_AUTO_FILL = "android.permission.BIND_AUTO_FILL";
     field public static final deprecated java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
     field public static final java.lang.String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
     field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
@@ -32764,6 +32765,7 @@
     field public static final java.lang.String ALLOWED_GEOLOCATION_ORIGINS = "allowed_geolocation_origins";
     field public static final deprecated java.lang.String ALLOW_MOCK_LOCATION = "mock_location";
     field public static final java.lang.String ANDROID_ID = "android_id";
+    field public static final java.lang.String AUTO_FILL_SERVICE = "auto_fill_service";
     field public static final deprecated java.lang.String BACKGROUND_DATA = "background_data";
     field public static final deprecated java.lang.String BLUETOOTH_ON = "bluetooth_on";
     field public static final android.net.Uri CONTENT_URI;
@@ -34717,6 +34719,20 @@
 
 }
 
+package android.service.autofill {
+
+  public abstract class AutoFillService extends android.app.Service {
+    ctor public AutoFillService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public void onNewSession(java.lang.String, android.os.Bundle, int, android.app.assist.AssistStructure);
+    method public void onReady();
+    method public void onSessionFinished(java.lang.String);
+    method public void onShutdown();
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
+  }
+
+}
+
 package android.service.carrier {
 
   public class CarrierIdentifier implements android.os.Parcelable {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 322cc7b..3964e0a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3338,6 +3338,14 @@
     public static final String VOICE_INTERACTION_MANAGER_SERVICE = "voiceinteraction";
 
     /**
+     * Official published name of the (internal) auto-fill service.
+     *
+     * @hide
+     * @see #getSystemService
+     */
+    public static final String AUTO_FILL_MANAGER_SERVICE = "autofill";
+
+    /**
      * Use with {@link #getSystemService} to access the
      * {@link com.android.server.voiceinteraction.SoundTriggerService}.
      *
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1b905a0..73eeccd 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4715,6 +4715,13 @@
         public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
 
         /**
+         * The currently selected auto-fill service flattened ComponentName.
+         * @hide
+         */
+        @TestApi
+        public static final String AUTO_FILL_SERVICE = "auto_fill_service";
+
+        /**
          * bluetooth HCI snoop log configuration
          * @hide
          */
diff --git a/core/java/android/service/autofill/AutoFillService.java b/core/java/android/service/autofill/AutoFillService.java
new file mode 100644
index 0000000..14ce009b
--- /dev/null
+++ b/core/java/android/service/autofill/AutoFillService.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2016 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.service.autofill;
+
+import android.annotation.SdkConstant;
+import android.app.Service;
+import android.app.assist.AssistStructure;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+
+import com.android.internal.os.HandlerCaller;
+import com.android.internal.os.SomeArgs;
+
+/**
+ * Top-level service of the current auto-fill service for a given user.
+ */
+// TODO: expand documentation
+public abstract class AutoFillService extends Service {
+
+    private static final String TAG = "AutoFillService";
+    private static final boolean DEBUG = true; // TODO: set to false once stable
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     * To be supported, the service must also require the
+     * {@link android.Manifest.permission#BIND_AUTO_FILL} permission so
+     * that other applications can not abuse it.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
+
+    private static final int MSG_READY = 1;
+    private static final int MSG_NEW_SESSION = 2;
+    private static final int MSG_SESSION_FINISHED = 3;
+    private static final int MSG_SHUTDOWN = 4;
+
+    // TODO: add metadata?
+
+    private final IAutoFillService mInterface = new IAutoFillService.Stub() {
+        @Override
+        public void ready() {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_READY));
+        }
+
+        @Override
+        public void newSession(String token, Bundle data, int flags,
+                AssistStructure structure) {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOOO(MSG_NEW_SESSION,
+                    flags, token, data, structure));
+        }
+
+        @Override
+        public void finishSession(String token) {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_SESSION_FINISHED, token));
+        }
+
+        @Override
+        public void shutdown() {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_SHUTDOWN));
+        }
+    };
+
+    private final HandlerCaller.Callback mHandlerCallback = new HandlerCaller.Callback() {
+
+        @Override
+        public void executeMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_READY: {
+                    onReady();
+                    break;
+                } case MSG_NEW_SESSION: {
+                    final SomeArgs args = (SomeArgs) msg.obj;
+                    final int flags = args.argi1;
+                    final String token = (String) args.arg1;
+                    final Bundle data = (Bundle) args.arg2;
+                    final AssistStructure assistStructure = (AssistStructure) args.arg3;
+                    onNewSession(token, data, flags, assistStructure);
+                    break;
+                } case MSG_SESSION_FINISHED: {
+                    final String token = (String) msg.obj;
+                    onSessionFinished(token);
+                    break;
+                } case MSG_SHUTDOWN: {
+                    onShutdown();
+                    break;
+                } default: {
+                    Log.w(TAG, "MyCallbacks received invalid message type: " + msg);
+                }
+            }
+        }
+    };
+
+    private HandlerCaller mHandlerCaller;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        mHandlerCaller = new HandlerCaller(null, Looper.getMainLooper(), mHandlerCallback, true);
+    }
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        if (SERVICE_INTERFACE.equals(intent.getAction())) {
+            return mInterface.asBinder();
+        }
+        return null;
+    }
+
+    /**
+     * Called during service initialization to tell you when the system is ready
+     * to receive interaction from it.
+     *
+     * <p>You should generally do initialization here rather than in {@link #onCreate}.
+     *
+     * <p>Sub-classes should call it first, since it sets the reference to the sytem-server service.
+     */
+    // TODO: rename to onConnected() / add onDisconnected()?
+    public void onReady() {
+        if (DEBUG) Log.d(TAG, "onReady()");
+    }
+
+    /**
+     * Called to receive data from the application that the user was requested auto-fill for.
+     *
+     * @param token unique token identifying the auto-fill session, it should be used when providing
+     * the auto-filled fields.
+     * @param data Arbitrary data supplied by the app through
+     * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}.
+     * May be {@code null} if data has been disabled by the user or device policy.
+     * @param startFlags currently always 0.
+     * @param structure If available, the structure definition of all windows currently
+     * displayed by the app.  May be {@code null} if auto-fill data has been disabled by the user
+     * or device policy; will be an empty stub if the application has disabled auto-fill
+     * by marking its window as secure.
+     */
+    @SuppressWarnings("unused")
+    // TODO: take the factory approach where this method return a session, and move the callback
+    // methods (like autofill()) to the session.
+    public void onNewSession(String token, Bundle data, int startFlags, AssistStructure structure) {
+        if (DEBUG) Log.d(TAG, "onNewSession(): token=" + token);
+    }
+
+    /**
+     * Called when an auto-fill session is finished.
+     */
+    @SuppressWarnings("unused")
+    public void onSessionFinished(String token) {
+        if (DEBUG) Log.d(TAG, "onSessionFinished(): token=" + token);
+    }
+
+    /**
+     * Called during service de-initialization to tell you when the system is shutting the
+     * service down.
+     *
+     * <p> At this point this service may no longer be an active {@link AutoFillService}.
+     */
+    public void onShutdown() {
+        if (DEBUG) Log.d(TAG, "onShutdown()");
+    }
+}
diff --git a/core/java/android/service/autofill/AutoFillServiceInfo.java b/core/java/android/service/autofill/AutoFillServiceInfo.java
new file mode 100644
index 0000000..fe21615
--- /dev/null
+++ b/core/java/android/service/autofill/AutoFillServiceInfo.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2016 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.service.autofill;
+
+import android.Manifest;
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.os.RemoteException;
+
+/** @hide */
+public final class AutoFillServiceInfo {
+
+    private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, int userHandle)
+            throws PackageManager.NameNotFoundException {
+        try {
+            final ServiceInfo si =
+                    AppGlobals.getPackageManager().getServiceInfo(comp, 0, userHandle);
+            if (si != null) {
+                return si;
+            }
+        } catch (RemoteException e) {
+        }
+        throw new PackageManager.NameNotFoundException(comp.toString());
+    }
+
+    private String mParseError;
+
+    private ServiceInfo mServiceInfo;
+
+    private  AutoFillServiceInfo(ServiceInfo si) {
+        if (si == null) {
+            mParseError = "Service not available";
+            return;
+        }
+        if (!Manifest.permission.BIND_AUTO_FILL.equals(si.permission)) {
+            mParseError = "Service does not require permission "
+                    + Manifest.permission.BIND_AUTO_FILL;
+            return;
+        }
+
+        mServiceInfo = si;
+    }
+
+    public AutoFillServiceInfo(ComponentName comp, int userHandle)
+            throws PackageManager.NameNotFoundException {
+        this(getServiceInfoOrThrow(comp, userHandle));
+    }
+
+    public String getParseError() {
+        return mParseError;
+    }
+
+    public ServiceInfo getServiceInfo() {
+        return mServiceInfo;
+    }
+}
diff --git a/core/java/android/service/autofill/IAutoFillManagerService.aidl b/core/java/android/service/autofill/IAutoFillManagerService.aidl
new file mode 100644
index 0000000..2c06234
--- /dev/null
+++ b/core/java/android/service/autofill/IAutoFillManagerService.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 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.service.autofill;
+
+import android.os.Bundle;
+
+/**
+ * Intermediator between apps being auto-filled and auto-fill service implementations.
+ *
+ * {@hide}
+ */
+interface IAutoFillManagerService {
+
+    /**
+     * Starts an auto-fill session for the top activities for a given user.
+     *
+     * It's used to start a new session from system affordances.
+     *
+     * @param userId user handle.
+     * @param args the bundle to pass as arguments to the voice interaction session.
+     * @param flags flags indicating optional session behavior.
+     * @param activityToken optional token of activity that needs to be on top.
+     *
+     * @return session token, or null if session was not created (for example, if the activity's
+     *         user does not have an auto-fill service associated with).
+     */
+     // TODO: pass callback providing an onAutoFill() method
+    String startSession(int userId, in Bundle args, int flags, IBinder activityToken);
+
+    /**
+     * Finishes an auto-fill session.
+     *
+     * @param userId user handle.
+     * @param token session token.
+     *
+     * @return true if session existed and was finished.
+     */
+    boolean finishSession(int userId, String token);
+
+}
diff --git a/core/java/android/service/autofill/IAutoFillService.aidl b/core/java/android/service/autofill/IAutoFillService.aidl
new file mode 100644
index 0000000..73d8d5d
--- /dev/null
+++ b/core/java/android/service/autofill/IAutoFillService.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 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.service.autofill;
+
+import android.os.Bundle;
+import android.app.assist.AssistStructure;
+
+/**
+ * @hide
+ */
+oneway interface IAutoFillService {
+    void ready();
+    void newSession(String token, in Bundle data, int flags, in AssistStructure structure);
+    void finishSession(String token);
+    void shutdown();
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4eebea6..3ec9de3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2323,6 +2323,13 @@
     <permission android:name="android.permission.BIND_VOICE_INTERACTION"
         android:protectionLevel="signature" />
 
+    <!-- Must be required by a {@link android.service.autofill.AutoFillService},
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature
+    -->
+    <permission android:name="android.permission.BIND_AUTO_FILL"
+        android:protectionLevel="signature" />
+
     <!-- Must be required by hotword enrollment application,
          to ensure that only the system can interact with it.
          @hide <p>Not for use by third-party applications.</p> -->
@@ -3118,6 +3125,11 @@
     <permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"
                 android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows an application to manage auto-fill sessions.
+         @hide  <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.MANAGE_AUTO_FILL"
+        android:protectionLevel="signature" />
+
     <application android:process="system"
                  android:persistent="true"
                  android:hasCode="false"
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 227d0e9..d4c7c7a 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -112,6 +112,7 @@
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
     <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
+    <uses-permission android:name="android.permission.MANAGE_AUTO_FILL" />
     <!-- Permission needed to rename bugreport notifications (so they're not shown as Shell) -->
     <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
     <!-- Permission needed to hold a wakelock in dumpstate.cpp (drop_root_user()) -->
diff --git a/services/Android.mk b/services/Android.mk
index 3385bed..2911983 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -22,6 +22,7 @@
     core \
     accessibility \
     appwidget \
+    autofill \
     backup \
     devicepolicy \
     midi \
diff --git a/services/autofill/Android.mk b/services/autofill/Android.mk
new file mode 100644
index 0000000..a1f19fd
--- /dev/null
+++ b/services/autofill/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.autofill
+
+LOCAL_SRC_FILES += \
+      $(call all-java-files-under,java)
+
+LOCAL_JAVA_LIBRARIES := services.core
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
new file mode 100644
index 0000000..3b41877
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2016 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.autofill;
+
+import static android.Manifest.permission.MANAGE_AUTO_FILL;
+import static android.content.Context.AUTO_FILL_MANAGER_SERVICE;
+
+import android.Manifest;
+import android.app.ActivityManager;
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.autofill.IAutoFillManagerService;
+import android.text.TextUtils;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
+import com.android.server.FgThread;
+import com.android.server.SystemService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Entry point service for auto-fill management.
+ *
+ * <p>This service provides the {@link IAutoFillManagerService} implementation and keeps a list of
+ * {@link AutoFillManagerServiceImpl} per user; the real work is done by
+ * {@link AutoFillManagerServiceImpl} itself.
+ */
+public final class AutoFillManagerService extends SystemService {
+
+    private static final String TAG = "AutoFillManagerService";
+    private static final boolean DEBUG = true; // TODO: change to false once stable
+
+    private final AutoFillManagerServiceStub mServiceStub;
+    private final Context mContext;
+    private final ContentResolver mResolver;
+
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private boolean mSafeMode;
+
+    /**
+     * Map of {@link AutoFillManagerServiceImpl} per user id.
+     * <p>
+     * It has to be mapped by user id because the same current user could have simultaneous sessions
+     * associated to different user profiles (for example, in a multi-window environment).
+     * <p>
+     * This map is filled on demand in the following scenarios:
+     * <ol>
+     *   <li>On start, it sets the value for the default user.
+     *   <li>When an auto-fill service app is removed, its entries are removed.
+     *   <li>When the current user changes.
+     *   <li>When the {@link android.provider.Settings.Secure#AUTO_FILL_SERVICE} changes.
+     * </ol>
+     */
+    // TODO: make sure all cases listed above are handled
+    // TODO: should entries be removed when there is no section and have not be used for a while?
+    @GuardedBy("mLock")
+    private SparseArray<AutoFillManagerServiceImpl> mImplByUser = new SparseArray<>();
+
+    // TODO: should disable it on low-memory devices? if not, this attribute should be removed...
+    private final boolean mEnableService = true;
+
+    public AutoFillManagerService(Context context) {
+        super(context);
+
+        mContext = context;
+        mResolver = context.getContentResolver();
+        mServiceStub = new AutoFillManagerServiceStub();
+    }
+
+    @Override
+    public void onStart() {
+        if (DEBUG)
+            Slog.d(TAG, "onStart(): binding as " + AUTO_FILL_MANAGER_SERVICE);
+        publishBinderService(AUTO_FILL_MANAGER_SERVICE, mServiceStub);
+    }
+
+    // TODO: refactor so it's bound on demand, in which case it can use isSafeMode() from PM.
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+            systemRunning(isSafeMode());
+        }
+    }
+
+    // TODO: refactor so it's bound on demand, in which case it can use isSafeMode() from PM.
+    @Override
+    public void onStartUser(int userHandle) {
+        if (DEBUG) Slog.d(TAG, "onStartUser(): userHandle=" + userHandle);
+
+        updateImplementationIfNeeded(userHandle, false);
+    }
+
+    @Override
+    public void onUnlockUser(int userHandle) {
+        if (DEBUG) Slog.d(TAG, "onUnlockUser(): userHandle=" + userHandle);
+
+        updateImplementationIfNeeded(userHandle, false);
+    }
+
+    @Override
+    public void onSwitchUser(int userHandle) {
+        if (DEBUG) Slog.d(TAG, "onSwitchUser(): userHandle=" + userHandle);
+
+        updateImplementationIfNeeded(userHandle, false);
+    }
+
+    private void systemRunning(boolean safeMode) {
+        if (DEBUG) Slog.d(TAG, "systemRunning(): safeMode=" + safeMode);
+
+        // TODO: register a PackageMonitor
+        new SettingsObserver(BackgroundThread.getHandler());
+
+        synchronized (mLock) {
+            mSafeMode = safeMode;
+            updateImplementationIfNeededLocked(ActivityManager.getCurrentUser(), false);
+        }
+    }
+
+    private void updateImplementationIfNeeded(int user, boolean force) {
+        synchronized (mLock) {
+            updateImplementationIfNeededLocked(user, force);
+        }
+    }
+
+    private void updateImplementationIfNeededLocked(int user, boolean force) {
+        if (DEBUG)
+            Slog.d(TAG, "updateImplementationIfNeededLocked(" + user + ", " + force + ")");
+
+        if (mSafeMode) {
+            if (DEBUG) Slog.d(TAG, "skipping on safe mode");
+            return;
+        }
+
+        final String curService = Settings.Secure.getStringForUser(
+                mResolver, Settings.Secure.AUTO_FILL_SERVICE, user);
+        if (DEBUG)
+            Slog.d(TAG, "Current service settings for user " + user + ": " + curService);
+        ComponentName serviceComponent = null;
+        ServiceInfo serviceInfo = null;
+        if (!TextUtils.isEmpty(curService)) {
+            try {
+                serviceComponent = ComponentName.unflattenFromString(curService);
+                serviceInfo =
+                        AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 0, user);
+            } catch (RuntimeException | RemoteException e) {
+                Slog.wtf(TAG, "Bad auto-fill service name " + curService, e);
+                serviceComponent = null;
+                serviceInfo = null;
+            }
+        }
+
+        final AutoFillManagerServiceImpl impl = mImplByUser.get(user);
+        if (DEBUG) Slog.d(TAG, "Current impl: " + impl + " component: " + serviceComponent
+                + " info: " + serviceInfo);
+
+        if (force || impl == null || !impl.mComponent.equals(serviceComponent)) {
+            if (impl != null) {
+                impl.shutdownLocked();
+            }
+            if (serviceInfo != null) {
+                final AutoFillManagerServiceImpl newImpl = new AutoFillManagerServiceImpl(mContext,
+                        mLock, mServiceStub, FgThread.getHandler(), user, serviceComponent);
+                if (DEBUG) Slog.d(TAG, "Setting impl for user " + user + " as: " + newImpl);
+                mImplByUser.put(user, newImpl);
+                newImpl.startLocked();
+            } else {
+                if (DEBUG) Slog.d(TAG, "Removing impl for user " + user + ": " + impl);
+                mImplByUser.remove(user);
+            }
+        }
+    }
+
+    // TODO: might need to return null instead of throw exception
+    private AutoFillManagerServiceImpl getImplOrThrowLocked(int userId) {
+        final AutoFillManagerServiceImpl impl = mImplByUser.get(userId);
+        if (impl == null) {
+            throw new IllegalStateException("no auto-fill service for user " + userId);
+        }
+        return impl;
+    }
+
+    final class AutoFillManagerServiceStub extends IAutoFillManagerService.Stub {
+
+        @Override
+        public String startSession(int userId, Bundle args, int flags, IBinder activityToken) {
+            mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
+            synchronized (mLock) {
+                return getImplOrThrowLocked(userId).startSession(args, flags, activityToken);
+            }
+        }
+
+        @Override
+        public boolean finishSession(int userId, String token) {
+            mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
+            synchronized (mLock) {
+                return getImplOrThrowLocked(userId).finishSessionLocked(token);
+            }
+        }
+
+        @Override
+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (mContext.checkCallingPermission(
+                    Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
+                pw.println("Permission Denial: can't dump autofill from from pid="
+                        + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid());
+                return;
+            }
+            if (args.length > 0) {
+                if ("--sessions".equals(args[0])) {
+                    dumpSessions(pw);
+                    return;
+                }
+            }
+            synchronized (mLock) {
+                pw.print("mEnableService: "); pw.println(mEnableService);
+                pw.print("mSafeMode: "); pw.println(mSafeMode);
+                final int size = mImplByUser.size();
+                pw.print("Number of implementations: ");
+                if (size == 0) {
+                    pw.println("none");
+                } else {
+                    pw.println(size);
+                    for (int i = 0; i < size; i++) {
+                        pw.print("\nImplementation at index "); pw.println(i);
+                        final AutoFillManagerServiceImpl impl = mImplByUser.valueAt(i);
+                        impl.dumpLocked("  ", pw);
+                    }
+                }
+            }
+        }
+
+        private void dumpSessions(PrintWriter pw) {
+            boolean foundOne = false;
+            synchronized (mLock) {
+                final int size = mImplByUser.size();
+                for (int i = 0; i < size; i++) {
+                    final AutoFillManagerServiceImpl impl = mImplByUser.valueAt(i);
+                    foundOne |= impl.dumpSessionsLocked("", pw);
+                }
+            }
+            if (!foundOne) {
+                pw.println("No active sessions");
+            }
+        }
+
+        @Override
+        public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+                String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
+            (new AutoFillManagerServiceShellCommand(this)).exec(
+                    this, in, out, err, args, callback, resultReceiver);
+        }
+
+    }
+
+    private final class SettingsObserver extends ContentObserver {
+        SettingsObserver(Handler handler) {
+            super(handler);
+            ContentResolver resolver = mContext.getContentResolver();
+            resolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.AUTO_FILL_SERVICE), false, this,
+                    UserHandle.USER_ALL);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri, int userId) {
+            synchronized (mLock) {
+                updateImplementationIfNeededLocked(userId, false);
+            }
+        }
+    }
+}
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
new file mode 100644
index 0000000..c780062
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2016 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.autofill;
+
+import android.app.ActivityManagerInternal;
+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.PackageManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.autofill.AutoFillService;
+import android.service.autofill.AutoFillServiceInfo;
+import android.service.autofill.IAutoFillService;
+import android.util.Log;
+import android.util.PrintWriterPrinter;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
+import com.android.server.autofill.AutoFillManagerService.AutoFillManagerServiceStub;
+
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * Bridge between the {@code system_server}'s {@link AutoFillManagerService} and the
+ * app's {@link IAutoFillService} implementation.
+ *
+ * <p>It keeps a list of auto-fill sessions for a specifc user.
+ */
+final class AutoFillManagerServiceImpl {
+
+    private static final String TAG = "AutoFillManagerServiceImpl";
+    private static final boolean DEBUG = true; // TODO: change to false once stable
+
+    final int mUser;
+    final ComponentName mComponent;
+
+    private final Context mContext;
+    private final Object mLock;
+    private final AutoFillManagerServiceStub mServiceStub;
+    private final AutoFillServiceInfo mInfo;
+
+    // Map of sessions keyed by session tokens.
+    @GuardedBy("mLock")
+    private Map<String, AutoFillSession> mSessions = new HashMap<>();
+
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+                final String reason = intent.getStringExtra("reason");
+                if (DEBUG) Slog.d(TAG, "close system dialogs: " + reason);
+                // TODO: close any pending UI like account selection
+            }
+        }
+    };
+
+    private final ServiceConnection mConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            if (DEBUG) Log.d(TAG, "onServiceConnected():" + name);
+            synchronized (mLock) {
+                mService = IAutoFillService.Stub.asInterface(service);
+                try {
+                    mService.ready();
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Exception on service.ready(): " + e);
+                }
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            if (DEBUG) Log.d(TAG, name + " disconnected");
+            mService = null;
+        }
+    };
+
+    @GuardedBy("mLock")
+    private IAutoFillService mService;
+    private boolean mBound;
+    private boolean mValid;
+
+    AutoFillManagerServiceImpl(Context context, Object lock, AutoFillManagerServiceStub stub,
+            Handler handler, int user, ComponentName component) {
+        mContext = context;
+        mLock = lock;
+        mServiceStub = stub;
+        mUser = user;
+        mComponent = component;
+
+        AutoFillServiceInfo info;
+        try {
+            info = new AutoFillServiceInfo(component, mUser);
+        } catch (PackageManager.NameNotFoundException e) {
+            Slog.w(TAG, "Auto-fill service not found: " + component, e);
+            mInfo = null;
+            mValid = false;
+            return;
+        }
+        mInfo = info;
+        if (mInfo.getParseError() != null) {
+            Slog.w(TAG, "Bad auto-fill service: " + mInfo.getParseError());
+            mValid = false;
+            return;
+        }
+
+        mValid = true;
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        mContext.registerReceiver(mBroadcastReceiver, filter, null, handler);
+    }
+
+    void startLocked() {
+        if (DEBUG) Slog.d(TAG, "startLocked()");
+
+        final Intent intent = new Intent(AutoFillService.SERVICE_INTERFACE);
+        intent.setComponent(mComponent);
+        mBound = mContext.bindServiceAsUser(intent, mConnection,
+                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, new UserHandle(mUser));
+        if (!mBound) {
+            Slog.w(TAG, "Failed binding to auto-fill service " + mComponent);
+            return;
+        }
+        if (DEBUG) Slog.d(TAG, "Bound to " + mComponent);
+    }
+
+    String startSession(Bundle args, int flags, IBinder activityToken) {
+
+        if (!mBound) {
+            // TODO: should it bind on demand? Or perhaps always run when on on low-memory?
+            Slog.w(TAG, "startSession() failed because it's not bound to service");
+            return null;
+        }
+
+        // TODO: session should have activity ids, so same session is reused when called again
+        // for the same activity.
+
+        // TODO: activityToken should probably not be null, but we need to wait until the UI is
+        // triggering the call (for now it's trough 'adb shell cmd autofill start session'
+        if (activityToken == null) {
+            // Let's get top activities from all visible stacks.
+
+            // TODO: overload getTopVisibleActivities() to take userId, otherwise it could return
+            // activities for different users when a work profile app is displayed in another
+            // window (in a multi-window environment).
+            final List<IBinder> topActivities = LocalServices
+                    .getService(ActivityManagerInternal.class).getTopVisibleActivities();
+            if (DEBUG)
+                Slog.d(TAG, "Top activities (" + topActivities.size() + "): " + topActivities);
+            if (topActivities.isEmpty()) {
+                Slog.w(TAG, "Could not get top activity");
+                return null;
+            }
+            activityToken = topActivities.get(0);
+        }
+
+        synchronized (mLock) {
+            return startSessionLocked(args, flags, activityToken);
+        }
+    }
+
+    // TODO: remove args and flags if not needed?
+    private String startSessionLocked(Bundle args, int flags, IBinder activityToken) {
+
+        final String sessionToken = UUID.randomUUID().toString();
+
+        if (DEBUG) Slog.d(TAG, "Starting session for user " + mUser
+                + ": sessionToken=" + sessionToken + ", activityToken=" + activityToken);
+
+        final AutoFillSession session =
+                new AutoFillSession(mService, mLock, sessionToken, activityToken);
+        session.startLocked();
+        mSessions.put(sessionToken, session);
+
+        return sessionToken;
+    }
+
+    // TODO: need a way to automatically call it when the activity is destroyed.
+    boolean finishSessionLocked(String token) {
+        if (DEBUG) Slog.d(TAG, "Removing session " + token + " for user " + mUser);
+        final AutoFillSession session = mSessions.remove(token);
+        if (session != null) {
+            session.finishLocked();
+        }
+        return session != null;
+    }
+
+    void shutdownLocked() {
+        if (DEBUG) Slog.d(TAG, "shutdownLocked()");
+
+        try {
+            if (mService != null) {
+                mService.shutdown();
+            }
+        } catch (RemoteException e) {
+            Slog.w(TAG, "RemoteException in shutdown", e);
+        }
+
+        if (mBound) {
+            mContext.unbindService(mConnection);
+            mBound = false;
+        }
+        if (mValid) {
+            mContext.unregisterReceiver(mBroadcastReceiver);
+        }
+    }
+
+    void dumpLocked(String prefix, PrintWriter pw) {
+        if (!mValid) {
+            pw.print("  NOT VALID: ");
+            if (mInfo == null) {
+                pw.println("no info");
+            } else {
+                pw.println(mInfo.getParseError());
+            }
+            return;
+        }
+
+        pw.print(prefix); pw.print("mUser="); pw.println(mUser);
+        pw.print(prefix); pw.print("mComponent="); pw.println(mComponent.flattenToShortString());
+        pw.print(prefix); pw.print("mBound="); pw.println(mBound);
+        pw.print(prefix); pw.print("mService="); pw.println(mService);
+
+        if (DEBUG) {
+            // ServiceInfo dump is too noisy and redundant (it can be obtained through other dumps)
+            pw.print(prefix); pw.println("Service info:");
+            mInfo.getServiceInfo().dump(new PrintWriterPrinter(pw), prefix + prefix);
+        }
+
+        if (!dumpSessionsLocked(prefix, pw)) {
+            pw.print(prefix); pw.print("No active sessions for user "); pw.println(mUser);
+        }
+    }
+
+    boolean dumpSessionsLocked(String prefix, PrintWriter pw) {
+        if (mSessions.isEmpty()) {
+            return false;
+        }
+
+        pw.print(mSessions.size());pw.println(" active sessions:");
+        final String sessionPrefix = prefix + prefix;
+        for (AutoFillSession session : mSessions.values()) {
+            pw.println();
+            session.dumpLocked(sessionPrefix, pw);
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "[AutoFillManagerServiceImpl: user=" + mUser
+                + ", component=" + mComponent.flattenToShortString() + "]";
+    }
+}
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
new file mode 100644
index 0000000..4e08ed6
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceShellCommand.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2016 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.autofill;
+
+import android.app.ActivityManager;
+import android.os.RemoteException;
+import android.os.ShellCommand;
+import android.os.UserHandle;
+import android.service.autofill.IAutoFillManagerService;
+
+import java.io.PrintWriter;
+
+public final class AutoFillManagerServiceShellCommand extends ShellCommand {
+
+    private final IAutoFillManagerService.Stub mService;
+
+    public AutoFillManagerServiceShellCommand(IAutoFillManagerService.Stub service) {
+        mService = service;
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
+        }
+        final PrintWriter pw = getOutPrintWriter();
+        try {
+            switch (cmd) {
+                case "start":
+                    return runStart(pw);
+                case "finish":
+                    return runFinish(pw);
+                default:
+                    return handleDefaultCommands(cmd);
+            }
+        } catch (RemoteException e) {
+            pw.println("error: " + e);
+        }
+        return -1;
+    }
+
+    @Override
+    public void onHelp() {
+        try (final PrintWriter pw = getOutPrintWriter();) {
+            pw.println("AutoFill Service (autofill) commands:");
+            pw.println("  help");
+            pw.println("    Prints this help text.");
+            pw.println("");
+            pw.println("  start session [--user USER_ID]");
+            pw.println("    Starts an auto-fill session. "
+                    + "Prints 'token:SESSION_TOKEN if successful, or error message");
+            pw.println("");
+            pw.println("  finish session <TOKEN> [--user USER_ID]");
+            pw.println("    Finishes a session with the given TOKEN. "
+                    + "Prints empty string if successful, or error message.");
+            pw.println("");
+        }
+    }
+
+    private int runStart(PrintWriter pw) throws RemoteException {
+        final String type = getNextArg();
+        if (type == null) {
+            pw.println("Error: didn't specify type of data to start");
+            return -1;
+        }
+        switch (type) {
+            case "session":
+                return startAutoFillSession(pw);
+        }
+        pw.println("Error: unknown start type '" + type + "'");
+        return -1;
+    }
+
+    private int runFinish(PrintWriter pw) throws RemoteException {
+        final String type = getNextArg();
+        if (type == null) {
+            pw.println("Error: didn't specify type of data to finish");
+            return -1;
+        }
+        switch (type) {
+            case "session":
+                return finishAutoFillSession(pw);
+        }
+        pw.println("Error: unknown finish type '" + type + "'");
+        return -1;
+    }
+
+    private int startAutoFillSession(PrintWriter pw) throws RemoteException {
+        final int userId = getUserIdFromArgs();
+        final String token = mService.startSession(userId, null, 0, null);
+        pw.print("token:"); pw.println(token);
+        return 0;
+    }
+
+    private int finishAutoFillSession(PrintWriter pw) throws RemoteException {
+        final String token = getNextArgRequired();
+        final int userId = getUserIdFromArgs();
+
+        boolean finished = mService.finishSession(userId, token);
+        if (!finished) {
+            pw.println("No such session");
+            return 1;
+        }
+        return 0;
+    }
+
+    private int getUserIdFromArgs() {
+        if ("--user".equals(getNextArg())) {
+            return UserHandle.parseUserArg(getNextArgRequired());
+        }
+        return ActivityManager.getCurrentUser();
+    }
+}
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillSession.java b/services/autofill/java/com/android/server/autofill/AutoFillSession.java
new file mode 100644
index 0000000..44637c3
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/AutoFillSession.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2016 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.autofill;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.app.assist.AssistStructure;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.service.autofill.AutoFillService;
+import android.service.autofill.IAutoFillService;
+import android.service.voice.VoiceInteractionSession;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.IResultReceiver;
+
+import java.io.PrintWriter;
+
+/**
+ * An auto-fill session between the system's {@link AutoFillManagerServiceImpl} and the provider's
+ * {@link AutoFillService} implementation.
+ */
+final class AutoFillSession {
+
+    private static final String TAG = "AutoFillSession";
+
+    private static final boolean FOCUSED = true;
+    private static final boolean NEW_SESSION_ID = true;
+
+    private final IAutoFillService mService;
+    private final String mSessionToken;
+    private final IBinder mActivityToken;
+    private final Object mLock;
+    private final IActivityManager mAm;
+
+    private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
+        @Override
+        public void send(int resultCode, Bundle resultData) throws RemoteException {
+            synchronized (mLock) {
+                mPendingResponse = false;
+                mAssistResponse = resultData;
+                deliverSessionDataLocked();
+            }
+        }
+    };
+
+    // Assist data is filled asynchronously.
+    @GuardedBy("mLock")
+    private Bundle mAssistResponse;
+    @GuardedBy("mLock")
+    private boolean mPendingResponse;
+
+    AutoFillSession(IAutoFillService service, Object lock, String sessionToken,
+            IBinder activityToken) {
+        mService = service;
+        mSessionToken = sessionToken;
+        mActivityToken = activityToken;
+        mLock = lock;
+        mAm = ActivityManagerNative.getDefault();
+    }
+
+    void startLocked() {
+        /*
+         * TODO: apply security checks below:
+         * - checks if disabled by secure settings / device policy
+         * - log operation using noteOp()
+         * - check flags
+         * - display disclosure if needed
+         */
+        mAssistResponse = null;
+        mPendingResponse = true;
+        try {
+            // TODO: add MetricsLogger call
+            if (!mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL,
+                    mAssistReceiver, (Bundle) null, mActivityToken, FOCUSED, NEW_SESSION_ID)) {
+                mPendingResponse = false;
+                Slog.w(TAG, "requestAssistContextExtras() rejected");
+            }
+        } catch (RemoteException e) {
+            // Should happen, it's a local call.
+        }
+    }
+
+    void finishLocked() {
+        try {
+            mService.finishSession(mSessionToken);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "auto-fill service failed to finish session " + mSessionToken, e);
+        }
+    }
+
+    private void deliverSessionDataLocked() {
+        if (mAssistResponse == null) {
+            Slog.w(TAG, "No assist data for session " + mSessionToken);
+            return;
+        }
+
+        final Bundle assistData = mAssistResponse.getBundle(VoiceInteractionSession.KEY_DATA);
+        final AssistStructure structure =
+                mAssistResponse.getParcelable(VoiceInteractionSession.KEY_STRUCTURE);
+        try {
+            mService.newSession(mSessionToken, assistData, 0, structure);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "auto-fill service failed to start session " + mSessionToken, e);
+        } finally {
+            mPendingResponse = false;
+            // We could set mAssistResponse to null here, but we don't so it's shown on dump()
+        }
+    }
+
+    void dumpLocked(String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.print("mSessionToken="); pw.println(mSessionToken);
+        pw.print(prefix); pw.print("mActivityToken="); pw.println(mActivityToken);
+        pw.print(prefix); pw.print("mPendingResponse="); pw.println(mPendingResponse);
+        pw.print(prefix); pw.print("mAssistResponse="); pw.println(mAssistResponse);
+    }
+
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index cc96f565..211e3b8 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -184,6 +184,8 @@
             "com.android.server.content.ContentService$Lifecycle";
     private static final String WALLPAPER_SERVICE_CLASS =
             "com.android.server.wallpaper.WallpaperManagerService$Lifecycle";
+    private static final String AUTO_FILL_MANAGER_SERVICE_CLASS =
+            "com.android.server.autofill.AutoFillManagerService";
 
     private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
 
@@ -1362,6 +1364,10 @@
         mSystemServiceManager.startService(RetailDemoModeService.class);
         traceEnd();
 
+        traceBeginAndSlog("StartAutoFillService");
+        mSystemServiceManager.startService(AUTO_FILL_MANAGER_SERVICE_CLASS);
+        traceEnd();
+
         // It is now time to start up the app processes...
 
         traceBeginAndSlog("MakeVibratorServiceReady");