blob: 9d979a6701c7c3c466dc2a662788bc424ed38584 [file] [log] [blame]
Howard Chenf17f42b2019-01-07 14:10:44 +08001/*
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
17package com.android.server;
18
19import android.content.Context;
20import android.content.pm.PackageManager;
Howard Chen148d7ed2019-03-26 16:13:04 +080021import android.gsi.GsiInstallParams;
Howard Chenf17f42b2019-01-07 14:10:44 +080022import android.gsi.GsiProgress;
23import android.gsi.IGsiService;
Howard Chen148d7ed2019-03-26 16:13:04 +080024import android.os.Environment;
Howard Chenf17f42b2019-01-07 14:10:44 +080025import android.os.IBinder;
26import android.os.IBinder.DeathRecipient;
Howard Chenf17f42b2019-01-07 14:10:44 +080027import android.os.RemoteException;
28import android.os.ServiceManager;
Howard Chen1392c142019-03-05 14:23:47 +080029import android.os.SystemProperties;
Howard Chen148d7ed2019-03-26 16:13:04 +080030import android.os.UserHandle;
Po-Chien Hsueh4e908c22019-03-07 11:57:17 +080031import android.os.image.IDynamicSystemService;
Howard Chen148d7ed2019-03-26 16:13:04 +080032import android.os.storage.StorageManager;
33import android.os.storage.StorageVolume;
Howard Chenf17f42b2019-01-07 14:10:44 +080034import android.util.Slog;
35
Howard Chen148d7ed2019-03-26 16:13:04 +080036import java.io.File;
37
Howard Chenf17f42b2019-01-07 14:10:44 +080038/**
Po-Chien Hsueh4e908c22019-03-07 11:57:17 +080039 * DynamicSystemService implements IDynamicSystemService. It provides permission check before
Howard Chenf17f42b2019-01-07 14:10:44 +080040 * passing requests to gsid
41 */
Po-Chien Hsueh4e908c22019-03-07 11:57:17 +080042public class DynamicSystemService extends IDynamicSystemService.Stub implements DeathRecipient {
43 private static final String TAG = "DynamicSystemService";
Howard Chenf17f42b2019-01-07 14:10:44 +080044 private static final String NO_SERVICE_ERROR = "no gsiservice";
Howard Chen1392c142019-03-05 14:23:47 +080045 private static final int GSID_ROUGH_TIMEOUT_MS = 8192;
Howard Chen148d7ed2019-03-26 16:13:04 +080046 private static final String PATH_DEFAULT = "/data/gsi";
Howard Chenf17f42b2019-01-07 14:10:44 +080047 private Context mContext;
48 private volatile IGsiService mGsiService;
49
Po-Chien Hsueh4e908c22019-03-07 11:57:17 +080050 DynamicSystemService(Context context) {
Howard Chenf17f42b2019-01-07 14:10:44 +080051 mContext = context;
52 }
53
54 private static IGsiService connect(DeathRecipient recipient) throws RemoteException {
55 IBinder binder = ServiceManager.getService("gsiservice");
56 if (binder == null) {
Po-Chien Hsueh7565fcc2019-04-11 16:36:54 +080057 return null;
Howard Chenf17f42b2019-01-07 14:10:44 +080058 }
59 /**
60 * The init will restart gsiservice if it crashed and the proxy object will need to be
61 * re-initialized in this case.
62 */
63 binder.linkToDeath(recipient, 0);
64 return IGsiService.Stub.asInterface(binder);
65 }
66
67 /** implements DeathRecipient */
68 @Override
69 public void binderDied() {
70 Slog.w(TAG, "gsiservice died; reconnecting");
71 synchronized (this) {
72 mGsiService = null;
73 }
74 }
75
76 private IGsiService getGsiService() throws RemoteException {
77 checkPermission();
Po-Chien Hsueh7565fcc2019-04-11 16:36:54 +080078
Howard Chen1392c142019-03-05 14:23:47 +080079 if (!"running".equals(SystemProperties.get("init.svc.gsid"))) {
80 SystemProperties.set("ctl.start", "gsid");
Po-Chien Hsueh7565fcc2019-04-11 16:36:54 +080081 }
82
83 for (int sleepMs = 64; sleepMs <= (GSID_ROUGH_TIMEOUT_MS << 1); sleepMs <<= 1) {
84 synchronized (this) {
85 if (mGsiService == null) {
86 mGsiService = connect(this);
Howard Chen72324e42019-03-29 16:38:39 +080087 }
Po-Chien Hsueh7565fcc2019-04-11 16:36:54 +080088 if (mGsiService != null) {
89 return mGsiService;
Howard Chen1392c142019-03-05 14:23:47 +080090 }
91 }
Po-Chien Hsueh7565fcc2019-04-11 16:36:54 +080092
93 try {
94 Slog.d(TAG, "GsiService is not ready, wait for " + sleepMs + "ms");
95 Thread.sleep(sleepMs);
96 } catch (InterruptedException e) {
97 Slog.e(TAG, "Interrupted when waiting for GSID");
98 return null;
Howard Chen72324e42019-03-29 16:38:39 +080099 }
Howard Chen72324e42019-03-29 16:38:39 +0800100 }
Po-Chien Hsueh7565fcc2019-04-11 16:36:54 +0800101
102 throw new RemoteException(NO_SERVICE_ERROR);
Howard Chenf17f42b2019-01-07 14:10:44 +0800103 }
104
105 private void checkPermission() {
106 if (mContext.checkCallingOrSelfPermission(
Po-Chien Hsueh4e908c22019-03-07 11:57:17 +0800107 android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
Howard Chenf17f42b2019-01-07 14:10:44 +0800108 != PackageManager.PERMISSION_GRANTED) {
Po-Chien Hsueh4e908c22019-03-07 11:57:17 +0800109 throw new SecurityException("Requires MANAGE_DYNAMIC_SYSTEM permission");
Howard Chenf17f42b2019-01-07 14:10:44 +0800110 }
111 }
112
113 @Override
114 public boolean startInstallation(long systemSize, long userdataSize) throws RemoteException {
Howard Chen148d7ed2019-03-26 16:13:04 +0800115 // priority from high to low: sysprop -> sdcard -> /data
116 String path = SystemProperties.get("os.aot.path");
117 if (path.isEmpty()) {
118 final int userId = UserHandle.myUserId();
119 final StorageVolume[] volumes =
120 StorageManager.getVolumeList(userId, StorageManager.FLAG_FOR_WRITE);
121 for (StorageVolume volume : volumes) {
122 if (volume.isEmulated()) continue;
123 if (!volume.isRemovable()) continue;
124 if (!Environment.MEDIA_MOUNTED.equals(volume.getState())) continue;
125 File sdCard = volume.getPathFile();
126 if (sdCard.isDirectory()) {
127 path = sdCard.getPath();
128 break;
129 }
130 }
131 if (path.isEmpty()) {
132 path = PATH_DEFAULT;
133 }
134 Slog.i(TAG, "startInstallation -> " + path);
135 }
136 GsiInstallParams installParams = new GsiInstallParams();
137 installParams.installDir = path;
138 installParams.gsiSize = systemSize;
139 installParams.userdataSize = userdataSize;
140 return getGsiService().beginGsiInstall(installParams) == 0;
Howard Chenf17f42b2019-01-07 14:10:44 +0800141 }
142
143 @Override
144 public GsiProgress getInstallationProgress() throws RemoteException {
145 return getGsiService().getInstallProgress();
146 }
147
148 @Override
149 public boolean abort() throws RemoteException {
150 return getGsiService().cancelGsiInstall();
151 }
152
153 @Override
154 public boolean isInUse() throws RemoteException {
155 return getGsiService().isGsiRunning();
156 }
157
158 @Override
159 public boolean isInstalled() throws RemoteException {
160 return getGsiService().isGsiInstalled();
161 }
162
163 @Override
Howard Chen72324e42019-03-29 16:38:39 +0800164 public boolean isEnabled() throws RemoteException {
165 return getGsiService().isGsiEnabled();
166 }
167
168 @Override
Howard Chenf17f42b2019-01-07 14:10:44 +0800169 public boolean remove() throws RemoteException {
170 return getGsiService().removeGsiInstall();
171 }
172
173 @Override
Howard Chen72324e42019-03-29 16:38:39 +0800174 public boolean setEnable(boolean enable) throws RemoteException {
Howard Chenf17f42b2019-01-07 14:10:44 +0800175 IGsiService gsiService = getGsiService();
Howard Chen72324e42019-03-29 16:38:39 +0800176 if (enable) {
David Anderson8ee06742019-02-27 13:45:34 -0800177 final int status = gsiService.getGsiBootStatus();
178 final boolean singleBoot = (status == IGsiService.BOOT_STATUS_SINGLE_BOOT);
179 return gsiService.setGsiBootable(singleBoot) == 0;
Howard Chen72324e42019-03-29 16:38:39 +0800180 } else {
181 return gsiService.disableGsiInstall();
Howard Chenf17f42b2019-01-07 14:10:44 +0800182 }
183 }
184
185 @Override
186 public boolean write(byte[] buf) throws RemoteException {
187 return getGsiService().commitGsiChunkFromMemory(buf);
188 }
189
190 @Override
191 public boolean commit() throws RemoteException {
David Anderson8ee06742019-02-27 13:45:34 -0800192 return getGsiService().setGsiBootable(true) == 0;
Howard Chenf17f42b2019-01-07 14:10:44 +0800193 }
194}