perfetto-ui: Fix permalinks

Creating permalinks was broken in debug mode builds with real files
since Immer freezes state (to prevent unintended modification) and
PermalinkController attempts to rewrite the state on the fly to turn
File sources into urls.

Change-Id: I686019950326ead426902f15df481533ff30eead
diff --git a/ui/src/controller/permalink_controller.ts b/ui/src/controller/permalink_controller.ts
index 0388934..7baeeb0 100644
--- a/ui/src/controller/permalink_controller.ts
+++ b/ui/src/controller/permalink_controller.ts
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+import {DraftObject, produce} from 'immer';
 import * as uuidv4 from 'uuid/v4';
 
 import {assertExists} from '../base/logging';
@@ -53,21 +54,30 @@
   }
 
   private static async createPermalink() {
-    const state = {...globals.state};
-    state.engines = {...state.engines};
+    const state = globals.state;
+
+    // Upload each loaded trace.
+    const fileToUrl = new Map<File, string>();
     for (const engine of Object.values<EngineConfig>(state.engines)) {
-      // If the trace was opened from a local file, upload it and store the
-      // url of the uploaded trace instead.
-      if (engine.source instanceof File) {
-        const url = await this.saveTrace(engine.source);
-        engine.source = url;
-      }
+      if (!(engine.source instanceof File)) continue;
+      const url = await this.saveTrace(engine.source);
+      fileToUrl.set(engine.source, url);
     }
-    const hash = await this.saveState(state);
+
+    // Convert state to use URLs.
+    const uploadState = produce(state, draft => {
+      for (const engine of Object.values<DraftObject<EngineConfig>>(
+               draft.engines)) {
+        if (!(engine.source instanceof File)) continue;
+        engine.source = fileToUrl.get(engine.source)!;
+      }
+    });
+
+    // Upload state.
+    const hash = await this.saveState(uploadState);
     return hash;
   }
 
-
   private static async saveState(state: State): Promise<string> {
     const text = JSON.stringify(state);
     const hash = await this.toSha256(text);