policy: add policy service functions to start, stop Chrome and continue
login

Add policy service functions to start and stop Chrome and accept options to keep enrollment or defer login. Add policy service function to continue login for Chrome instance which has used defer login option before.

BUG=b:192279295
TEST=tast run -var=router=<Router IP> <DUT IP> wifi.PolicyBasic
with the following CL: https://crrev.com/c/3159812

Change-Id: I9ce8a9ba687df971f82d82fe191edaedfdd5ca41
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/tast-tests/+/3159811
Tested-by: Jintao Lin <jintaolin@chromium.org>
Commit-Queue: Jintao Lin <jintaolin@chromium.org>
Reviewed-by: Shuo-Peng Liao <deanliao@chromium.org>
Reviewed-by: Victor-Gabriel Savu <vsavu@google.com>
diff --git a/src/chromiumos/tast/local/bundles/cros/policy/policy_service.go b/src/chromiumos/tast/local/bundles/cros/policy/policy_service.go
index 44fe995..d2440e1 100644
--- a/src/chromiumos/tast/local/bundles/cros/policy/policy_service.go
+++ b/src/chromiumos/tast/local/bundles/cros/policy/policy_service.go
@@ -218,14 +218,13 @@
 			lastErr = errors.Wrapf(err, "failed to close connection to extension %s", id)
 		}
 	}
+	c.extensionConns = make(map[string]*chrome.Conn)
 
