• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.car.pm;
18 
19 import android.annotation.IntDef;
20 import android.annotation.Nullable;
21 import android.content.ComponentName;
22 import android.content.Intent;
23 import android.text.TextUtils;
24 
25 import java.lang.annotation.Retention;
26 import java.lang.annotation.RetentionPolicy;
27 
28 /**
29  * Describes configuration of the vendor service that needs to be started by Car Service. This is
30  * immutable object to store only service configuration.
31  */
32 final class VendorServiceInfo {
33     private static final String KEY_BIND = "bind";
34     private static final String KEY_USER_SCOPE = "user";
35     private static final String KEY_TRIGGER = "trigger";
36 
37     private static final int USER_SCOPE_ALL = 0;
38     private static final int USER_SCOPE_SYSTEM = 1;
39     private static final int USER_SCOPE_FOREGROUND = 2;
40     @Retention(RetentionPolicy.SOURCE)
41     @IntDef({
42             USER_SCOPE_ALL,
43             USER_SCOPE_FOREGROUND,
44             USER_SCOPE_SYSTEM,
45     })
46     @interface UserScope {}
47 
48     private static final int TRIGGER_ASAP = 0;
49     private static final int TRIGGER_UNLOCKED = 1;
50     private static final int TRIGGER_POST_UNLOCKED = 2;
51     @Retention(RetentionPolicy.SOURCE)
52     @IntDef({
53             TRIGGER_ASAP,
54             TRIGGER_UNLOCKED,
55             TRIGGER_POST_UNLOCKED,
56     })
57     @interface Trigger {}
58 
59     private static final int BIND = 0;
60     private static final int START = 1;
61     private static final int START_FOREGROUND = 2;
62     @Retention(RetentionPolicy.SOURCE)
63     @IntDef({
64             BIND,
65             START,
66             START_FOREGROUND,
67     })
68     @interface Bind {}
69 
70     private final @Bind int mBind;
71     private final @UserScope int mUserScope;
72     private final @Trigger int mTrigger;
73     @Nullable
74     private final ComponentName mComponentName;
75 
VendorServiceInfo(@ullable ComponentName componentName, @Bind int bind, @UserScope int userScope, @Trigger int trigger)76     private VendorServiceInfo(@Nullable ComponentName componentName, @Bind int bind,
77             @UserScope int userScope, @Trigger int trigger) {
78         mComponentName = componentName;
79         mUserScope = userScope;
80         mTrigger = trigger;
81         mBind = bind;
82     }
83 
isSystemUserService()84     boolean isSystemUserService() {
85         return mUserScope == USER_SCOPE_ALL || mUserScope == USER_SCOPE_SYSTEM;
86     }
87 
isForegroundUserService()88     boolean isForegroundUserService() {
89         return mUserScope == USER_SCOPE_ALL || mUserScope == USER_SCOPE_FOREGROUND;
90     }
91 
shouldStartOnUnlock()92     boolean shouldStartOnUnlock() {
93         return mTrigger == TRIGGER_UNLOCKED;
94     }
95 
shouldStartOnPostUnlock()96     boolean shouldStartOnPostUnlock() {
97         return mTrigger == TRIGGER_POST_UNLOCKED;
98     }
99 
shouldStartAsap()100     boolean shouldStartAsap() {
101         return mTrigger == TRIGGER_ASAP;
102     }
103 
shouldBeBound()104     boolean shouldBeBound() {
105         return mBind == BIND;
106     }
107 
shouldBeStartedInForeground()108     boolean shouldBeStartedInForeground() {
109         return mBind == START_FOREGROUND;
110     }
111 
getIntent()112     Intent getIntent() {
113         Intent intent = new Intent();
114         intent.setComponent(mComponentName);
115         return intent;
116     }
117 
parse(String rawServiceInfo)118     static VendorServiceInfo parse(String rawServiceInfo) {
119         String[] serviceParamTokens = rawServiceInfo.split("#");
120         if (serviceParamTokens.length < 1 || serviceParamTokens.length > 2) {
121             throw new IllegalArgumentException("Failed to parse service info: "
122                     + rawServiceInfo + ", expected a single '#' symbol");
123 
124         }
125 
126         final ComponentName cn = ComponentName.unflattenFromString(serviceParamTokens[0]);
127         if (cn == null) {
128             throw new IllegalArgumentException("Failed to unflatten component name from: "
129                     + rawServiceInfo);
130         }
131 
132         int bind = START;
133         int userScope = USER_SCOPE_ALL;
134         int trigger = TRIGGER_UNLOCKED;
135 
136         if (serviceParamTokens.length == 2) {
137             for (String keyValueStr : serviceParamTokens[1].split(",")) {
138                 String[] pair = keyValueStr.split("=");
139                 String key = pair[0];
140                 String val = pair[1];
141                 if (TextUtils.isEmpty(key)) {
142                     continue;
143                 }
144 
145                 switch (key) {
146                     case KEY_BIND:
147                         switch (val) {
148                             case "bind":
149                                 bind = BIND;
150                                 break;
151                             case "start":
152                                 bind = START;
153                                 break;
154                             case "startForeground":
155                                 bind = START_FOREGROUND;
156                                 break;
157                             default:
158                                 throw new IllegalArgumentException("Unexpected bind option: "
159                                         + val);
160                         }
161                         break;
162                     case KEY_USER_SCOPE:
163                         switch (val) {
164                             case "all":
165                                 userScope = USER_SCOPE_ALL;
166                                 break;
167                             case "system":
168                                 userScope = USER_SCOPE_SYSTEM;
169                                 break;
170                             case "foreground":
171                                 userScope = USER_SCOPE_FOREGROUND;
172                                 break;
173                             default:
174                                 throw new IllegalArgumentException("Unexpected user scope: " + val);
175                         }
176                         break;
177                     case KEY_TRIGGER:
178                         switch (val) {
179                             case "asap":
180                                 trigger = TRIGGER_ASAP;
181                                 break;
182                             case "userUnlocked":
183                                 trigger = TRIGGER_UNLOCKED;
184                                 break;
185                             case "userPostUnlocked":
186                                 trigger = TRIGGER_POST_UNLOCKED;
187                                 break;
188                             default:
189                                 throw new IllegalArgumentException("Unexpected trigger: " + val);
190                         }
191                         break;
192                     default:
193                         throw new IllegalArgumentException("Unexpected token: " + key);
194                 }
195             }
196         }
197 
198         return new VendorServiceInfo(cn, bind, userScope, trigger);
199     }
200 
201     @Override
toString()202     public String toString() {
203         return "VendorService{"
204                 + "component=" + toShortString()
205                 + ", bind=" + bindToString(mBind)
206                 + ", trigger=" + triggerToString(mTrigger)
207                 + ", userScope=" + userScopeToString(mUserScope)
208                 + '}';
209     }
210 
toShortString()211     String toShortString() {
212         return mComponentName != null ? mComponentName.flattenToShortString() : "N/A";
213     }
214 
215     // NOTE: cannot use DebugUtils below because constants are private
216 
bindToString(@ind int bind)217     private static String bindToString(@Bind int bind) {
218         switch (bind) {
219             case BIND:
220                 return "BIND";
221             case START:
222                 return "START";
223             case START_FOREGROUND:
224                 return "START_FOREGROUND";
225             default:
226                 return "INVALID-" + bind;
227         }
228     }
229 
triggerToString(@rigger int trigger)230     private static String triggerToString(@Trigger int trigger) {
231         switch (trigger) {
232             case TRIGGER_ASAP:
233                 return "ASAP";
234             case TRIGGER_UNLOCKED:
235                 return "UNLOCKED";
236             case TRIGGER_POST_UNLOCKED:
237                 return "POST_UNLOCKED";
238             default:
239                 return "INVALID-" + trigger;
240         }
241     }
242 
userScopeToString(@serScope int userScope)243     private static String userScopeToString(@UserScope int userScope) {
244         switch (userScope) {
245             case USER_SCOPE_ALL:
246                 return "ALL";
247             case USER_SCOPE_FOREGROUND:
248                 return "FOREGROUND";
249             case USER_SCOPE_SYSTEM:
250                 return "SYSTEM";
251             default:
252                 return "INVALID-" + userScope;
253         }
254     }
255 }
256