summaryrefslogtreecommitdiffstats
path: root/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/DebugConfig.java
blob: b030c8e67f0dcecaef25983a051084a9cba214e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.gecko.util;

import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.mozilla.gecko.annotation.ReflectionTarget;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.error.YAMLException;

// Raptor writes a *-config.yaml file to specify Gecko runtime settings (e.g.
// the profile dir). This file gets deserialized into a DebugConfig object.
// Yaml uses reflection to create this class so we have to tell PG to keep it.
@ReflectionTarget
public class DebugConfig {
  private static final String LOGTAG = "GeckoDebugConfig";

  protected Map<String, Object> prefs;
  protected Map<String, String> env;
  protected List<String> args;

  public static class ConfigException extends RuntimeException {
    public ConfigException(final String message) {
      super(message);
    }
  }

  public static @NonNull DebugConfig fromFile(final @NonNull File configFile)
      throws FileNotFoundException {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
      // There are a lot of problems with SnakeYaml on older version let's just bail.
      throw new ConfigException("Config version is only supported for SDK_INT >= 21.");
    }

    final LoaderOptions options = new LoaderOptions();
    final Constructor constructor = new Constructor(DebugConfig.class, options);
    final TypeDescription description = new TypeDescription(DebugConfig.class);
    description.putMapPropertyType("prefs", String.class, Object.class);
    description.putMapPropertyType("env", String.class, String.class);
    description.putListPropertyType("args", String.class);

    final Yaml yaml = new Yaml(constructor);
    yaml.addTypeDescription(description);

    final FileInputStream fileInputStream = new FileInputStream(configFile);
    try {
      return yaml.load(fileInputStream);
    } catch (final YAMLException e) {
      throw new ConfigException(e.getMessage());
    } finally {
      try {
        if (fileInputStream != null) {
          ((Closeable) fileInputStream).close();
        }
      } catch (final IOException e) {
      }
    }
  }

  @Nullable
  public Bundle mergeIntoExtras(final @Nullable Bundle extras) {
    if (env == null) {
      return extras;
    }

    Log.d(LOGTAG, "Adding environment variables from debug config: " + env);

    final Bundle result = extras != null ? extras : new Bundle();

    int c = 0;
    while (result.getString("env" + c) != null) {
      c += 1;
    }

    for (final Map.Entry<String, String> entry : env.entrySet()) {
      result.putString("env" + c, entry.getKey() + "=" + entry.getValue());
      c += 1;
    }

    return result;
  }

  @Nullable
  public String[] mergeIntoArgs(final @Nullable String[] initArgs) {
    if (args == null) {
      return initArgs;
    }

    Log.d(LOGTAG, "Adding arguments from debug config: " + args);

    final ArrayList<String> combinedArgs = new ArrayList<>();
    if (initArgs != null) {
      combinedArgs.addAll(Arrays.asList(initArgs));
    }
    combinedArgs.addAll(args);

    return combinedArgs.toArray(new String[combinedArgs.size()]);
  }

  @Nullable
  public Map<String, Object> mergeIntoPrefs(final @Nullable Map<String, Object> initPrefs) {
    if (prefs == null) {
      return initPrefs;
    }

    Log.d(LOGTAG, "Adding prefs from debug config: " + prefs);

    final Map<String, Object> combinedPrefs = new HashMap<>();
    if (initPrefs != null) {
      combinedPrefs.putAll(initPrefs);
    }
    combinedPrefs.putAll(prefs);

    return Collections.unmodifiableMap(combinedPrefs);
  }
}