internal void FlashFFUTask(string FFUPath) { new Thread(() => { bool Result = true; NokiaFlashModel Phone = (NokiaFlashModel)PhoneNotifier.CurrentModel; PhoneInfo Info = Phone.ReadPhoneInfo(false); #region Remove bootloader changes // If necessary remove bootloader changes // In case the NV vars were redirected, and a stock FFU is flashed, then the IsFlashing flag will be cleared in the redirected NV vars // And after a reboot the original NV vars are active again, but the IsFlashing flag is still set from when the bootloader was unlocked // So we will first restore the GPT, so the original vars are active again. // Then IsFlashing is true and the phone boots forcibly to FlashApp again. // Then we start normal FFU flasing and at the end the IsFlashing flag is cleared in the original vars. if (Info.FlashAppProtocolVersionMajor >= 2) { byte[] GPTChunk = LumiaUnlockBootloaderViewModel.GetGptChunk(Phone, 0x20000); // TODO: Get proper profile FFU and get ChunkSizeInBytes GPT GPT = new GPT(GPTChunk); FlashPart Part; List <FlashPart> FlashParts = new List <FlashPart>(); Partition NvBackupPartition = GPT.GetPartition("BACKUP_BS_NV"); if (NvBackupPartition != null) { // This must be a left over of a half unlocked bootloader Partition NvPartition = GPT.GetPartition("UEFI_BS_NV"); NvBackupPartition.Name = "UEFI_BS_NV"; NvBackupPartition.PartitionGuid = NvPartition.PartitionGuid; NvBackupPartition.PartitionTypeGuid = NvPartition.PartitionTypeGuid; GPT.Partitions.Remove(NvPartition); GPT.Rebuild(); Part = new FlashPart(); Part.StartSector = 0; Part.Stream = new MemoryStream(GPTChunk); FlashParts.Add(Part); } bool ClearFlashingStatus = true; // We should only clear NV if there was no backup NV to be restored and the current NV contains the SB unlock. if ((NvBackupPartition == null) && !Info.UefiSecureBootEnabled) { // ClearNV Part = new FlashPart(); Partition Target = GPT.GetPartition("UEFI_BS_NV"); Part.StartSector = (UInt32)Target.FirstSector; Part.Stream = new MemoryStream(new byte[0x40000]); FlashParts.Add(Part); ClearFlashingStatus = false; } if (FlashParts.Count > 0) { ActivateSubContext(new BusyViewModel("Restoring bootloader...")); WPinternalsStatus LastStatus = WPinternalsStatus.Undefined; LumiaV2UnlockBootViewModel.LumiaV2CustomFlash(PhoneNotifier, FFUPath, false, false, FlashParts, true, ClearFlashingStatusAtEnd: ClearFlashingStatus, SetWorkingStatus: (m, s, v, a, st) => { if ((st == WPinternalsStatus.Scanning) || (st == WPinternalsStatus.WaitingForManualReset)) { SetWorkingStatus(m, s, v, a, st); } else if ((LastStatus == WPinternalsStatus.Scanning) || (LastStatus == WPinternalsStatus.WaitingForManualReset)) { SetWorkingStatus("Restoring bootloader...", null, null, Status: WPinternalsStatus.Flashing); } LastStatus = st; }, UpdateWorkingStatus: (m, s, v, st) => { if ((st == WPinternalsStatus.Scanning) || (st == WPinternalsStatus.WaitingForManualReset)) { UpdateWorkingStatus(m, s, v, st); } else if ((LastStatus == WPinternalsStatus.Scanning) || (LastStatus == WPinternalsStatus.WaitingForManualReset)) { SetWorkingStatus("Restoring bootloader...", null, null, Status: WPinternalsStatus.Flashing); } LastStatus = st; } ).Wait(); if ((PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_Bootloader) && (PhoneNotifier.CurrentInterface != PhoneInterfaces.Lumia_Flash)) { PhoneNotifier.WaitForArrival().Wait(); } if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_Bootloader) { ((NokiaFlashModel)PhoneNotifier.CurrentModel).SwitchToFlashAppContext(); } } } #endregion Phone = (NokiaFlashModel)PhoneNotifier.CurrentModel; ActivateSubContext(new BusyViewModel("Initializing flash...")); string ErrorSubMessage = null; try { FFU FFU = new FFU(FFUPath); BusyViewModel Busy = new BusyViewModel("Flashing original FFU...", MaxProgressValue: FFU.TotalChunkCount, UIContext: UIContext); ActivateSubContext(Busy); byte Options = 0; if (!Info.IsBootloaderSecure) { Options = (byte)((FlashOptions)Options | FlashOptions.SkipSignatureCheck); } Phone.FlashFFU(FFU, Busy.ProgressUpdater, true, Options); } catch (Exception Ex) { LogFile.LogException(Ex); if (Ex is WPinternalsException) { ErrorSubMessage = ((WPinternalsException)Ex).SubMessage; } Result = false; } if (!Result) { ExitFailure("Flash failed!", ErrorSubMessage); return; } ExitSuccess("Flash successful!", null); }).Start(); }