1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
|
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.ContentResolver;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import com.android.server.am.ActivityManagerService;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.UserManagerInternal;
import com.android.server.utils.Slogf;
import com.android.server.utils.TimingsTraceAndSlog;
/**
* Class responsible for booting the device in the proper user on headless system user mode.
*
*/
final class HsumBootUserInitializer {
private static final String TAG = HsumBootUserInitializer.class.getSimpleName();
private final UserManagerInternal mUmi;
private final ActivityManagerService mAms;
private final PackageManagerService mPms;
private final ContentResolver mContentResolver;
private final ContentObserver mDeviceProvisionedObserver =
new ContentObserver(new Handler(Looper.getMainLooper())) {
@Override
public void onChange(boolean selfChange) {
// Set USER_SETUP_COMPLETE for the (headless) system user only when the device
// has been set up at least once.
if (isDeviceProvisioned()) {
Slogf.i(TAG, "Marking USER_SETUP_COMPLETE for system user");
Settings.Secure.putInt(mContentResolver,
Settings.Secure.USER_SETUP_COMPLETE, 1);
mContentResolver.unregisterContentObserver(mDeviceProvisionedObserver);
}
}
};
/** Whether this device should always have a non-removable MainUser, including at first boot. */
private final boolean mShouldAlwaysHaveMainUser;
/** Static factory method for creating a {@link HsumBootUserInitializer} instance. */
public static @Nullable HsumBootUserInitializer createInstance(ActivityManagerService am,
PackageManagerService pms, ContentResolver contentResolver,
boolean shouldAlwaysHaveMainUser) {
if (!UserManager.isHeadlessSystemUserMode()) {
return null;
}
return new HsumBootUserInitializer(
LocalServices.getService(UserManagerInternal.class),
am, pms, contentResolver, shouldAlwaysHaveMainUser);
}
private HsumBootUserInitializer(UserManagerInternal umi, ActivityManagerService am,
PackageManagerService pms, ContentResolver contentResolver,
boolean shouldAlwaysHaveMainUser) {
mUmi = umi;
mAms = am;
mPms = pms;
mContentResolver = contentResolver;
mShouldAlwaysHaveMainUser = shouldAlwaysHaveMainUser;
}
/**
* Initialize this object, and create MainUser if needed.
*
* <p>Should be called before PHASE_SYSTEM_SERVICES_READY as services' setups may require
* MainUser, but probably after PHASE_LOCK_SETTINGS_READY since that may be needed for user
* creation.
*/
public void init(TimingsTraceAndSlog t) {
Slogf.i(TAG, "init())");
if (mShouldAlwaysHaveMainUser) {
t.traceBegin("createMainUserIfNeeded");
createMainUserIfNeeded();
t.traceEnd();
}
}
private void createMainUserIfNeeded() {
final int mainUser = mUmi.getMainUserId();
if (mainUser != UserHandle.USER_NULL) {
Slogf.d(TAG, "Found existing MainUser, userId=%d", mainUser);
return;
}
Slogf.d(TAG, "Creating a new MainUser");
try {
final UserInfo newInitialUser = mUmi.createUserEvenWhenDisallowed(
/* name= */ null, // null will appear as "Owner" in on-demand localisation
UserManager.USER_TYPE_FULL_SECONDARY,
UserInfo.FLAG_ADMIN | UserInfo.FLAG_MAIN,
/* disallowedPackages= */ null,
/* token= */ null);
Slogf.i(TAG, "Successfully created MainUser, userId=%d", newInitialUser.id);
} catch (UserManager.CheckedUserOperationException e) {
Slogf.wtf(TAG, "Initial bootable MainUser creation failed", e);
}
}
/**
* Put the device into the correct user state: unlock the system and switch to the boot user.
*
* <p>Should only call once PHASE_THIRD_PARTY_APPS_CAN_START is reached to ensure that
* privileged apps have had the chance to set the boot user, if applicable.
*/
public void systemRunning(TimingsTraceAndSlog t) {
observeDeviceProvisioning();
unlockSystemUser(t);
try {
t.traceBegin("getBootUser");
final int bootUser = mUmi.getBootUser(/* waitUntilSet= */ mPms
.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, /* version= */0));
t.traceEnd();
t.traceBegin("switchToBootUser-" + bootUser);
switchToBootUser(bootUser);
t.traceEnd();
} catch (UserManager.CheckedUserOperationException e) {
Slogf.wtf(TAG, "Failed to switch to boot user since there isn't one.");
}
}
private void observeDeviceProvisioning() {
if (isDeviceProvisioned()) {
return;
}
mContentResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
false,
mDeviceProvisionedObserver
);
}
private boolean isDeviceProvisioned() {
try {
return Settings.Global.getInt(mContentResolver,
Settings.Global.DEVICE_PROVISIONED) == 1;
} catch (Exception e) {
Slogf.wtf(TAG, "DEVICE_PROVISIONED setting not found.", e);
return false;
}
}
// NOTE: Mostly copied from Automotive's InitialUserSetter
// TODO(b/266158156): Refactor how starting/unlocking works for the System.
private void unlockSystemUser(TimingsTraceAndSlog t) {
Slogf.i(TAG, "Unlocking system user");
t.traceBegin("unlock-system-user");
try {
// This is for force changing state into RUNNING_LOCKED. Otherwise unlock does not
// update the state and USER_SYSTEM unlock happens twice.
t.traceBegin("am.startUser");
final boolean started = mAms.startUserInBackgroundWithListener(UserHandle.USER_SYSTEM,
/* listener= */ null);
t.traceEnd();
if (!started) {
Slogf.w(TAG, "could not restart system user in background; trying unlock instead");
t.traceBegin("am.unlockUser");
final boolean unlocked = mAms.unlockUser(UserHandle.USER_SYSTEM, /* token= */ null,
/* secret= */ null, /* listener= */ null);
t.traceEnd();
if (!unlocked) {
Slogf.w(TAG, "could not unlock system user either");
}
}
} finally {
t.traceEnd();
}
}
private void switchToBootUser(@UserIdInt int bootUserId) {
Slogf.i(TAG, "Switching to boot user %d", bootUserId);
final boolean started = mAms.startUserInForegroundWithListener(bootUserId,
/* unlockListener= */ null);
if (!started) {
Slogf.wtf(TAG, "Failed to start user %d in foreground", bootUserId);
}
}
}
|