Merge lp:~humpolec-team/humpolec/UbuntuInstaller-ota into lp:humpolec

Proposed by Rex Tsai
Status: Merged
Approved by: Yuan-Chen Cheng
Approved revision: 45
Merge reported by: Rex Tsai
Merged at revision: not available
Proposed branch: lp:~humpolec-team/humpolec/UbuntuInstaller-ota
Merge into: lp:humpolec
Diff against target: 1175 lines (+428/-315)
7 files modified
AndroidManifest.xml (+1/-0)
assets/system-image-upgrader (+16/-11)
assets/upgrade-checker (+16/-0)
src/com/canonical/ubuntu/installer/InstallActivity.java (+34/-32)
src/com/canonical/ubuntu/installer/LaunchActivity.java (+29/-6)
src/com/canonical/ubuntu/installer/UbuntuInstallService.java (+332/-262)
src/com/canonical/ubuntu/installer/VersionInfo.java (+0/-4)
To merge this branch: bzr merge lp:~humpolec-team/humpolec/UbuntuInstaller-ota
Reviewer Review Type Date Requested Status
Yuan-Chen Cheng Approve
Review via email: mp+200035@code.launchpad.net

Description of the change

Support Ubuntu Touch upgrade.

* Find update_command in /cache/recovery, if update_command comes from /cache, it's upgradeable.
* Added Upgradeable checking script, check if upgrade image available in /cache
* Use INSTALLED_VERSION as DOWNLOADED_VERSION for system upgrade, since we don't know what's the version in /cache.
* New Intent Servcie for checking upgrade.
* make doInstallUbuntu works with images file stored in /cache.
* clean up UpdateComamnd function.
* only using executeSUCommands for shell access.

To post a comment you must log in.
Revision history for this message
Yuan-Chen Cheng (ycheng-twn) wrote :

line 35: why not move BUSYBOX=busybox up and
        cd `${BUSYBOX} dirname $1`

line 104: what's "user's data" did you mean ?
        user data that android create, user data that ubuntu user create or ?

line 335: will it better to name something like IS_UBUNTU_UPGRADABLE
        instead of UPGRADE_UBUNTU

line 425: can you add comment on the logic ? like
        As working dir in /data, blalal
        As working dir in /cache, blalal

line 1140: please also add comment like line 425. (or refer to it)

line 1082, "getApplication()." can be removed.

line 1034: UbuntuInstallService.isUpgradeable
        check command file against /cache works in this case, but it
        does not necessary means upgradable (it might means some
        error on internal status keeping) since normal install
        could have command file in /cache if the apk is installed
        in ROM.

        should we rename this function to something else ?

Maybe we should stop adding new code and try to document the state machine.
Maybe more re-factor then.

review: Needs Fixing
40. By Rex Tsai

use for busybox.

41. By Rex Tsai

Removed confusing comment on Ubuntu user data.

42. By Rex Tsai

s/UPGRADE_UBUNTU/IS_UBUNTU_UPGRADABLE/

43. By Rex Tsai

Comment on updates command checking.

44. By Rex Tsai

Add comment on findUpgradeable()

45. By Rex Tsai

s/findUpgradeable/findInstallCommand/

Revision history for this message
Rex Tsai (chihchun) wrote :

Changes for meet YC's requests.

* 2f4e386 - s/findUpgradeable/findInstallCommand/
* 6b5b8b9 - Add comment on findUpgradeable()
* 64ca88b - Comment on updates command checking.
* 686a879 - s/UPGRADE_UBUNTU/IS_UBUNTU_UPGRADABLE/
* 2d031a6 - Removed confusing comment on Ubuntu user data.
* 33e8eea - use ${BUSYBOX} for busybox.

Revision history for this message
Yuan-Chen Cheng (ycheng-twn) wrote :

+1

I still don't like the function name isUpgradeable, but it's too personal and the code is good enough for now.

review: Approve
Revision history for this message
Rex Tsai (chihchun) wrote :

I think we can integrate both checkifReadyToInstall and isUpgradeable into one function.
But need to clean up how we manage Shared Preferences data.