-	if c.fakeDMS == nil {
-		return nil, errors.New("fake DMS server not started")
+	if c.fakeDMS != nil {
+		c.fakeDMS.Stop(ctx)
+		c.fakeDMS = nil
 	}
 
-	c.fakeDMS.Stop(ctx)
-	c.fakeDMS = nil
-
 	if c.fakeDMSRemoval {
 		if err := os.RemoveAll(c.fakeDMSDir); err != nil {
 			testing.ContextLog(ctx, "Failed to remove temporary directory: ", err)
@@ -233,11 +232,13 @@
 		}
 	}
 
-	if err := c.chrome.Close(ctx); err != nil {
-		testing.ContextLog(ctx, "Failed to close chrome: ", err)
-		lastErr = errors.Wrap(err, "failed to close chrome")
+	if c.chrome != nil {
+		if err := c.chrome.Close(ctx); err != nil {
+			testing.ContextLog(ctx, "Failed to close chrome: ", err)
+			lastErr = errors.Wrap(err, "failed to close chrome")
+		}
+		c.chrome = nil
 	}
-	c.chrome = nil
 
 	for _, extDir := range c.extensionDirs {
 		if err := os.RemoveAll(extDir); err != nil {
@@ -249,6 +250,87 @@
 	return &empty.Empty{}, lastErr
 }
 
+func (c *PolicyService) StartChrome(ctx context.Context, req *ppb.StartChromeRequest) (*empty.Empty, error) {
+	testing.ContextLogf(ctx, "Starting Chrome with policy %s", string(req.PolicyJson))
+
+	if c.chrome != nil {
+		return nil, errors.New("Chrome is already started")
+	}
+
+	var opts []chrome.Option
+
+	if req.KeepEnrollment {
+		opts = append(opts, chrome.KeepEnrollment())
+	}
+
+	user := req.Username
+	if user == "" {
+		user = "tast-user@managedchrome.com"
+	}
+	opts = append(opts, chrome.FakeLogin(chrome.Creds{User: user, Pass: "test0000", GAIAID: "gaiaid"}))
+
+	if req.SkipLogin {
+		opts = append(opts, chrome.NoLogin())
+	} else if req.DeferLogin {
+		opts = append(opts, chrome.DeferLogin())
+	} else {
+		opts = append(opts, chrome.CustomLoginTimeout(chrome.LoginTimeout))
+	}
+
+	if c.fakeDMS != nil {
+		opts = append(opts, chrome.DMSPolicy(c.fakeDMS.URL))
+		if err := c.fakeDMS.WritePolicyBlobRaw(req.PolicyJson); err != nil {
+			return nil, errors.Wrap(err, "failed to write policy blob")
+		}
+	}
+	opts = append(opts, chrome.EnableLoginVerboseLogs())
+
+	cr, err := chrome.New(ctx, opts...)
+	if err != nil {
+		return nil, errors.Wrap(err, "failed to start Chrome")
+	}
+
+	c.chrome = cr
+
+	return &empty.Empty{}, nil
+}
+
+func (c *PolicyService) StopChrome(ctx context.Context, req *empty.Empty) (*empty.Empty, error) {
+	var lastErr error
+
+	if c.chrome == nil {
+		return nil, errors.New("No active Chrome instance")
+	}
+
+	for id, conn := range c.extensionConns {
+		if err := conn.Close(); err != nil {
+			testing.ContextLogf(ctx, "Failed to close connection to extension %s", id)
+			lastErr = errors.Wrapf(err, "failed to close connection to extension %s", id)
+		}
+	}
+	c.extensionConns = make(map[string]*chrome.Conn)
+
+	if err := c.chrome.Close(ctx); err != nil {
+		testing.ContextLog(ctx, "Failed to close Chrome: ", err)
+		lastErr = errors.Wrap(err, "failed to close Chrome")
+	}
+	c.chrome = nil
+
+	return &empty.Empty{}, lastErr
+}
+
+func (c *PolicyService) ContinueLogin(ctx context.Context, req *empty.Empty) (*empty.Empty, error) {
+	if c.chrome == nil {
+		return nil, errors.New("No active Chrome instance")
+	}
+
+	if err := c.chrome.ContinueLogin(ctx); err != nil {
+		return nil, errors.Wrap(err, "Chrome login failed")
+	}
+
+	return &empty.Empty{}, nil
+}
+
 // CreateFakeDMSDir creates a directory. It needs to be removed with RemoveFakeDMSDir.
 func (c *PolicyService) CreateFakeDMSDir(ctx context.Context, req *ppb.CreateFakeDMSDirRequest) (*empty.Empty, error) {
 	// Remove existing data.
diff --git a/src/chromiumos/tast/services/cros/policy/policy.pb.go b/src/chromiumos/tast/services/cros/policy/policy.pb.go
index f2d8508..e6cf9bb 100644
--- a/src/chromiumos/tast/services/cros/policy/policy.pb.go
+++ b/src/chromiumos/tast/services/cros/policy/policy.pb.go
@@ -573,6 +573,77 @@
 	return ""
 }
 
+type StartChromeRequest struct {
+	PolicyJson           []byte   `protobuf:"bytes,1,opt,name=policy_json,json=policyJson,proto3" json:"policy_json,omitempty"`
+	Username             string   `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"`
+	SkipLogin            bool     `protobuf:"varint,3,opt,name=skip_login,json=skipLogin,proto3" json:"skip_login,omitempty"`
+	KeepEnrollment       bool     `protobuf:"varint,4,opt,name=keep_enrollment,json=keepEnrollment,proto3" json:"keep_enrollment,omitempty"`
+	DeferLogin           bool     `protobuf:"varint,5,opt,name=defer_login,json=deferLogin,proto3" json:"defer_login,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *StartChromeRequest) Reset()         { *m = StartChromeRequest{} }
+func (m *StartChromeRequest) String() string { return proto.CompactTextString(m) }
+func (*StartChromeRequest) ProtoMessage()    {}
+func (*StartChromeRequest) Descriptor() ([]byte, []int) {
+	return fileDescriptor_ac3b897852294d6a, []int{12}
+}
+
+func (m *StartChromeRequest) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_StartChromeRequest.Unmarshal(m, b)
+}
+func (m *StartChromeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_StartChromeRequest.Marshal(b, m, deterministic)
+}
+func (m *StartChromeRequest) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_StartChromeRequest.Merge(m, src)
+}
+func (m *StartChromeRequest) XXX_Size() int {
+	return xxx_messageInfo_StartChromeRequest.Size(m)
+}
+func (m *StartChromeRequest) XXX_DiscardUnknown() {
+	xxx_messageInfo_StartChromeRequest.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_StartChromeRequest proto.InternalMessageInfo
+
+func (m *StartChromeRequest) GetPolicyJson() []byte {
+	if m != nil {
+		return m.PolicyJson
+	}
+	return nil
+}
+
+func (m *StartChromeRequest) GetUsername() string {
+	if m != nil {
+		return m.Username
+	}
+	return ""
+}
+
+func (m *StartChromeRequest) GetSkipLogin() bool {
+	if m != nil {
+		return m.SkipLogin
+	}
+	return false
+}
+
+func (m *StartChromeRequest) GetKeepEnrollment() bool {
+	if m != nil {
+		return m.KeepEnrollment
+	}
+	return false
+}
+
+func (m *StartChromeRequest) GetDeferLogin() bool {
+	if m != nil {
+		return m.DeferLogin
+	}
+	return false
+}
+
 func init() {
 	proto.RegisterType((*EnrollUsingChromeRequest)(nil), "tast.cros.policy.EnrollUsingChromeRequest")
 	proto.RegisterType((*CreateFakeDMSDirRequest)(nil), "tast.cros.policy.CreateFakeDMSDirRequest")
@@ -586,60 +657,67 @@
 	proto.RegisterType((*Extension)(nil), "tast.cros.policy.Extension")
 	proto.RegisterType((*VerifyVisibleNotificationRequest)(nil), "tast.cros.policy.VerifyVisibleNotificationRequest")
 	proto.RegisterType((*EvalExpressionInChromeUrlRequest)(nil), "tast.cros.policy.EvalExpressionInChromeUrlRequest")
+	proto.RegisterType((*StartChromeRequest)(nil), "tast.cros.policy.StartChromeRequest")
 }
 
 func init() { proto.RegisterFile("policy.proto", fileDescriptor_ac3b897852294d6a) }
 
 var fileDescriptor_ac3b897852294d6a = []byte{
-	// 765 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0x7f, 0x6f, 0x1a, 0x47,
-	0x10, 0x35, 0xf8, 0x87, 0xcc, 0xf8, 0x67, 0x57, 0x35, 0x9c, 0xb1, 0x5a, 0xd3, 0x53, 0x55, 0xe3,
-	0x4a, 0x3d, 0x54, 0xb7, 0x95, 0x2a, 0xe5, 0x0f, 0xcb, 0x31, 0x58, 0xc1, 0x76, 0xa2, 0xe8, 0x88,
-	0x1d, 0x25, 0x91, 0x82, 0xd6, 0xdc, 0x00, 0x1b, 0x8e, 0xdd, 0xcb, 0xee, 0x62, 0xc5, 0x1f, 0x29,
-	0x9f, 0x2f, 0x5f, 0x20, 0xda, 0xbb, 0xe3, 0x4c, 0x38, 0xc0, 0x24, 0xf2, 0x7f, 0xb7, 0x73, 0x33,
-	0x6f, 0xdf, 0xbc, 0x99, 0x7d, 0xb0, 0x1e, 0x08, 0x9f, 0xb5, 0xee, 0x9c, 0x40, 0x0a, 0x2d, 0xc8,
-	0xb6, 0xa6, 0x4a, 0x3b, 0x2d, 0x29, 0x94, 0x13, 0xc5, 0x8b, 0x7b, 0x1d, 0x21, 0x3a, 0x3e, 0x56,
-	0xc2, 0xff, 0x37, 0x83, 0x76, 0x05, 0xfb, 0x81, 0x8e, 0xd3, 0xed, 0x2f, 0x19, 0xb0, 0x6a, 0x5c,
-	0x0a, 0xdf, 0xbf, 0x52, 0x8c, 0x77, 0x4e, 0xbb, 0x52, 0xf4, 0xd1, 0xc5, 0x8f, 0x03, 0x54, 0x9a,
-	0xec, 0xc3, 0x5a, 0x84, 0xd1, 0xfc, 0xa0, 0x04, 0xb7, 0x32, 0xa5, 0x4c, 0x79, 0xdd, 0x85, 0x28,
-	0x74, 0xae, 0x04, 0x27, 0x45, 0x58, 0x1d, 0x28, 0x94, 0x9c, 0xf6, 0xd1, 0xca, 0x96, 0x32, 0xe5,
-	0x9c, 0x9b, 0x9c, 0xc9, 0x13, 0x00, 0xfc, 0xa4, 0x91, 0x2b, 0x26, 0xb8, 0xb2, 0x16, 0x4b, 0x8b,
-	0xe5, 0xb5, 0xa3, 0x3d, 0x67, 0x9c, 0x9d, 0x53, 0x1b, 0xe6, 0xb8, 0x23, 0xe9, 0xe4, 0x97, 0xb0,
-	0x58, 0xd2, 0x26, 0x95, 0x1d, 0x65, 0x2d, 0x85, 0xd0, 0xb9, 0x30, 0x72, 0x22, 0x3b, 0xca, 0x10,
-	0x6b, 0xd3, 0x1e, 0x7a, 0x7d, 0xd5, 0xf4, 0x98, 0xb4, 0x96, 0xc3, 0xff, 0x10, 0x87, 0xaa, 0x4c,
-	0x9a, 0x7a, 0xd5, 0x63, 0x41, 0xd3, 0x17, 0x1d, 0xc6, 0xad, 0x95, 0x52, 0xa6, 0xbc, 0xea, 0xe6,
-	0x4c, 0xe4, 0xd2, 0x04, 0xec, 0xbf, 0xa0, 0x70, 0x2a, 0x91, 0x6a, 0x3c, 0xa3, 0x3d, 0xac, 0x3e,
-	0x6f, 0x54, 0x99, 0x1c, 0xf6, 0x4c, 0x60, 0x29, 0xa0, 0xba, 0x1b, 0x36, 0x9b, 0x73, 0xc3, 0x6f,
-	0x93, 0xee, 0x62, 0x5f, 0xdc, 0xce, 0x99, 0xfe, 0x3f, 0xec, 0x5c, 0x05, 0x1e, 0xd5, 0xf8, 0xd2,
-	0xb4, 0xc8, 0x50, 0xcd, 0xab, 0xa7, 0xfd, 0x2f, 0xe4, 0x1b, 0x28, 0x6f, 0xa3, 0xc2, 0xbb, 0x2a,
-	0xd5, 0x74, 0x58, 0x5a, 0x84, 0xd5, 0x96, 0xe0, 0x1a, 0xb9, 0x56, 0x71, 0x5d, 0x72, 0xb6, 0x8f,
-	0xa1, 0x90, 0xaa, 0x52, 0x81, 0xe0, 0x0a, 0xc9, 0x36, 0x2c, 0x0e, 0xa4, 0x1f, 0xb3, 0x33, 0x9f,
-	0x86, 0x70, 0x97, 0xaa, 0x6e, 0x3c, 0xae, 0xf0, 0xdb, 0x7e, 0x07, 0xf9, 0xda, 0x2d, 0xf5, 0xeb,
-	0xfc, 0x7e, 0x18, 0xf1, 0xb5, 0xbf, 0xc1, 0x7a, 0x32, 0x95, 0x26, 0xf3, 0x62, 0xa0, 0xb5, 0x24,
-	0x56, 0xf7, 0xc8, 0xaf, 0x66, 0x54, 0x81, 0x44, 0x65, 0xce, 0x31, 0xec, 0x48, 0xc4, 0xfe, 0x1b,
-	0x0a, 0x29, 0xf0, 0x98, 0x5d, 0x1e, 0x56, 0x24, 0xaa, 0x81, 0xaf, 0xe3, 0x96, 0xe2, 0x93, 0x7d,
-	0x0c, 0x1b, 0x49, 0xf2, 0x19, 0xf3, 0xd1, 0x90, 0x0e, 0x77, 0x2c, 0x56, 0x39, 0xdc, 0xaf, 0x51,
-	0x45, 0xb2, 0x63, 0x8a, 0xb8, 0x90, 0x4b, 0x00, 0xc8, 0x26, 0x64, 0x13, 0xe6, 0x59, 0xe6, 0x91,
-	0xff, 0x60, 0xb9, 0xcd, 0x7c, 0x34, 0x55, 0x66, 0x27, 0xf7, 0x67, 0xec, 0xa4, 0xb9, 0xdc, 0x8d,
-	0xb2, 0xed, 0x0b, 0x28, 0x5d, 0xa3, 0x64, 0xed, 0xbb, 0x6b, 0xa6, 0xd8, 0x8d, 0x8f, 0x2f, 0x84,
-	0x66, 0x6d, 0xd6, 0xa2, 0x7a, 0x44, 0xae, 0x03, 0xd8, 0xe2, 0x23, 0xe1, 0x7b, 0xc5, 0x36, 0x47,
-	0xc3, 0x75, 0xcf, 0x7e, 0x05, 0x25, 0x23, 0x4a, 0x2d, 0x91, 0xa9, 0xce, 0xa3, 0xa7, 0x77, 0x25,
-	0xfd, 0x21, 0x58, 0x7a, 0x76, 0x0f, 0x48, 0x7d, 0xf4, 0x39, 0x07, 0x1b, 0xd1, 0x12, 0x98, 0x7d,
-	0x60, 0x2d, 0x24, 0x6f, 0xe0, 0xa7, 0xd4, 0xeb, 0x26, 0x7f, 0x4e, 0xe8, 0x78, 0x8a, 0x05, 0x14,
-	0xf3, 0x4e, 0xe4, 0x1e, 0xce, 0xd0, 0x3d, 0x9c, 0x9a, 0x71, 0x0f, 0x7b, 0x81, 0x34, 0x60, 0xf3,
-	0xdb, 0x2d, 0x27, 0x07, 0x69, 0xdc, 0x89, 0xef, 0x60, 0x06, 0x68, 0x1d, 0x76, 0x4e, 0xbb, 0xd8,
-	0xea, 0x45, 0x24, 0x4e, 0xb8, 0x17, 0xbf, 0x38, 0x32, 0xa5, 0x64, 0x06, 0xd4, 0x33, 0xf8, 0xb9,
-	0xa1, 0x45, 0xf0, 0x08, 0x48, 0xaf, 0x61, 0x7b, 0xdc, 0x2d, 0xc8, 0x61, 0xba, 0xd7, 0x29, 0x8e,
-	0x32, 0x1b, 0x78, 0xdc, 0x57, 0x26, 0x01, 0x4f, 0xf1, 0x9e, 0x19, 0xc0, 0x17, 0x50, 0x68, 0x68,
-	0x2a, 0xb5, 0x59, 0x64, 0xc9, 0xa9, 0x6f, 0x3c, 0x21, 0xb4, 0x08, 0xf9, 0x03, 0xed, 0x77, 0x61,
-	0x6b, 0xcc, 0x5e, 0x48, 0x39, 0x4d, 0x72, 0xb2, 0x6f, 0x15, 0x0f, 0xe7, 0xc8, 0x8c, 0xdc, 0xc0,
-	0x5e, 0x20, 0xe7, 0x90, 0x37, 0x23, 0x7b, 0x14, 0xd6, 0xef, 0xc1, 0x32, 0x2f, 0xac, 0xa1, 0xa9,
-	0xc6, 0x3e, 0x72, 0x3d, 0xe2, 0x3f, 0x93, 0xe8, 0x4f, 0xf6, 0xbf, 0xd9, 0xaa, 0x8c, 0xd5, 0x7c,
-	0x07, 0xec, 0xe1, 0x1c, 0x99, 0x89, 0x2a, 0x0c, 0x76, 0xa7, 0x1a, 0x0f, 0x39, 0x4a, 0x23, 0x3d,
-	0xe4, 0x52, 0x33, 0x9a, 0x62, 0xb0, 0x3b, 0xc5, 0x96, 0xdc, 0xcb, 0x49, 0x57, 0x3d, 0xe4, 0x61,
-	0xd3, 0xaf, 0x7a, 0xfa, 0xc7, 0xdb, 0xdf, 0x5b, 0x26, 0x9b, 0x0d, 0xfa, 0x42, 0x55, 0x0c, 0x72,
-	0x45, 0x45, 0xa6, 0xa5, 0x2a, 0xe6, 0x8a, 0x4a, 0x74, 0xc5, 0xcd, 0x4a, 0x58, 0xf9, 0xcf, 0xd7,
-	0x00, 0x00, 0x00, 0xff, 0xff, 0xbd, 0x12, 0x79, 0x86, 0xe6, 0x08, 0x00, 0x00,
+	// 849 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0x6d, 0x6f, 0xe3, 0x44,
+	0x10, 0xbe, 0xb4, 0xd7, 0xaa, 0x99, 0xbe, 0x5c, 0x59, 0x71, 0x89, 0x2f, 0x27, 0xb8, 0x60, 0x9d,
+	0xb8, 0x14, 0x09, 0x47, 0x14, 0x90, 0x90, 0x90, 0x38, 0x95, 0x24, 0x27, 0x72, 0x2f, 0x08, 0x39,
+	0xf4, 0x10, 0x20, 0x11, 0x6d, 0xe3, 0x49, 0xb2, 0xc4, 0xd9, 0x35, 0xbb, 0x9b, 0x8a, 0xfe, 0x35,
+	0xfe, 0x16, 0x1f, 0xf9, 0x82, 0x76, 0xed, 0xb8, 0xbe, 0xd8, 0x71, 0x73, 0x55, 0xbf, 0x79, 0xc7,
+	0x33, 0xcf, 0x3e, 0xf3, 0xb2, 0xcf, 0xc0, 0x41, 0x24, 0x42, 0x36, 0xba, 0xf2, 0x22, 0x29, 0xb4,
+	0x20, 0xc7, 0x9a, 0x2a, 0xed, 0x8d, 0xa4, 0x50, 0x5e, 0x6c, 0x6f, 0x3c, 0x9e, 0x08, 0x31, 0x09,
+	0xb1, 0x6d, 0xff, 0x5f, 0x2c, 0xc6, 0x6d, 0x9c, 0x47, 0x3a, 0x71, 0x77, 0xff, 0xad, 0x80, 0xd3,
+	0xe3, 0x52, 0x84, 0xe1, 0xb9, 0x62, 0x7c, 0xd2, 0x99, 0x4a, 0x31, 0x47, 0x1f, 0xff, 0x5a, 0xa0,
+	0xd2, 0xe4, 0x09, 0xec, 0xc7, 0x18, 0xc3, 0x3f, 0x95, 0xe0, 0x4e, 0xa5, 0x59, 0x69, 0x1d, 0xf8,
+	0x10, 0x9b, 0x5e, 0x2a, 0xc1, 0x49, 0x03, 0xf6, 0x16, 0x0a, 0x25, 0xa7, 0x73, 0x74, 0xb6, 0x9a,
+	0x95, 0x56, 0xd5, 0x4f, 0xcf, 0xe4, 0x5b, 0x00, 0xfc, 0x5b, 0x23, 0x57, 0x4c, 0x70, 0xe5, 0x6c,
+	0x37, 0xb7, 0x5b, 0xfb, 0xa7, 0x8f, 0xbd, 0x55, 0x76, 0x5e, 0x6f, 0xe9, 0xe3, 0x67, 0xdc, 0xc9,
+	0x47, 0x36, 0x58, 0xd2, 0x21, 0x95, 0x13, 0xe5, 0xdc, 0xb7, 0xd0, 0x55, 0x6b, 0x39, 0x93, 0x13,
+	0x65, 0x88, 0x8d, 0xe9, 0x0c, 0x83, 0xb9, 0x1a, 0x06, 0x4c, 0x3a, 0x3b, 0xf6, 0x3f, 0x24, 0xa6,
+	0x2e, 0x93, 0x26, 0x5e, 0xcd, 0x58, 0x34, 0x0c, 0xc5, 0x84, 0x71, 0x67, 0xb7, 0x59, 0x69, 0xed,
+	0xf9, 0x55, 0x63, 0x79, 0x6d, 0x0c, 0xee, 0xe7, 0x50, 0xef, 0x48, 0xa4, 0x1a, 0x5f, 0xd0, 0x19,
+	0x76, 0xdf, 0x0c, 0xba, 0x4c, 0x2e, 0x73, 0x26, 0x70, 0x3f, 0xa2, 0x7a, 0x6a, 0x93, 0xad, 0xfa,
+	0xf6, 0xdb, 0xb8, 0xfb, 0x38, 0x17, 0x97, 0x1b, 0xba, 0x7f, 0x03, 0x0f, 0xcf, 0xa3, 0x80, 0x6a,
+	0xfc, 0xc9, 0xa4, 0xc8, 0x50, 0x6d, 0x5a, 0x4f, 0xf7, 0x2b, 0xa8, 0x0d, 0x50, 0x5e, 0xc6, 0x81,
+	0x57, 0x5d, 0xaa, 0xe9, 0x32, 0xb4, 0x01, 0x7b, 0x23, 0xc1, 0x35, 0x72, 0xad, 0x92, 0xb8, 0xf4,
+	0xec, 0x3e, 0x87, 0x7a, 0x2e, 0x4a, 0x45, 0x82, 0x2b, 0x24, 0xc7, 0xb0, 0xbd, 0x90, 0x61, 0xc2,
+	0xce, 0x7c, 0x1a, 0xc2, 0x53, 0xaa, 0xa6, 0x49, 0xbb, 0xec, 0xb7, 0xfb, 0x3b, 0xd4, 0x7a, 0x97,
+	0x34, 0xec, 0xf3, 0xeb, 0x66, 0x24, 0xd7, 0x7e, 0x02, 0x07, 0x69, 0x57, 0x86, 0x2c, 0x48, 0x80,
+	0xf6, 0x53, 0x5b, 0x3f, 0x20, 0x1f, 0x9b, 0x56, 0x45, 0x12, 0x95, 0x39, 0x27, 0xb0, 0x19, 0x8b,
+	0xfb, 0x05, 0xd4, 0x73, 0xe0, 0x09, 0xbb, 0x1a, 0xec, 0x4a, 0x54, 0x8b, 0x50, 0x27, 0x29, 0x25,
+	0x27, 0xf7, 0x39, 0x1c, 0xa6, 0xce, 0x2f, 0x58, 0x88, 0x86, 0xb4, 0x9d, 0xb1, 0xa4, 0xca, 0x76,
+	0xbe, 0xb2, 0x15, 0xd9, 0x5a, 0xa9, 0x88, 0x0f, 0xd5, 0x14, 0x80, 0x1c, 0xc1, 0x56, 0xca, 0x7c,
+	0x8b, 0x05, 0xe4, 0x6b, 0xd8, 0x19, 0xb3, 0x10, 0x4d, 0x94, 0x99, 0xc9, 0x27, 0x25, 0x33, 0x69,
+	0x2e, 0xf7, 0x63, 0x6f, 0xf7, 0x15, 0x34, 0xdf, 0xa2, 0x64, 0xe3, 0xab, 0xb7, 0x4c, 0xb1, 0x8b,
+	0x10, 0x7f, 0x14, 0x9a, 0x8d, 0xd9, 0x88, 0xea, 0x4c, 0xb9, 0x9e, 0xc1, 0x03, 0x9e, 0x31, 0x5f,
+	0x57, 0xec, 0x28, 0x6b, 0xee, 0x07, 0xee, 0xcf, 0xd0, 0x34, 0x45, 0xe9, 0xa5, 0x65, 0xea, 0xf3,
+	0xf8, 0xe9, 0x9d, 0xcb, 0x70, 0x09, 0x96, 0xef, 0xdd, 0x4d, 0xa5, 0xfe, 0xa7, 0x02, 0x64, 0xa0,
+	0xa9, 0xd4, 0x77, 0xf8, 0x8c, 0xdf, 0x7d, 0x49, 0xdb, 0x2b, 0x2f, 0xc9, 0x64, 0x3c, 0x43, 0x8c,
+	0x86, 0x68, 0x35, 0x64, 0x8e, 0x5c, 0xdb, 0xd7, 0xba, 0xe7, 0x1f, 0x19, 0x73, 0x2f, 0xb5, 0x1a,
+	0x12, 0x01, 0x8e, 0x51, 0x26, 0x40, 0x3b, 0xd6, 0x09, 0xac, 0xc9, 0x22, 0x9d, 0xfe, 0x07, 0x70,
+	0x18, 0x4f, 0xb0, 0x19, 0x66, 0x36, 0x42, 0xf2, 0x2b, 0x7c, 0x90, 0x93, 0x26, 0xf2, 0x59, 0x41,
+	0xbb, 0xd6, 0xe8, 0x57, 0xa3, 0xe6, 0xc5, 0xd2, 0xe7, 0x2d, 0xa5, 0xcf, 0xeb, 0x19, 0xe9, 0x73,
+	0xef, 0x91, 0x01, 0x1c, 0xbd, 0xfb, 0x44, 0xc9, 0xb3, 0x3c, 0x6e, 0xe1, 0x23, 0x2e, 0x01, 0xed,
+	0xc3, 0xc3, 0xce, 0x14, 0x47, 0xb3, 0x98, 0xc4, 0x19, 0x0f, 0x12, 0xb9, 0x20, 0x6b, 0x42, 0x4a,
+	0xa0, 0x7e, 0x80, 0x0f, 0x07, 0x5a, 0x44, 0x77, 0x80, 0xf4, 0x06, 0xf6, 0x33, 0x23, 0x41, 0x9e,
+	0xe6, 0xd3, 0xcc, 0x4f, 0x4c, 0x09, 0xdc, 0x77, 0x00, 0xd7, 0xc4, 0x6e, 0x41, 0xe7, 0x0c, 0x0e,
+	0x3b, 0x82, 0x6b, 0xc6, 0x17, 0x18, 0x0f, 0xd0, 0xfb, 0x43, 0xfc, 0x02, 0xc7, 0xab, 0xe2, 0x4d,
+	0x4e, 0xf2, 0x69, 0xad, 0x11, 0xf8, 0x72, 0xe0, 0x55, 0x99, 0x2f, 0x02, 0x5e, 0xb3, 0x0a, 0x4a,
+	0x80, 0x5f, 0x41, 0xdd, 0x16, 0xd9, 0xe8, 0x8a, 0xe4, 0x34, 0x34, 0x12, 0x6d, 0x15, 0x5b, 0xde,
+	0x22, 0xfd, 0x29, 0x3c, 0x58, 0x51, 0x7b, 0xd2, 0x2a, 0x68, 0x6a, 0xe1, 0x1a, 0x69, 0x9c, 0x6c,
+	0xe0, 0x19, 0x8b, 0xb3, 0x7b, 0x8f, 0xbc, 0x84, 0x9a, 0xe9, 0xf5, 0x9d, 0xb0, 0xfe, 0x03, 0x1c,
+	0x23, 0x78, 0x03, 0x4d, 0x35, 0x1a, 0x3d, 0xc8, 0xac, 0x83, 0x22, 0xfa, 0xc5, 0xeb, 0xa8, 0xbc,
+	0x2a, 0x2b, 0x31, 0xef, 0x01, 0x7b, 0xb2, 0x81, 0x67, 0x5a, 0x15, 0x06, 0x8f, 0xd6, 0xee, 0x01,
+	0x72, 0x9a, 0x47, 0xba, 0x69, 0x69, 0x94, 0x24, 0xc5, 0xe0, 0xd1, 0x9a, 0x2d, 0xe1, 0xbf, 0x2e,
+	0xba, 0xea, 0xa6, 0x95, 0xb2, 0xfe, 0xaa, 0xef, 0x3f, 0xfd, 0xed, 0xe9, 0xc8, 0x78, 0xb3, 0xc5,
+	0x5c, 0xa8, 0xb6, 0x41, 0x6e, 0xab, 0x58, 0x86, 0x55, 0xdb, 0x5c, 0xd1, 0x8e, 0xaf, 0xb8, 0xd8,
+	0xb5, 0x91, 0x5f, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0xff, 0x97, 0x95, 0x99, 0x09, 0x75, 0x0a, 0x00,
+	0x00,
 }
 
 // Reference imports to suppress errors if they are not otherwise used.
@@ -658,6 +736,9 @@
 	UpdatePolicies(ctx context.Context, in *UpdatePoliciesRequest, opts ...grpc.CallOption) (*empty.Empty, error)
 	CheckChromeAndFakeDMS(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error)
 	StopChromeAndFakeDMS(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error)
+	StartChrome(ctx context.Context, in *StartChromeRequest, opts ...grpc.CallOption) (*empty.Empty, error)
+	StopChrome(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error)
+	ContinueLogin(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error)
 	CreateFakeDMSDir(ctx context.Context, in *CreateFakeDMSDirRequest, opts ...grpc.CallOption) (*empty.Empty, error)
 	RemoveFakeDMSDir(ctx context.Context, in *RemoveFakeDMSDirRequest, opts ...grpc.CallOption) (*empty.Empty, error)
 	StartExternalDataServer(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error)
@@ -715,6 +796,33 @@
 	return out, nil
 }
 
+func (c *policyServiceClient) StartChrome(ctx context.Context, in *StartChromeRequest, opts ...grpc.CallOption) (*empty.Empty, error) {
+	out := new(empty.Empty)
+	err := c.cc.Invoke(ctx, "/tast.cros.policy.PolicyService/StartChrome", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *policyServiceClient) StopChrome(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error) {
+	out := new(empty.Empty)
+	err := c.cc.Invoke(ctx, "/tast.cros.policy.PolicyService/StopChrome", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *policyServiceClient) ContinueLogin(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error) {
+	out := new(empty.Empty)
+	err := c.cc.Invoke(ctx, "/tast.cros.policy.PolicyService/ContinueLogin", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
 func (c *policyServiceClient) CreateFakeDMSDir(ctx context.Context, in *CreateFakeDMSDirRequest, opts ...grpc.CallOption) (*empty.Empty, error) {
 	out := new(empty.Empty)
 	err := c.cc.Invoke(ctx, "/tast.cros.policy.PolicyService/CreateFakeDMSDir", in, out, opts...)
@@ -802,6 +910,9 @@
 	UpdatePolicies(context.Context, *UpdatePoliciesRequest) (*empty.Empty, error)
 	CheckChromeAndFakeDMS(context.Context, *empty.Empty) (*empty.Empty, error)
 	StopChromeAndFakeDMS(context.Context, *empty.Empty) (*empty.Empty, error)
+	StartChrome(context.Context, *StartChromeRequest) (*empty.Empty, error)
+	StopChrome(context.Context, *empty.Empty) (*empty.Empty, error)
+	ContinueLogin(context.Context, *empty.Empty) (*empty.Empty, error)
 	CreateFakeDMSDir(context.Context, *CreateFakeDMSDirRequest) (*empty.Empty, error)
 	RemoveFakeDMSDir(context.Context, *RemoveFakeDMSDirRequest) (*empty.Empty, error)
 	StartExternalDataServer(context.Context, *empty.Empty) (*empty.Empty, error)
@@ -831,6 +942,15 @@
 func (*UnimplementedPolicyServiceServer) StopChromeAndFakeDMS(ctx context.Context, req *empty.Empty) (*empty.Empty, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method StopChromeAndFakeDMS not implemented")
 }
+func (*UnimplementedPolicyServiceServer) StartChrome(ctx context.Context, req *StartChromeRequest) (*empty.Empty, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method StartChrome not implemented")
+}
+func (*UnimplementedPolicyServiceServer) StopChrome(ctx context.Context, req *empty.Empty) (*empty.Empty, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method StopChrome not implemented")
+}
+func (*UnimplementedPolicyServiceServer) ContinueLogin(ctx context.Context, req *empty.Empty) (*empty.Empty, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ContinueLogin not implemented")
+}
 func (*UnimplementedPolicyServiceServer) CreateFakeDMSDir(ctx context.Context, req *CreateFakeDMSDirRequest) (*empty.Empty, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method CreateFakeDMSDir not implemented")
 }
@@ -935,6 +1055,60 @@
 	return interceptor(ctx, in, info, handler)
 }
 
+func _PolicyService_StartChrome_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(StartChromeRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(PolicyServiceServer).StartChrome(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tast.cros.policy.PolicyService/StartChrome",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(PolicyServiceServer).StartChrome(ctx, req.(*StartChromeRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _PolicyService_StopChrome_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(empty.Empty)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(PolicyServiceServer).StopChrome(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tast.cros.policy.PolicyService/StopChrome",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(PolicyServiceServer).StopChrome(ctx, req.(*empty.Empty))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _PolicyService_ContinueLogin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(empty.Empty)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(PolicyServiceServer).ContinueLogin(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/tast.cros.policy.PolicyService/ContinueLogin",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(PolicyServiceServer).ContinueLogin(ctx, req.(*empty.Empty))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
 func _PolicyService_CreateFakeDMSDir_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
 	in := new(CreateFakeDMSDirRequest)
 	if err := dec(in); err != nil {
@@ -1118,6 +1292,18 @@
 			Handler:    _PolicyService_StopChromeAndFakeDMS_Handler,
 		},
 		{
+			MethodName: "StartChrome",
+			Handler:    _PolicyService_StartChrome_Handler,
+		},
+		{
+			MethodName: "StopChrome",
+			Handler:    _PolicyService_StopChrome_Handler,
+		},
+		{
+			MethodName: "ContinueLogin",
+			Handler:    _PolicyService_ContinueLogin_Handler,
+		},
+		{
 			MethodName: "CreateFakeDMSDir",
 			Handler:    _PolicyService_CreateFakeDMSDir_Handler,
 		},
diff --git a/src/chromiumos/tast/services/cros/policy/policy.proto b/src/chromiumos/tast/services/cros/policy/policy.proto
index 9230a1c..68ba1eb 100644
--- a/src/chromiumos/tast/services/cros/policy/policy.proto
+++ b/src/chromiumos/tast/services/cros/policy/policy.proto
@@ -16,6 +16,9 @@
   rpc UpdatePolicies(UpdatePoliciesRequest) returns (google.protobuf.Empty) {}
   rpc CheckChromeAndFakeDMS(google.protobuf.Empty) returns (google.protobuf.Empty) {}
   rpc StopChromeAndFakeDMS(google.protobuf.Empty) returns (google.protobuf.Empty) {}
+  rpc StartChrome(StartChromeRequest) returns (google.protobuf.Empty) {}
+  rpc StopChrome(google.protobuf.Empty) returns (google.protobuf.Empty) {}
+  rpc ContinueLogin(google.protobuf.Empty) returns (google.protobuf.Empty) {}
 
   rpc CreateFakeDMSDir(CreateFakeDMSDirRequest) returns (google.protobuf.Empty) {}
   rpc RemoveFakeDMSDir(RemoveFakeDMSDirRequest) returns (google.protobuf.Empty) {}
@@ -97,3 +100,11 @@
   string url = 1;
   string expression = 2;
 }
+
+message StartChromeRequest {
+  bytes policy_json = 1;
+  string username = 2;
+  bool skip_login = 3;
+  bool keep_enrollment = 4;
+  bool defer_login = 5;
+}