Base
This commit is contained in:
@@ -0,0 +1,205 @@
|
||||
package dev.oxmc.configprovisioner;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.IBinder;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
public class ProvisioningService extends Service {
|
||||
private static final String TAG = "ConfigProvisioner";
|
||||
private static final String DOWNLOAD_PATH = "/data/local/tmp/config_provision.apk";
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
Log.d(TAG, "Starting provisioning service");
|
||||
|
||||
// Double-check that vendor config exists
|
||||
if (!VendorConfig.hasVendorConfig()) {
|
||||
Log.i(TAG, "No vendor config found, stopping service");
|
||||
BootReceiver.setProvisioned(this, true);
|
||||
stopSelf();
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
new ProvisioningTask().execute();
|
||||
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
private class ProvisioningTask extends AsyncTask<Void, Void, Boolean> {
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
Log.i(TAG, "Starting provisioning process");
|
||||
|
||||
// Log all config values for debugging
|
||||
VendorConfig.logConfigValues();
|
||||
|
||||
// Check if provisioning is enabled
|
||||
if (!VendorConfig.isProvisioningEnabled()) {
|
||||
Log.i(TAG, "Provisioning disabled by vendor config");
|
||||
configureSetupWizard();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get config URL
|
||||
String configUrl = VendorConfig.getConfigApkUrl();
|
||||
if (configUrl == null || configUrl.isEmpty() || configUrl.equals(VendorConfig.DEFAULT_CONFIG_APK_URL)) {
|
||||
Log.e(TAG, "No valid config URL configured, skipping provisioning");
|
||||
configureSetupWizard();
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
Log.d(TAG, "Downloading config from: " + configUrl);
|
||||
|
||||
if (downloadApk(configUrl, DOWNLOAD_PATH)) {
|
||||
Log.i(TAG, "Download successful, installing APK");
|
||||
|
||||
if (installApk(DOWNLOAD_PATH)) {
|
||||
Log.i(TAG, "Installation successful");
|
||||
configureSetupWizard();
|
||||
return true;
|
||||
} else {
|
||||
Log.e(TAG, "Installation failed");
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Download failed");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Provisioning failed with error", e);
|
||||
} finally {
|
||||
// Clean up downloaded file
|
||||
File downloadedFile = new File(DOWNLOAD_PATH);
|
||||
if (downloadedFile.exists()) {
|
||||
if (downloadedFile.delete()) {
|
||||
Log.d(TAG, "Cleaned up downloaded file");
|
||||
} else {
|
||||
Log.w(TAG, "Failed to clean up downloaded file");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean success) {
|
||||
if (success) {
|
||||
Log.i(TAG, "Provisioning completed successfully");
|
||||
BootReceiver.setProvisioned(ProvisioningService.this, true);
|
||||
} else {
|
||||
Log.e(TAG, "Provisioning failed");
|
||||
// Don't mark as provisioned on failure, so it retries on next boot
|
||||
}
|
||||
stopSelf();
|
||||
}
|
||||
|
||||
private boolean downloadApk(String urlString, String outputPath) {
|
||||
HttpURLConnection connection = null;
|
||||
try {
|
||||
URL url = new URL(urlString);
|
||||
connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setConnectTimeout(VendorConfig.getNetworkTimeout());
|
||||
connection.setReadTimeout(VendorConfig.getNetworkTimeout());
|
||||
connection.setRequestProperty("User-Agent", "ConfigProvisioner/1.0");
|
||||
connection.connect();
|
||||
|
||||
int responseCode = connection.getResponseCode();
|
||||
if (responseCode != HttpURLConnection.HTTP_OK) {
|
||||
Log.e(TAG, "Server returned HTTP " + responseCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
try (InputStream input = connection.getInputStream();
|
||||
FileOutputStream output = new FileOutputStream(outputPath)) {
|
||||
|
||||
byte[] buffer = new byte[8192];
|
||||
int bytesRead;
|
||||
long totalBytes = 0;
|
||||
|
||||
while ((bytesRead = input.read(buffer)) != -1) {
|
||||
output.write(buffer, 0, bytesRead);
|
||||
totalBytes += bytesRead;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Downloaded " + totalBytes + " bytes to " + outputPath);
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Download failed", e);
|
||||
return false;
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean installApk(String apkPath) {
|
||||
try {
|
||||
Process process = Runtime.getRuntime().exec(
|
||||
new String[]{"pm", "install", "-r", "--user", "0", apkPath}
|
||||
);
|
||||
|
||||
int exitCode = process.waitFor();
|
||||
if (exitCode == 0) {
|
||||
Log.i(TAG, "APK installed successfully via pm install");
|
||||
return true;
|
||||
} else {
|
||||
Log.e(TAG, "pm install failed with exit code: " + exitCode);
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Installation failed", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void configureSetupWizard() {
|
||||
boolean enableWizard = VendorConfig.isSetupWizardEnabled();
|
||||
Log.i(TAG, "Configuring Setup Wizard: " + (enableWizard ? "ENABLED" : "DISABLED"));
|
||||
|
||||
if (!enableWizard) {
|
||||
disablePackage("com.android.setupwizard");
|
||||
disablePackage("com.google.android.setupwizard");
|
||||
disablePackage("org.lineageos.setupwizard");
|
||||
|
||||
// Mark setup as complete
|
||||
try {
|
||||
Settings.Secure.putInt(getContentResolver(),
|
||||
Settings.Secure.USER_SETUP_COMPLETE, 1);
|
||||
Settings.Global.putInt(getContentResolver(),
|
||||
Settings.Global.DEVICE_PROVISIONED, 1);
|
||||
Log.d(TAG, "Setup marked as complete");
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Failed to set setup complete flags", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void disablePackage(String packageName) {
|
||||
try {
|
||||
PackageManager pm = getPackageManager();
|
||||
pm.setApplicationEnabledSetting(packageName,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);
|
||||
Log.d(TAG, "Disabled package: " + packageName);
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Failed to disable package: " + packageName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user