I will do merge first.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'AndroidManifest.xml'
--- AndroidManifest.xml 2013-12-21 16:59:18 +0000
+++ AndroidManifest.xml 2013-12-26 07:18:46 +0000
@@ -62,6 +62,7 @@
62 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.GET_SERVICE_STATE" />62 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.GET_SERVICE_STATE" />
63 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.GET_PROGRESS_STATUS" />63 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.GET_PROGRESS_STATUS" />
64 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.REBOOT_UBUNTU" />64 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.REBOOT_UBUNTU" />
65 <action android:name="com.canonical.ubuntuinstaller.UbuntuInstallService.IS_UBUNTU_UPGRADABLE" />
65 </intent-filter>66 </intent-filter>
66 </service>67 </service>
67 </application>68 </application>
6869
=== modified file 'assets/system-image-upgrader'
--- assets/system-image-upgrader 2013-12-20 03:39:53 +0000
+++ assets/system-image-upgrader 2013-12-26 07:18:46 +0000
@@ -1,25 +1,30 @@
1#!/sbin/sh1#!/system/bin/sh
2# Copyright (C) 2013 Canonical Ltd.
23
3export PATH=$PATH:${PWD}4# $0 [ubuntu command file] [app/private folder]
4UPDATE_FOLDER=${PWD}
5PRIVATE_DIR=$2
6BUSYBOX=busybox
7TAR=u_tar
8set -e
95
10if [ ! -e "$1" ]; then6if [ ! -e "$1" ]; then
11 echo "Command file doesn't exist: $1"7 echo "Command file doesn't exist: $1"
12 exit 18 exit 1
13fi9fi
14mv $1 $1.applying10
15COMMAND_FILE=$1.applying11COMMAND_FILE=$1.applying
16
17REMOVE_LIST="$COMMAND_FILE"12REMOVE_LIST="$COMMAND_FILE"
1813UPDATE_FOLDER=${PWD}
14PRIVATE_DIR=$2
15BUSYBOX=busybox
16TAR=u_tar
19TMP=/cache/tmp17TMP=/cache/tmp
18export PATH=${PWD}:${PRIVATE_DIR}:$PATH
2019
20set -e
21echo "Starting image upgrader: $(date)"21echo "Starting image upgrader: $(date)"
2222
23# switch to the update command folder, which has the images
24cd `$BUSYBOX dirname $1`
25mv $1 $1.applying
26
27
23# Functions28# Functions
24verify_signature() {29verify_signature() {
25 return 030 return 0
@@ -143,7 +148,7 @@
143148
144# Process the command file149# Process the command file
145FULL_IMAGE=0150FULL_IMAGE=0
146echo "Processing the command file"151echo "Processing the command file $COMMAND_FILE"
147while read line152while read line
148do153do
149 set -- $line154 set -- $line
150155
=== added file 'assets/upgrade-checker'
--- assets/upgrade-checker 1970-01-01 00:00:00 +0000
+++ assets/upgrade-checker 2013-12-26 07:18:46 +0000
@@ -0,0 +1,16 @@
1#!/system/bin/sh
2# Copyright (C) 2013 Canonical Ltd.
3#
4# Check if ubuntu_command exist
5# print the path and exit 0 if found.
6
7FILES=$@
8
9for file in $FILES ; do
10 if [[ -f $file ]] ; then
11 echo $file
12 exit 1
13 fi
14done
15
16exit 0
017
=== modified file 'src/com/canonical/ubuntu/installer/InstallActivity.java'
--- src/com/canonical/ubuntu/installer/InstallActivity.java 2013-12-25 06:09:49 +0000
+++ src/com/canonical/ubuntu/installer/InstallActivity.java 2013-12-26 07:18:46 +0000
@@ -114,14 +114,14 @@
114 }114 }
115 mObserversRegistered = false;115 mObserversRegistered = false;
116 }116 }
117 117
118 @Override118 @Override
119 public boolean onCreateOptionsMenu(Menu menu) {119 public boolean onCreateOptionsMenu(Menu menu) {
120 // Inflate the menu; this adds items to the action bar if it is present.120 // Inflate the menu; this adds items to the action bar if it is present.
121 getMenuInflater().inflate(R.menu.installer_menu, menu);121 getMenuInflater().inflate(R.menu.installer_menu, menu);
122 return true;122 return true;
123 }123 }
124 124
125 @Override125 @Override
126 public boolean onOptionsItemSelected(MenuItem item) {126 public boolean onOptionsItemSelected(MenuItem item) {
127 switch (item.getItemId()) {127 switch (item.getItemId()) {
@@ -183,11 +183,13 @@
183 }183 }
184184
185 private void checkIfUbuntuIsInstalled() {185 private void checkIfUbuntuIsInstalled() {
186 // check is there is Ubuntu installed186 // check is there is Ubuntu installed or is upgradeable
187 if (UbuntuInstallService.isUbuntuInstalled(this.getApplicationContext())) {187 if (UbuntuInstallService.isUbuntuInstalled(getApplicationContext())) {
188 // go to launch screen, and kill this activity.188 if(!UbuntuInstallService.isUpgradeable(getApplicationContext())) {
189 LaunchActivity.startFrom(this);189 Log.d(TAG, "go to launch screen, and kill Install activity");
190 finish();190 LaunchActivity.startFrom(this);
191 finish();
192 }
191 }193 }
192 }194 }
193195
@@ -262,7 +264,7 @@
262 // reset progress bar264 // reset progress bar
263 mProgressBar.setProgress(0);265 mProgressBar.setProgress(0);
264 }266 }
265 267
266 TextPickerDialog.OnChannelPicktListener mInstallDialogListener 268 TextPickerDialog.OnChannelPicktListener mInstallDialogListener
267 = new TextPickerDialog.OnChannelPicktListener() {269 = new TextPickerDialog.OnChannelPicktListener() {
268 public void onChannelPicked(Context context, String channel, boolean bootstrap, boolean latest) {270 public void onChannelPicked(Context context, String channel, boolean bootstrap, boolean latest) {
@@ -292,38 +294,38 @@
292 294
293 private void downloadVersion(final Context context, final String channel, final boolean bootstrap) {295 private void downloadVersion(final Context context, final String channel, final boolean bootstrap) {
294 final ProgressDialog progress = ProgressDialog.show(this, 296 final ProgressDialog progress = ProgressDialog.show(this,
295 "Fetching versions", 297 "Fetching versions",
296 "Checking list of availanble versions for choosen channel", true);298 "Checking list of availanble versions for choosen channel", true);
297 new Thread(new Runnable() {299 new Thread(new Runnable() {
298 @Override300 @Override
299 public void run() {301 public void run() {
300 String jsonStr = Utils.httpDownload(UbuntuInstallService.BASE_URL 302 String jsonStr = Utils.httpDownload(UbuntuInstallService.BASE_URL
301 + mAvailableChannels.get(channel));303 + mAvailableChannels.get(channel));
302 // TODO: handle malformed JSON304 // TODO: handle malformed JSON
303 final List<Image> releases = JsonChannelParser.getAvailableReleases(jsonStr, ReleaseType.FULL);305 final List<Image> releases = JsonChannelParser.getAvailableReleases(jsonStr, ReleaseType.FULL);
304 306
305 runOnUiThread(new Runnable() {307 runOnUiThread(new Runnable() {
306 @Override308 @Override
307 public void run() {309 public void run() {
308 progress.dismiss();310 progress.dismiss();
309 // if there are available releases, show number picker311 // if there are available releases, show number picker
310 if (releases.size() != 0 && releases.get(0).files.length != 0) {312 if (releases.size() != 0 && releases.get(0).files.length != 0) {
311 int[] values = new int[releases.size()];313 int[] values = new int[releases.size()];
312 for (int i = 0 ; i < values.length ; ++i) {314 for (int i = 0 ; i < values.length ; ++i) {
313 values[i] = releases.get(i).version;315 values[i] = releases.get(i).version;
314 }316 }
315 new NumberPickerDialog(context, 317 new NumberPickerDialog(context,
316 R.string.version_picker_dialog_title,318 R.string.version_picker_dialog_title,
317 R.string.action_install,319 R.string.action_install,
318 R.string.cancel,320 R.string.cancel,
319 values,321 values,
320 0, 322 0,
321 new NumberPickerDialog.OnNumberPicktListener() {323 new NumberPickerDialog.OnNumberPicktListener() {
322 @Override324 @Override
323 public void onNumberSelected(Context context, int value) {325 public void onNumberSelected(Context context, int value) {
324 startDownload(channel, bootstrap, value);326 startDownload(channel, bootstrap, value);
325 }327 }
326 }).show();;328 }).show();;
327 } 329 }
328 }330 }
329 });331 });
@@ -359,7 +361,7 @@
359 mProgressText.setText("");361 mProgressText.setText("");
360 }362 }
361 }363 }
362 break;364 break;
363 case FETCHING_CHANNELS:365 case FETCHING_CHANNELS:
364 mInstallButton.setText(Html.fromHtml(getResources().getString(R.string.install_button_label_fetching)));366 mInstallButton.setText(Html.fromHtml(getResources().getString(R.string.install_button_label_fetching)));
365 mInstallButton.setEnabled(false);367 mInstallButton.setEnabled(false);
@@ -406,7 +408,7 @@
406 int progress = intent.getIntExtra(UbuntuInstallService.PROGRESS_EXTRA_INT, -1);408 int progress = intent.getIntExtra(UbuntuInstallService.PROGRESS_EXTRA_INT, -1);
407 if (progress != -1) {409 if (progress != -1) {
408 mProgressBar.setProgress(progress);410 mProgressBar.setProgress(progress);
409 Log.v(TAG, "Progress:" + progress);411 Log.d(TAG, "Progress: " + progress);
410 }412 }
411 if (p != null && !p.equals("")) {413 if (p != null && !p.equals("")) {
412 // update terminal with progress text414 // update terminal with progress text
@@ -440,7 +442,7 @@
440 }442 }
441 updateUiElements();443 updateUiElements();
442 }444 }
443 445
444 // Handle download result446 // Handle download result
445 } else if(action.equals(UbuntuInstallService.DOWNLOAD_RESULT)) {447 } else if(action.equals(UbuntuInstallService.DOWNLOAD_RESULT)) {
446 int r = intent.getIntExtra(UbuntuInstallService.DOWNLOAD_RESULT_EXTRA_INT, -1);448 int r = intent.getIntExtra(UbuntuInstallService.DOWNLOAD_RESULT_EXTRA_INT, -1);
447449
=== modified file 'src/com/canonical/ubuntu/installer/LaunchActivity.java'
--- src/com/canonical/ubuntu/installer/LaunchActivity.java 2013-12-19 09:36:28 +0000
+++ src/com/canonical/ubuntu/installer/LaunchActivity.java 2013-12-26 07:18:46 +0000
@@ -8,6 +8,7 @@
8import android.content.Intent;8import android.content.Intent;
9import android.content.IntentFilter;9import android.content.IntentFilter;
10import android.os.Bundle;10import android.os.Bundle;
11import android.util.Log;
11import android.view.Menu;12import android.view.Menu;
12import android.view.MenuItem;13import android.view.MenuItem;
13import android.view.View;14import android.view.View;
@@ -16,7 +17,6 @@
1617
17import com.canonical.ubuntu.widget.UbuntuButton;18import com.canonical.ubuntu.widget.UbuntuButton;
1819
19
20public class LaunchActivity extends Activity {20public class LaunchActivity extends Activity {
21 private static final String TAG = "UbuntuLaunchActivity";21 private static final String TAG = "UbuntuLaunchActivity";
22 private UbuntuButton mRebootButton;22 private UbuntuButton mRebootButton;
@@ -28,7 +28,7 @@
28 private TextView mTextDescriptionLabel;28 private TextView mTextDescriptionLabel;
29 private TextView mTextDescription;29 private TextView mTextDescription;
30 private VersionInfo mUbuntuVersion;30 private VersionInfo mUbuntuVersion;
31 31
32 @Override32 @Override
33 protected void onCreate(Bundle savedInstanceState) {33 protected void onCreate(Bundle savedInstanceState) {
34 super.onCreate(savedInstanceState);34 super.onCreate(savedInstanceState);
@@ -48,8 +48,11 @@
48 mTextTitle.setText(R.string.launch_title);48 mTextTitle.setText(R.string.launch_title);
49 mRebootButton.setText(R.string.reboot_button_label);49 mRebootButton.setText(R.string.reboot_button_label);
50 fillInstalledVersionInfo();50 fillInstalledVersionInfo();
51
52 // check the upgradeable image.
53 startService(new Intent(UbuntuInstallService.IS_UBUNTU_UPGRADABLE));
51 }54 }
52 55
53 @Override56 @Override
54 public void onResume() {57 public void onResume() {
55 super.onResume();58 super.onResume();
@@ -62,7 +65,7 @@
62 filter.addAction(UbuntuInstallService.VERSION_UPDATE);65 filter.addAction(UbuntuInstallService.VERSION_UPDATE);
63 registerReceiver(mServiceObserver, filter);66 registerReceiver(mServiceObserver, filter);
64 }67 }
65 68
66 @Override69 @Override
67 public void onPause() {70 public void onPause() {
68 super.onPause();71 super.onPause();
@@ -113,7 +116,19 @@
113 }116 }
114 return super.onOptionsItemSelected(item);117 return super.onOptionsItemSelected(item);
115 }118 }
116 119
120 /**
121 * Create a dialog for confirmation.
122 * @param title
123 * @param positiveButton
124 * @param negativeButton
125 * @param action
126 * @param toastText
127 * @param choiceItemsArray
128 * @param defaultChoiceValues
129 * @param choiceClickListener
130 * @return AlertDialog
131 */
117 private AlertDialog createConfirmationDialog(final int title, 132 private AlertDialog createConfirmationDialog(final int title,
118 final int positiveButton, 133 final int positiveButton,
119 final int negativeButton, 134 final int negativeButton,
@@ -151,7 +166,10 @@
151 mTextVersionLabel.setText(R.string.label_version);166 mTextVersionLabel.setText(R.string.label_version);
152 mTextDescriptionLabel.setText(R.string.label_description);167 mTextDescriptionLabel.setText(R.string.label_description);
153 }168 }
154 169
170 /**
171 * Get installed version to check Ubuntu is installed
172 */
155 private void ensureUbuntuIsInstalled() {173 private void ensureUbuntuIsInstalled() {
156 VersionInfo v = UbuntuInstallService.getInstalledVersion(this.getApplicationContext());174 VersionInfo v = UbuntuInstallService.getInstalledVersion(this.getApplicationContext());
157 if (v == null) {175 if (v == null) {
@@ -177,6 +195,11 @@
177 String action = intent.getAction();195 String action = intent.getAction();
178 if (action.equals(UbuntuInstallService.VERSION_UPDATE)) {196 if (action.equals(UbuntuInstallService.VERSION_UPDATE)) {
179 ensureUbuntuIsInstalled();197 ensureUbuntuIsInstalled();
198 if(UbuntuInstallService.isUpgradeable(getApplicationContext())) {
199 Log.d(TAG, "Found upgradeable file, kill LaunchActivity");
200 InstallActivity.startFrom(context);
201 finish();
202 }
180 }203 }
181 }204 }
182 };205 };
183206
=== modified file 'src/com/canonical/ubuntu/installer/UbuntuInstallService.java'
--- src/com/canonical/ubuntu/installer/UbuntuInstallService.java 2013-12-24 09:14:25 +0000
+++ src/com/canonical/ubuntu/installer/UbuntuInstallService.java 2013-12-26 07:18:46 +0000
@@ -9,6 +9,7 @@
9import java.net.MalformedURLException;9import java.net.MalformedURLException;
10import java.net.URL;10import java.net.URL;
11import java.net.URLConnection;11import java.net.URLConnection;
12import java.util.ArrayList;
12import java.util.Collections;13import java.util.Collections;
13import java.util.HashMap;14import java.util.HashMap;
14import java.util.Iterator;15import java.util.Iterator;
@@ -90,6 +91,7 @@
90 public static final String INSTALL_UBUNTU = "com.canonical.ubuntuinstaller.UbuntuInstallService.INSTALL_UBUNTU";91 public static final String INSTALL_UBUNTU = "com.canonical.ubuntuinstaller.UbuntuInstallService.INSTALL_UBUNTU";
91 public static final String CANCEL_INSTALL = "com.canonical.ubuntuinstaller.UbuntuInstallService.CANCEL_INSTALL";92 public static final String CANCEL_INSTALL = "com.canonical.ubuntuinstaller.UbuntuInstallService.CANCEL_INSTALL";
92 public static final String UNINSTALL_UBUNTU = "com.canonical.ubuntuinstaller.UbuntuInstallService.UINSTALL_UBUNTU";93 public static final String UNINSTALL_UBUNTU = "com.canonical.ubuntuinstaller.UbuntuInstallService.UINSTALL_UBUNTU";
94 public static final String IS_UBUNTU_UPGRADABLE = "com.canonical.ubuntuinstaller.UbuntuInstallService.IS_UBUNTU_UPGRADABLE";
93 public static final String UNINSTALL_UBUNTU_EXTRA_REMOVE_USER_DATA = "user_data";95 public static final String UNINSTALL_UBUNTU_EXTRA_REMOVE_USER_DATA = "user_data";
94 public static final String CHECK_FOR_UPDATE = "com.canonical.ubuntuinstaller.UbuntuInstallService.CHECK_FOR_UPDATE";96 public static final String CHECK_FOR_UPDATE = "com.canonical.ubuntuinstaller.UbuntuInstallService.CHECK_FOR_UPDATE";
95 public static final String DELETE_UBUNTU_USER_DATA = "com.canonical.ubuntuinstaller.UbuntuInstallService.DELETE_USER_DATA";97 public static final String DELETE_UBUNTU_USER_DATA = "com.canonical.ubuntuinstaller.UbuntuInstallService.DELETE_USER_DATA";
@@ -151,6 +153,7 @@
151 private static final String TAR = "u_tar";153 private static final String TAR = "u_tar";
152 private static final String ANDROID_LOOP_MOUNT = "aloopmount";154 private static final String ANDROID_LOOP_MOUNT = "aloopmount";
153 private static final String ANDROID_BOOTMGR = "bootmgr";155 private static final String ANDROID_BOOTMGR = "bootmgr";
156 private static final String UPGRADECHECKER = "upgrade-checker";
154 private static final String UPDATE_SCRIPT = "system-image-upgrader";157 private static final String UPDATE_SCRIPT = "system-image-upgrader";
155 private static final String ARCHIVE_MASTER = "archive-master.tar.xz";158 private static final String ARCHIVE_MASTER = "archive-master.tar.xz";
156 private static final String ARCHIVE_MASTER_ASC = "archive-master.tar.xz.asc";159 private static final String ARCHIVE_MASTER_ASC = "archive-master.tar.xz.asc";
@@ -179,6 +182,7 @@
179 private static final int PROGRESS_MKSWAP_ADJUSTMENT = 17; // equivalent of time tar --checkpoint=200182 private static final int PROGRESS_MKSWAP_ADJUSTMENT = 17; // equivalent of time tar --checkpoint=200
180 private PowerManager mPowerManager;183 private PowerManager mPowerManager;
181 private PowerManager.WakeLock mWakeLock;184 private PowerManager.WakeLock mWakeLock;
185 // FIXME make workPath in Cache a private function
182 private boolean workPathInCache = false;186 private boolean workPathInCache = false;
183 private String mRootOfWorkPath;187 private String mRootOfWorkPath;
184 private boolean mIsCanceled;188 private boolean mIsCanceled;
@@ -210,7 +214,16 @@
210 }214 }
211215
212 public ESumNotMatchException(String string) {216 public ESumNotMatchException(String string) {
213 // TODO Auto-generated constructor stub217 super(string);
218 }
219 };
220
221 class EShellExecException extends Exception {
222 public EShellExecException(){
223 super();
224 }
225
226 public EShellExecException(String string) {
214 super(string);227 super(string);
215 }228 }
216 };229 };
@@ -218,7 +231,7 @@
218 public UbuntuInstallService() {231 public UbuntuInstallService() {
219 super(TAG);232 super(TAG);
220 }233 }
221 234
222 @Override235 @Override
223 public void onCreate() {236 public void onCreate() {
224 super.onCreate();237 super.onCreate();
@@ -231,7 +244,7 @@
231 mRootOfWorkPath = "/cache";244 mRootOfWorkPath = "/cache";
232 workPathInCache = true;245 workPathInCache = true;
233 } else {246 } else {
234 mRootOfWorkPath = getFilesDir().toString(); // "/data/data/com.canonical.ubuntuinstaller/files";247 mRootOfWorkPath = getFilesDir().toString(); // "/data/data/com.canonical.ubuntu.installer/files";
235 workPathInCache = false;248 workPathInCache = false;
236 }249 }
237 mInstallerState = InstallerState.READY;250 mInstallerState = InstallerState.READY;
@@ -281,6 +294,12 @@
281 } else if (action.equals(INSTALL_UBUNTU)) {294 } else if (action.equals(INSTALL_UBUNTU)) {
282 updateInstallerState(InstallerState.INSTALLING);295 updateInstallerState(InstallerState.INSTALLING);
283 result = doInstallUbuntu(intent);296 result = doInstallUbuntu(intent);
297 } else if (action.equals(IS_UBUNTU_UPGRADABLE)) {
298 // check if the upgradeable images available.
299 if(findInstallCommand()) {
300 Log.d(TAG, "There is a upgradeable file. send VERSION_UPDATE");
301 result = new Intent(VERSION_UPDATE);
302 }
284 } else if (action.equals(CANCEL_INSTALL)) {303 } else if (action.equals(CANCEL_INSTALL)) {
285 // install should be already cancelled, try to delete it now304 // install should be already cancelled, try to delete it now
286 updateInstallerState(InstallerState.UNINSTALLING);305 updateInstallerState(InstallerState.UNINSTALLING);
@@ -309,7 +328,7 @@
309328
310 private Intent doGetChannelList(Intent intent) {329 private Intent doGetChannelList(Intent intent) {
311 Intent result = new Intent(AVAILABLE_CHANNELS);330 Intent result = new Intent(AVAILABLE_CHANNELS);
312 // 331
313 HashMap<String, String> channels= new HashMap<String, String>();332 HashMap<String, String> channels= new HashMap<String, String>();
314 boolean includeHidden = getSharedPreferences( SHARED_PREF, Context.MODE_PRIVATE).getBoolean(PREF_KEY_DEVELOPER, false);333 boolean includeHidden = getSharedPreferences( SHARED_PREF, Context.MODE_PRIVATE).getBoolean(PREF_KEY_DEVELOPER, false);
315 String deviceModel = Build.DEVICE.toLowerCase(Locale.US);334 String deviceModel = Build.DEVICE.toLowerCase(Locale.US);
@@ -365,149 +384,74 @@
365 }384 }
366385
367 private Intent doInstallUbuntu(Intent intent) {386 private Intent doInstallUbuntu(Intent intent) {
368 Log.w(TAG, "doInstallUbuntu"); 387 Log.w(TAG, "doInstallUbuntu");
369 Intent result = new Intent(INSTALL_RESULT);388 Intent result = new Intent(INSTALL_RESULT);
389
370 // get update command file390 // get update command file
371 SharedPreferences pref = getSharedPreferences( SHARED_PREF, Context.MODE_PRIVATE);391 String updateCommand = getUpdateCommand();
372 String updateCommand = pref.getString(PREF_KEY_UPDATE_COMMAND,"");392
393 // 1. check if update command exist.
394 // 2. However, if the udpate command is in "/cache",
395 // the app can not access to /cache sometimes.
396 if (updateCommand.equals("") ||
397 (!new File(updateCommand).exists() &&
398 !updateCommand.startsWith("/cache"))) {
399 return handleInstallFail(result, -1, "Missing update command");
400 }
401
402 SharedPreferences pref = getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE);
373 mTotalSize = pref.getInt(PREF_KEY_ESTIMATED_CHECKPOINTS, 0);403 mTotalSize = pref.getInt(PREF_KEY_ESTIMATED_CHECKPOINTS, 0);
374 mLastSignalledProgress = 0;404 mLastSignalledProgress = 0;
375 if (updateCommand.equals("") || ! new File(updateCommand).exists()) {405
376 return handleInstallFail(result, -1, "Missing update command");406 List<String> shellcmds = new ArrayList<String>();
377 }407 {
378 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ubuntu-installing");408 shellcmds.add("echo Installing\n");
379 try {409 // run system-image-upgrader.
380 File rootFolder = new File(mRootOfWorkPath);410 shellcmds.add(String.format("%s %s %s\n",
381 File supportingFiles = new File(rootFolder, RELEASE_FOLDER);411 UPDATE_SCRIPT,
382 broadcastProgress(0, "Extracting supporting files");412 updateCommand,
383 try {413 getFilesDir().getAbsolutePath()
384 Utils.extractExecutableAsset(this, BUSYBOX, supportingFiles.toString(), true);414 ));
385 Utils.extractExecutableAsset(this, ANDROID_BOOTMGR, supportingFiles.toString(), true);415 // Only backup original recovery, when there is no backuped file.
386 Utils.extractExecutableAsset(this, GPG, supportingFiles.toString(), true);416 if(!new File(getFilesDir().toString(), ANDROID_REOCVERY_IMG).exists()) {
387 Utils.extractExecutableAsset(this, TAR, supportingFiles.toString(), true);417 shellcmds.add(String.format("%s -b %s %s/%s\n",
388 Utils.extractExecutableAsset(this, UPDATE_SCRIPT, supportingFiles.toString(), true);
389 Utils.extractExecutableAsset(this, ANDROID_LOOP_MOUNT, supportingFiles.toString(), true);
390 Utils.extractExecutableAsset(this, ARCHIVE_MASTER, supportingFiles.toString(), false);
391 Utils.extractExecutableAsset(this, ARCHIVE_MASTER_ASC, supportingFiles.toString(), false);
392 Utils.extractExecutableAsset(this, U_REBOOT_APP, supportingFiles.toString(), false);
393 Utils.extractExecutableAsset(this, U_REBOOT_APP_ASC, supportingFiles.toString(), false);
394 } catch (IOException e) {
395 e.printStackTrace();
396 return handleInstallFail(result, -1, "Failed to extract supporting assets");
397 }
398 // get superuser and run update script
399 broadcastProgress(-1, "Starting update script");
400 try {
401 Process process = Runtime.getRuntime().exec("su", null, supportingFiles);
402 DataOutputStream os = new DataOutputStream(process.getOutputStream());
403 // debug purpose.
404 // os.writeBytes("set -x\n");
405 // make sure we are in work folder
406 os.writeBytes(String.format("cd %s\n", supportingFiles.getAbsolutePath()));
407 os.writeBytes("echo \"SU granted\"\n");
408 // run system-image-upgrader.
409 os.writeBytes(String.format("sh %s %s %s\n",
410 UPDATE_SCRIPT,
411 updateCommand,
412 getFilesDir().getAbsolutePath()
413 ));
414 os.writeBytes(String.format("cd %s\n", supportingFiles.getAbsolutePath()));
415 // backup original recovery.
416 if(!new File(getFilesDir().toString(), ANDROID_REOCVERY_IMG).exists()) {
417 os.writeBytes(String.format("./%s -b %s %s/%s\n",
418 ANDROID_BOOTMGR,
419 Utils.getRecoveryPartitionPath(),
420 getFilesDir().getAbsolutePath(),
421 ANDROID_REOCVERY_IMG
422 ));
423 }
424 os.writeBytes(String.format("cd %s\n", supportingFiles.getAbsolutePath()));
425 // overwrite the recovery partition.
426 os.writeBytes(String.format("./%s -b %s/%s %s\n",
427 ANDROID_BOOTMGR,418 ANDROID_BOOTMGR,
419 Utils.getRecoveryPartitionPath(),
428 getFilesDir().getAbsolutePath(),420 getFilesDir().getAbsolutePath(),
429 UBUNTU_BOOT_IMG,421 ANDROID_REOCVERY_IMG
430 Utils.getRecoveryPartitionPath()
431 ));422 ));
432423 }
433 // close terminal424 // overwrite the recovery partition.
434 os.writeBytes("exit\n");425 shellcmds.add(String.format("%s -b %s/%s %s\n",
435 os.flush();426 ANDROID_BOOTMGR,
436 InputStream is = process.getInputStream();427 getFilesDir().getAbsolutePath(),
437 InputStream es = process.getErrorStream();428 UBUNTU_BOOT_IMG,
438 int read = 0;429 Utils.getRecoveryPartitionPath()
439 byte[] buff = new byte[4096];430 ));
440 boolean running = true;431 shellcmds.add("exit");
441 boolean scriptExecuted = false;432 }
442 do {433
443 while( is.available() > 0) {434 broadcastProgress(-1, "Starting update script - " + updateCommand);
444 read = is.read(buff);435 try {
445 if ( read <= 0 ) {436 int ret = executeSUCommands(shellcmds.toArray(new String[shellcmds.size()]));
446 break;437 result.putExtra(INSTALL_RESULT_EXTRA_INT, ret);
447 }438 } catch (EShellExecException e) {
448 scriptExecuted = true;439 return handleInstallFail(result, -1, e.getMessage());
449 String seg = new String(buff,0,read);440 }
450 Log.d(TAG, "Script Output: " + seg);441
451 broadcastProgress(-1, seg);442 // we done.
452 }443 cleanUpdateCommand();
453 while( es.available() > 0) {
454 read = es.read(buff);
455 if ( read <= 0 ) {
456 break;
457 }
458 scriptExecuted = true;
459 String seg = new String(buff,0,read);
460 if (seg.startsWith("SWAP-file-missing")) {
461 // this is signal that we will also install swap, adjust progress estimates
462 mTotalSize += PROGRESS_MKSWAP_ADJUSTMENT + PROGRESS_SWAP_CREATION_ADJUSTMENT;
463 } else {
464 mProgress++;
465 if ( mLastSignalledProgress < (mProgress * 100 / mTotalSize)) {
466 // update and signal new progress
467 mLastSignalledProgress = (int) (mProgress * 100 / mTotalSize);
468 broadcastProgress(mLastSignalledProgress, null);
469 }
470 }
471 Log.d(TAG, "Stderr Output: " + seg);
472 }
473 try {
474 int ret = process.exitValue();
475 Log.v(TAG, "Worker thread exited with: " + ret);
476 // if script was not executed, then user did not granted SU permissions
477 if (ret == 255 || !scriptExecuted ) {
478 return handleInstallFail(result, -1, "Failed to get SU permissions");
479 } else if (ret != 0) {
480 return handleInstallFail(result, -1, "Instalation failed");
481 }
482 running =false;
483 } catch (IllegalThreadStateException e) {
484 // still running, wait a bit
485 try { Thread.sleep(200); } catch(Exception ex) {}
486 }
487 } while (running);
488 } catch (IOException e) {
489 e.printStackTrace();
490 Log.w(TAG, "Update failed");
491 return handleInstallFail(result, -1, "Install failed");
492 }
493 } finally {
494 if (mWakeLock != null && mWakeLock.isHeld()) {
495 mWakeLock.release();
496 }
497 }
498 SharedPreferences.Editor editor = pref.edit();
499 editor.putString(PREF_KEY_UPDATE_COMMAND, "");
500 VersionInfo v = new VersionInfo(pref, PREF_KEY_DOWNLOADED_VERSION);444 VersionInfo v = new VersionInfo(pref, PREF_KEY_DOWNLOADED_VERSION);
501 v.storeVersion(editor, PREF_KEY_INSTALLED_VERSION);445 v.storeVersion(pref.edit(), PREF_KEY_INSTALLED_VERSION);
502 mProgress = 100;446 mProgress = 100;
503 result.putExtra(INSTALL_RESULT_EXTRA_INT, 0);
504 return result;447 return result;
505 }448 }
506 449
507 private Intent handleInstallFail(Intent i, int res, String failReason) {450 private Intent handleInstallFail(Intent i, int res, String failReason) {
508 i.putExtra(INSTALL_RESULT_EXTRA_INT, -1);451 i.putExtra(INSTALL_RESULT_EXTRA_INT, -1);
509 i.putExtra(INSTALL_RESULT_EXTRA_STR, "Missing update command");452 i.putExtra(INSTALL_RESULT_EXTRA_STR, failReason);
510 doUninstallUbuntu(i);453 // we don't want to unstainll if we failed to install a update.
454 // doUninstallUbuntu(i);
511 return i;455 return i;
512 }456 }
513457
@@ -516,9 +460,11 @@
516 File updateCommand = new File(workingFolder, UPDATE_COMMAND);460 File updateCommand = new File(workingFolder, UPDATE_COMMAND);
517 Intent result = new Intent(VERSION_UPDATE);461 Intent result = new Intent(VERSION_UPDATE);
518 boolean removeUserData = intent.getBooleanExtra(UNINSTALL_UBUNTU_EXTRA_REMOVE_USER_DATA, false);462 boolean removeUserData = intent.getBooleanExtra(UNINSTALL_UBUNTU_EXTRA_REMOVE_USER_DATA, false);
463 Log.d(TAG, "doUninstallUbuntu");
519464
520 String format_cmd = null;465 String format_cmd = null;
521 if (removeUserData) {466 if (removeUserData) {
467 Log.d(TAG, "removing user data.");
522 format_cmd = String.format("echo \"%s %s\n %s %s\" > %s\n",468 format_cmd = String.format("echo \"%s %s\n %s %s\" > %s\n",
523 COMMAND_FORMAT, PARTITION_DATA,469 COMMAND_FORMAT, PARTITION_DATA,
524 COMMAND_UMOUNT, PARTITION_SYSTEM,470 COMMAND_UMOUNT, PARTITION_SYSTEM,
@@ -532,41 +478,53 @@
532 // 1. force unmount478 // 1. force unmount
533 // 2. restore android recovery partition, and deleted it.479 // 2. restore android recovery partition, and deleted it.
534 // 3. delete system.img and SWAP.img.480 // 3. delete system.img and SWAP.img.
535 int r = executeSUCommands(result, "result", new String[]{481 try {
536 format_cmd,482 int r = executeSUCommands(
537 ("sh " + UPDATE_SCRIPT 483 new String[]{
538 + " " + updateCommand.getAbsolutePath() 484 ("echo Uninstalling\n"),
539 + " " + getFilesDir().toString() + "\n"),485 format_cmd,
540 String.format("./%s -b %s/%s %s\n",486 ("sh " + UPDATE_SCRIPT
541 ANDROID_BOOTMGR,487 + " " + updateCommand.getAbsolutePath()
542 getFilesDir().toString(),488 + " " + getFilesDir().toString() + "\n"),
543 ANDROID_REOCVERY_IMG,489 String.format("%s -b %s/%s %s || true\n",
544 Utils.getRecoveryPartitionPath()),490 ANDROID_BOOTMGR,
545 (String.format("rm -f %s/%s\n", getFilesDir().toString(), ANDROID_REOCVERY_IMG)),491 getFilesDir().toString(),
546 ("rm -rf /data/system.img\n"),492 ANDROID_REOCVERY_IMG,
547 ("rm -rf /data/SWAP.img\n"),493 Utils.getRecoveryPartitionPath()),
548 } );494 (String.format("rm -f %s/%s || true\n", getFilesDir().toString(), ANDROID_REOCVERY_IMG)),
549 if (r == 0) {495 ("rm -rf /data/system.img || true\n"),
550 // delete installed version in preferences496 ("rm -rf /data/SWAP.img || true\n"),
551 SharedPreferences pref = getSharedPreferences( SHARED_PREF, Context.MODE_PRIVATE);497 } );
552 SharedPreferences.Editor editor = pref.edit();498
553 editor.putString(PREF_KEY_UPDATE_COMMAND, "");499 if (r == 0) {
554 VersionInfo.storeEmptyVersion(editor, PREF_KEY_INSTALLED_VERSION);500 // delete installed version in preferences
555 editor.commit();501 cleanUpdateCommand();
502 VersionInfo.storeEmptyVersion(
503 getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE).edit(), PREF_KEY_INSTALLED_VERSION);
504 }
505 result.putExtra("result", r);
506 } catch (EShellExecException e) {
507 result.putExtra("result", -1);
556 }508 }
557 result.putExtra("result", r);509
558 return result;510 return result;
559 }511 }
560512
561 private Intent doDeleteUbuntuUserData(Intent intent) {513 private Intent doDeleteUbuntuUserData(Intent intent) {
562 Intent result = new Intent(VERSION_UPDATE);514 Intent result = new Intent(VERSION_UPDATE);
563 File workingFolder = new File(mRootOfWorkPath, TEMP_FOLDER);515 File workingFolder = new File(mRootOfWorkPath, TEMP_FOLDER);
564 File updateCommand = new File(workingFolder, UPDATE_COMMAND); 516 File updateCommand = new File(workingFolder, UPDATE_COMMAND);
565 int r = executeSUCommands(result, "fail_description", new String[]{517
518 try {
519 int r = executeSUCommands(new String[]{
566 String.format("echo \"%s %s\" > %s\n", COMMAND_FORMAT, PARTITION_DATA, UPDATE_COMMAND),520 String.format("echo \"%s %s\" > %s\n", COMMAND_FORMAT, PARTITION_DATA, UPDATE_COMMAND),
567 ("sh " + UPDATE_SCRIPT + " " + updateCommand.getAbsolutePath() + " " + getFilesDir().toString() + "\n")521 ("sh " + UPDATE_SCRIPT + " " + updateCommand.getAbsolutePath() + " " + getFilesDir().toString() + "\n")
568 } );522 } );
569 result.putExtra("result", r);523 result.putExtra("result", r);
524 } catch (EShellExecException e) {
525 result.putExtra("fail_description", e.getMessage());
526 result.putExtra("result", -1);
527 }
570 return result;528 return result;
571 }529 }
572530
@@ -579,75 +537,83 @@
579 // FIXME: in Android 4.4, we do not get power manager permission.537 // FIXME: in Android 4.4, we do not get power manager permission.
580 // try it with SU permissions538 // try it with SU permissions
581 try {539 try {
582 Process process = Runtime.getRuntime().exec("su", null, getFilesDir());540 int r = executeSUCommands(new String[] {
583 DataOutputStream os = new DataOutputStream(process.getOutputStream());541 String.format("%s -b %s/%s %s || true\n",
584 542 ANDROID_BOOTMGR,
585 Utils.extractExecutableAsset(this, ANDROID_BOOTMGR, getFilesDir().toString(), true);543 getFilesDir().getAbsolutePath(),
586 // overwrite the recovery partition.544 UBUNTU_BOOT_IMG,
587 os.writeBytes(String.format("%s/%s -b %s/%s %s\n",545 Utils.getRecoveryPartitionPath()),
588 getFilesDir().getAbsolutePath(),546 "reboot recovery\n"
589 ANDROID_BOOTMGR,547 });
590 getFilesDir().getAbsolutePath(),548 if(r != 255) {
591 UBUNTU_BOOT_IMG,549 Utils.showToast(this.getApplicationContext(), "Rebooting to Ubuntu");
592 Utils.getRecoveryPartitionPath()550 } else {
593 ));551 Utils.showToast(this.getApplicationContext(), "No permissions to reboot to recovery");
594 os.writeBytes("reboot recovery\n");
595 os.flush();
596 try {
597 process.waitFor();
598 if (process.exitValue() != 255) {
599 Utils.showToast(this.getApplicationContext(), "Rebooting to Ubuntu");
600 } else {
601 Utils.showToast(this.getApplicationContext(), "No permissions to reboot to recovery");
602 }
603 } catch (InterruptedException ee) {
604 Utils.showToast(this.getApplicationContext(), "No permissions to reboot to recovery");
605 }552 }
606 } catch (IOException eee) {553 } catch (EShellExecException e1) {
607 Utils.showToast(this.getApplicationContext(), "No permissions to reboot to recovery");554 Utils.showToast(this.getApplicationContext(), "No permissions to reboot to recovery");
608 }555 }
609 }556 }
610 }557 }
611558
612 /**559 /**
613 * 560 * This command exec commands in the working folder with supporting utils.
614 * @param result intent to update with result text561 *
615 * @param resultExtraText 562 * @param commands commands to be executed
616 * @param commands commands to execute563 * @return shell script exit value.
617 * @return 0 for success and -1 for fail564 * @throws EShellExecException
618 */565 */
619 private int executeSUCommands(Intent result, String resultExtraText, String[] commands) {566 private int executeSUCommands(String[] commands) throws EShellExecException {
567 int ret = 0;
620 File rootFolder = new File(mRootOfWorkPath);568 File rootFolder = new File(mRootOfWorkPath);
621 File workingFolder = new File(rootFolder, TEMP_FOLDER);569 File workingFolder = new File(rootFolder, TEMP_FOLDER);
570 String workingFolderPath = workingFolder.getAbsolutePath();
571
622 if (!workingFolder.exists() && !workingFolder.mkdir()) {572 if (!workingFolder.exists() && !workingFolder.mkdir()) {
623 result.putExtra(resultExtraText, "Failed to create working folder");573 throw(new EShellExecException("Failed to create working folder"));
624 return -1;
625 }574 }
575
576 broadcastProgress(0, "Extracting supporting files at " + workingFolder.getAbsolutePath());
626 try {577 try {
627 Utils.extractExecutableAsset(this, UPDATE_SCRIPT, workingFolder.toString(), true);578 // extract utils into working folder.
628 Utils.extractExecutableAsset(this, ANDROID_LOOP_MOUNT, workingFolder.toString(), true);579 Utils.extractExecutableAsset(this, ANDROID_BOOTMGR, workingFolderPath, true);
629 Utils.extractExecutableAsset(this, ANDROID_BOOTMGR, workingFolder.toString(), true);580 Utils.extractExecutableAsset(this, ANDROID_LOOP_MOUNT, workingFolderPath, true);
581 Utils.extractExecutableAsset(this, ARCHIVE_MASTER_ASC, workingFolderPath, false);
582 Utils.extractExecutableAsset(this, ARCHIVE_MASTER, workingFolderPath, false);
583 Utils.extractExecutableAsset(this, BUSYBOX, workingFolderPath, true);
584 Utils.extractExecutableAsset(this, GPG, workingFolderPath, true);
585 Utils.extractExecutableAsset(this, TAR, workingFolderPath, true);
586 Utils.extractExecutableAsset(this, UPDATE_SCRIPT, workingFolderPath, true);
587 Utils.extractExecutableAsset(this, U_REBOOT_APP_ASC, workingFolderPath, false);
588 Utils.extractExecutableAsset(this, U_REBOOT_APP, workingFolderPath, false);
589 Utils.extractExecutableAsset(this, UPGRADECHECKER, workingFolderPath, true);
630 } catch (IOException e) {590 } catch (IOException e) {
631 e.printStackTrace();591 throw(new EShellExecException("Failed to extract supporting utils"));
632 result.putExtra(resultExtraText, "Failed to extract supporting files");
633 return -1;
634 }592 }
635593
636 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ubuntu-installing");594 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "shelling");
637 try {595 try {
638 Process process = Runtime.getRuntime().exec("su", null, workingFolder);596 Process process = Runtime.getRuntime().exec("su", null, workingFolder);
639 DataOutputStream os = new DataOutputStream(process.getOutputStream());597 DataOutputStream os = new DataOutputStream(process.getOutputStream());
598 // debug purpose.
599 os.writeBytes("set -x\n");
600
601 os.writeBytes("echo \"SU granted\"\n");
640 // make sure we are in work folder602 // make sure we are in work folder
641 os.writeBytes("echo \"SU granted\"\n");603 os.writeBytes(String.format("cd %s\n", workingFolder.getAbsolutePath()));
642 for (String c : commands) {604 // setup search path for commands
643 Log.v(TAG, "Executing:" + c);605 os.writeBytes(String.format("export PATH=%s:$PATH\n", workingFolder.getAbsolutePath()));
644 // make sure we are always at working folder before running next command606
645 os.writeBytes(String.format("cd %s\n", workingFolder.getAbsolutePath()));607 for (String cmd : commands) {
646 os.writeBytes(c);608 Log.d(TAG, "Executing: " + cmd + "\n");
609 os.writeBytes(cmd + "\n");
610 os.writeBytes("CMDSTATES=$?\n");
647 }611 }
612 // clean up supporting utils.
648 os.writeBytes(String.format("rm -rf %s\n", workingFolder.getAbsolutePath()));613 os.writeBytes(String.format("rm -rf %s\n", workingFolder.getAbsolutePath()));
649 os.writeBytes("exit\n");614 os.writeBytes("exit $CMDSTATES\n");
650 os.flush();615 os.flush();
616
651 int read = 0;617 int read = 0;
652 byte[] buff = new byte[4096];618 byte[] buff = new byte[4096];
653 InputStream is = process.getInputStream();619 InputStream is = process.getInputStream();
@@ -661,7 +627,7 @@
661 break;627 break;
662 }628 }
663 scriptExecuted = true;629 scriptExecuted = true;
664 String seg = new String(buff,0,read);630 String seg = new String(buff, 0, read);
665 Log.i(TAG, "Script Output: " + seg);631 Log.i(TAG, "Script Output: " + seg);
666 broadcastProgress(-1, seg);632 broadcastProgress(-1, seg);
667 }633 }
@@ -672,37 +638,44 @@
672 }638 }
673 scriptExecuted = true;639 scriptExecuted = true;
674 String seg = new String(buff,0,read);640 String seg = new String(buff,0,read);
641
642 if (seg.startsWith("SWAP-file-missing")) {
643 // this is signal that we will also install swap, adjust progress estimates
644 mTotalSize += PROGRESS_MKSWAP_ADJUSTMENT + PROGRESS_SWAP_CREATION_ADJUSTMENT;
645 } else {
646 mProgress++;
647 if (mTotalSize > 0 && mLastSignalledProgress < (mProgress * 100 / mTotalSize)) {
648 // update and signal new progress
649 mLastSignalledProgress = (int) (mProgress * 100 / mTotalSize);
650 broadcastProgress(mLastSignalledProgress, null);
651 }
652 }
653
675 Log.i(TAG, "Stderr Output: " + seg);654 Log.i(TAG, "Stderr Output: " + seg);
676 }655 }
677 try {656 try {
678 int ret = process.exitValue();657 ret = process.exitValue();
679 Log.v(TAG, "Worker thread exited with: " + ret);658 Log.d(TAG, "Worker thread exited with: " + ret);
680 // if script was not executed, then user did not granted SU permissions659 // if script was not executed, then user did not granted SU permissions
681 if (ret == 255 || !scriptExecuted ) {660 if (!scriptExecuted) {
682 result.putExtra(resultExtraText, "Failed to get SU permissions");661 throw new EShellExecException("Failed to get SU permissions");
683 return -1;
684 } else if (ret != 0) {
685 result.putExtra(resultExtraText, "Script failed");
686 return -1;
687 }662 }
688 running =false;663 running = false;
689 } catch (IllegalThreadStateException e) {664 } catch (IllegalThreadStateException e) {
690 // still running, wait a bit665 // still running, wait a bit
691 try { Thread.sleep(200); } catch(Exception ex) {}666 try { Thread.sleep(200); } catch(Exception ex) {}
692 }667 }
693 } while (running);668 } while (running);
694 }catch (IOException e) {669 } catch (IOException e) {
695 e.printStackTrace();670 throw(new EShellExecException("Script execution exception " + e.getMessage()));
696 result.putExtra(resultExtraText, "Script execution exception");
697 return -1;
698 } finally {671 } finally {
699 if (mWakeLock != null && mWakeLock.isHeld()) {672 if (mWakeLock != null && mWakeLock.isHeld()) {
700 mWakeLock.release();673 mWakeLock.release();
701 }674 }
702 }675 }
703 return 0;676 return ret;
704 }677 }
705 678
706 private Intent doDownloadRelease(Intent intent) {679 private Intent doDownloadRelease(Intent intent) {
707 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ufa-downloading");680 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ufa-downloading");
708 mIsCanceled = false;681 mIsCanceled = false;
@@ -780,7 +753,7 @@
780 }753 }
781754
782 // make sure release folder exists755 // make sure release folder exists
783 File release = new File(rootFolder,RELEASE_FOLDER);756 File release = new File(rootFolder, RELEASE_FOLDER);
784 release.mkdir();757 release.mkdir();
785 // download release758 // download release
786 long time = System.currentTimeMillis();759 long time = System.currentTimeMillis();
@@ -970,8 +943,11 @@
970 }943 }
971 }944 }
972 // store update command945 // store update command
946 setUpdateCommand(updateCommand.getAbsolutePath());
947
948 // updated downloaded information.
973 VersionInfo v = new VersionInfo(alias, jsonUrl, choosenRelease.description, choosenRelease.version, 0, releaseType);949 VersionInfo v = new VersionInfo(alias, jsonUrl, choosenRelease.description, choosenRelease.version, 0, releaseType);
974 editor.putString(PREF_KEY_UPDATE_COMMAND, updateCommand.getAbsolutePath());950
975 editor.putInt(PREF_KEY_ESTIMATED_CHECKPOINTS, estimatedCheckCount);951 editor.putInt(PREF_KEY_ESTIMATED_CHECKPOINTS, estimatedCheckCount);
976 v.storeVersion(editor, PREF_KEY_DOWNLOADED_VERSION);952 v.storeVersion(editor, PREF_KEY_DOWNLOADED_VERSION);
977 mProgress = 100;953 mProgress = 100;
@@ -1071,40 +1047,38 @@
1071 return fileName;1047 return fileName;
1072 }1048 }
10731049
1050
1051 private static boolean deleteDirectory(File path) {
1052 if( path.exists() ) {
1053 File[] files = path.listFiles();
1054 for(int i=0; i<files.length; i++) {
1055 if(files[i].isDirectory()) {
1056 deleteDirectory(files[i]);
1057 } else {
1058 files[i].delete();
1059 }
1060 }
1061 }
1062 return( path.delete() );
1063 }
1064
1074 /**1065 /**
1075 *
1076 * @return null if success or error1066 * @return null if success or error
1077 */1067 */
1078 private String deleteRelease() {1068 private String deleteRelease() {
1079 // First delete old release if it exists1069 // First delete old release if it exists
1080 File rootFolder = new File(mRootOfWorkPath);1070 File rootFolder = new File(mRootOfWorkPath);
1081 File release = new File(rootFolder,RELEASE_FOLDER);1071 File release = new File(rootFolder, RELEASE_FOLDER);
1082 if (release.exists()) {1072 if (release.exists()) {
1083 try {1073 deleteDirectory(release);
1084 String command = "rm -rf " + release.getAbsolutePath();1074 // cleanup update command
1085 Process p = Runtime.getRuntime().exec(command , null, rootFolder);1075 cleanUpdateCommand();
1086 try { 1076 // clean up version number.
1087 p.waitFor();1077 VersionInfo.storeEmptyVersion(getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE).edit(), PREF_KEY_DOWNLOADED_VERSION);
1088 int r = p.exitValue();
1089 if (r == 255) {
1090 return "failed to remove old download";
1091 }
1092 } catch (InterruptedException e) {
1093 }
1094 }catch (IOException e) {
1095 e.printStackTrace();
1096 Log.w(TAG, "failed to remove old download");
1097 return "failed to remove old download";
1098 }
1099 SharedPreferences pref = getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE);
1100 SharedPreferences.Editor editor = pref.edit();
1101 editor.putString(PREF_KEY_UPDATE_COMMAND, "");
1102 VersionInfo.storeEmptyVersion(editor, PREF_KEY_DOWNLOADED_VERSION);
1103 editor.commit();
1104 }1078 }
1105 return null;1079 return null;
1106 }1080 }
1107 1081
1108 private void broadcastInstallerState() {1082 private void broadcastInstallerState() {
1109 Intent i = new Intent(SERVICE_STATE);1083 Intent i = new Intent(SERVICE_STATE);
1110 i.putExtra(SERVICE_STATE, mInstallerState.ordinal());1084 i.putExtra(SERVICE_STATE, mInstallerState.ordinal());
@@ -1117,16 +1091,7 @@
1117 i.putExtra(SERVICE_STATE, mInstallerState.ordinal());1091 i.putExtra(SERVICE_STATE, mInstallerState.ordinal());
1118 sendBroadcast(i); 1092 sendBroadcast(i);
1119 }1093 }
1120 1094
1121 private void broadcastProgress(int val, String progress) {
1122 Intent i = new Intent(PROGRESS);
1123 i.putExtra(PROGRESS_EXTRA_INT, val);
1124 if (progress!= null) {
1125 i.putExtra(PROGRESS_EXTRA_TEXT, progress);
1126 }
1127 sendBroadcast(i);
1128 }
1129
1130 /**1095 /**
1131 * Check whether storage free space is enough.1096 * Check whether storage free space is enough.
1132 * @param downloadSize: download size from json. 0 means file already downloaded.1097 * @param downloadSize: download size from json. 0 means file already downloaded.
@@ -1161,6 +1126,7 @@
1161 }1126 }
1162 return null;1127 return null;
1163 }1128 }
1129
1164 /**1130 /**
1165 * Internal helper function to get current DOWNLOAD_VERSION even download is partial1131 * Internal helper function to get current DOWNLOAD_VERSION even download is partial
1166 * @param context1132 * @param context
@@ -1186,6 +1152,7 @@
1186 public static VersionInfo getInstalledVersion(Context c) {1152 public static VersionInfo getInstalledVersion(Context c) {
1187 return getVersionWithPrefKey(c, PREF_KEY_INSTALLED_VERSION);1153 return getVersionWithPrefKey(c, PREF_KEY_INSTALLED_VERSION);
1188 }1154 }
1155
1189 public static boolean isUbuntuInstalled(Context c) {1156 public static boolean isUbuntuInstalled(Context c) {
1190 SharedPreferences pref = c.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE);1157 SharedPreferences pref = c.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE);
1191 if (VersionInfo.hasValidVersion(pref, PREF_KEY_INSTALLED_VERSION)) {1158 if (VersionInfo.hasValidVersion(pref, PREF_KEY_INSTALLED_VERSION)) {
@@ -1194,9 +1161,111 @@
1194 }1161 }
1195 return false;1162 return false;
1196 }1163 }
1164
1165 /**
1166 * check if update_command available for upgrade.
1167 *
1168 * @param c
1169 * @return
1170 */
1171 public static boolean isUpgradeable(Context c) {
1172 String cmd = c.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE).getString(PREF_KEY_UPDATE_COMMAND, "");
1173 return (cmd.startsWith("/cache/"));
1174 }
1175
1176 /**
1177 * check if recovery command is exist on the system.
1178 * system-image in Ubuntu Touch downloaded new version of image at /cache/recovery.
1179 * This function check if there is a ubuntu_command file in /cache/recovery.
1180 *
1181 * The ubuntu_command will be renamed or removed after installation.
1182 *
1183 * @return if there is upgradeable images stored in /cache.
1184 */
1185 public boolean findInstallCommand () {
1186 String[] candidates = {
1187 "/cache/recovery/ubuntu_command",
1188 "/cache/ubunturecovery/ubuntu_command",
1189 };
1190 boolean ret = false;
1191 for(String command: candidates) {
1192 if(new File("/cache").canRead()) {
1193 // if we have permission, we can read /cache.
1194 File cmd = new File(command);
1195 if(cmd.exists() && cmd.isFile()) {
1196 Log.d(TAG, "Found upgrade command - " + cmd.getAbsoluteFile().toString());
1197 // find the upgradeable file, stored into pref.
1198 setUpdateCommand(cmd.getAbsolutePath());
1199 ret = true;
1200 }
1201 } else {
1202 // check the file with su
1203 File workingFolder = new File(mRootOfWorkPath + "/" + TEMP_FOLDER);
1204 if (!workingFolder.exists() && !workingFolder.mkdir()) {
1205 Log.e(TAG, "can not create working folder");
1206 ret = false;
1207 }
1208 try {
1209 int r = executeSUCommands(new String[] {
1210 String.format("%s %s\n", UPGRADECHECKER, command),
1211 });
1212 if(r == 1) {
1213 Log.d(TAG, "Found upgradeable file - " + command);
1214 setUpdateCommand(command);
1215 ret = true;
1216 }
1217 } catch (EShellExecException e) {
1218 ret = false;
1219 }
1220 }
1221 }
1222 if(ret) {
1223 // FIXME we don't know what's the version in /cache.
1224 SharedPreferences pref = getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE);
1225 VersionInfo v = new VersionInfo(pref, PREF_KEY_INSTALLED_VERSION);
1226 v.storeVersion(pref.edit(), PREF_KEY_DOWNLOADED_VERSION);
1227 }
1228 return ret;
1229 }
1230
1231 /**
1232 * set update command string stored in shared preferences.
1233 * @file absolute file path of Ubuntu Command file.
1234 */
1235 private String getUpdateCommand(){
1236 return getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE).getString(PREF_KEY_UPDATE_COMMAND, "");
1237 }
1238
1239 /**
1240 * set update command string stored in shared preferences.
1241 * @file absolute file path of Ubuntu Command file.
1242 */
1243 private void setUpdateCommand(String file){
1244 getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE).
1245 edit().
1246 putString(PREF_KEY_UPDATE_COMMAND, file).
1247 commit();
1248 }
1249
1250 /**
1251 * clean update command string stored in shared preferences.
1252 */
1253 private void cleanUpdateCommand() {
1254 this.setUpdateCommand("");
1255 }
1197 1256
1257 private void broadcastProgress(int val, String progress) {
1258 Intent i = new Intent(PROGRESS);
1259 i.putExtra(PROGRESS_EXTRA_INT, val);
1260 if (progress!= null) {
1261 i.putExtra(PROGRESS_EXTRA_TEXT, progress);
1262 }
1263 sendBroadcast(i);
1264 }
1265
1198 /**1266 /**
1199 * Check if there is downloaded release ready to install1267 * Check if there is downloaded release ready to install.
1268 * If command file is not exist, reset downloaded version.
1200 * @param context1269 * @param context
1201 * @return true if there is downloaded release ready to install1270 * @return true if there is downloaded release ready to install
1202 */1271 */
@@ -1207,9 +1276,10 @@
1207 if (versionInfo.getDownloadedSize() != 0) return false;1276 if (versionInfo.getDownloadedSize() != 0) return false;
1208 1277
1209 String command = pref.getString(PREF_KEY_UPDATE_COMMAND, "");1278 String command = pref.getString(PREF_KEY_UPDATE_COMMAND, "");
1279 Log.d(TAG, "checkifReadyToInstall");
1210 if (!command.equals("")) {1280 if (!command.equals("")) {
1211 File f = new File(command);1281 if (new File(command).exists() || command.startsWith("/cache")) {
1212 if (f.exists()) {1282 Log.d(TAG, "checkifReadyToInstall - found command file " + command);
1213 return true;1283 return true;
1214 } else {1284 } else {
1215 pref.edit().putString(PREF_KEY_UPDATE_COMMAND, "").commit();1285 pref.edit().putString(PREF_KEY_UPDATE_COMMAND, "").commit();
12161286
=== modified file 'src/com/canonical/ubuntu/installer/VersionInfo.java'
--- src/com/canonical/ubuntu/installer/VersionInfo.java 2013-12-24 03:50:41 +0000
+++ src/com/canonical/ubuntu/installer/VersionInfo.java 2013-12-26 07:18:46 +0000
@@ -5,7 +5,6 @@
55
6/**6/**
7 * Version holder7 * Version holder
8 *
9 */8 */
10public class VersionInfo {9public class VersionInfo {
11 10
@@ -109,9 +108,6 @@
109 }108 }
110109
111 public static boolean hasValidVersion(SharedPreferences sp, String set) {110 public static boolean hasValidVersion(SharedPreferences sp, String set) {
112 int v = sp.getInt(set + VERSION, -1);
113 String s1 = sp.getString(set + ALIAS, "");
114 String s2 = sp.getString(set + JSON, "");
115 return (-1 != sp.getInt(set + VERSION, -1));111 return (-1 != sp.getInt(set + VERSION, -1));
116 }112 }
117 113

Subscribers

People subscribed via source and target branches

to all changes: