summaryrefslogtreecommitdiff
path: root/service/java/com/android/server/deviceconfig/DeviceConfigInit.java
blob: b1ed0d6719a47a3918471be684d6138bacfa3fdd (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
package com.android.server.deviceconfig;

import static com.android.server.deviceconfig.Flags.enableRebootNotification;
import static com.android.server.deviceconfig.Flags.enableUnattendedReboot;

import java.io.IOException;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import android.aconfig.Aconfig.parsed_flags;
import android.aconfig.Aconfig.parsed_flag;
import android.content.Intent;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Binder;
import android.content.IntentFilter;
import android.provider.DeviceConfig;
import android.provider.UpdatableDeviceConfigServiceReadiness;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.content.ComponentName;
import android.util.Slog;
import com.android.modules.utils.build.SdkLevel;
import com.android.server.SystemService;

/** @hide */
@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
public class DeviceConfigInit {
    private static final String TAG = "DEVICE_CONFIG_INIT";
    private static final String STAGED_NAMESPACE = "staged";

    private static final String SYSTEM_FLAGS_PATH = "/system/etc/aconfig_flags.pb";
    private static final String SYSTEM_EXT_FLAGS_PATH = "/system_ext/etc/aconfig_flags.pb";
    private static final String VENDOR_FLAGS_PATH = "/vendor/etc/aconfig_flags.pb";

    private DeviceConfigInit() {
        // do not instantiate
    }

    /** @hide */
    @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
    public static class Lifecycle extends SystemService {
        private DeviceConfigServiceImpl mService;
        private UnattendedRebootManager mUnattendedRebootManager;

        /** @hide */
        @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
        public Lifecycle(@NonNull Context context) {
            super(context);
            // this service is always instantiated but should only launch subsequent service(s)
            // if the module is ready
            if (UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService()) {
                mService = new DeviceConfigServiceImpl(getContext());
                publishBinderService(DeviceConfig.SERVICE_NAME, mService);
            }
            applyBootstrapValues();
        }

        /**
         * @hide
         */
        @Override
        public void onStart() {
            if (enableRebootNotification()) {
                Map<String, Set<String>> aconfigFlags = new HashMap<>();
                try {
                    addAconfigFlagsFromFile(aconfigFlags, SYSTEM_FLAGS_PATH);
                    addAconfigFlagsFromFile(aconfigFlags, SYSTEM_EXT_FLAGS_PATH);
                    addAconfigFlagsFromFile(aconfigFlags, VENDOR_FLAGS_PATH);
                } catch (IOException e) {
                    Slog.e(TAG, "error loading aconfig flags", e);
                }

                BootNotificationCreator notifCreator = new BootNotificationCreator(
                    getContext().getApplicationContext(),
                    aconfigFlags);

                DeviceConfig.addOnPropertiesChangedListener(
                    STAGED_NAMESPACE,
                    AsyncTask.THREAD_POOL_EXECUTOR,
                    notifCreator);
            }

            if (enableUnattendedReboot()) {
                mUnattendedRebootManager =
                    new UnattendedRebootManager(getContext().getApplicationContext());
                getContext()
                    .registerReceiver(
                        new BroadcastReceiver() {
                            @Override
                            public void onReceive(Context context, Intent intent) {
                                mUnattendedRebootManager.prepareUnattendedReboot();
                                mUnattendedRebootManager.scheduleReboot();
                            }
                        },
                        new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
            }
        }

        private void addAconfigFlagsFromFile(Map<String, Set<String>> aconfigFlags,
                                             String fileName) throws IOException {
            byte[] contents = (new FileInputStream(fileName)).readAllBytes();
            parsed_flags parsedFlags = parsed_flags.parseFrom(contents);
            for (parsed_flag flag : parsedFlags.getParsedFlagList()) {
                if (aconfigFlags.get(flag.getNamespace()) == null) {
                    aconfigFlags.put(flag.getNamespace(), new HashSet<>());
                    aconfigFlags.get(flag.getNamespace()).add(flag.getName());
                } else {
                    aconfigFlags.get(flag.getNamespace()).add(flag.getName());
                }
            }
        }

        private void applyBootstrapValues() {
            if (SdkLevel.isAtLeastV()) {
                try {
                    new DeviceConfigBootstrapValues().applyValuesIfNeeded();
                } catch (RuntimeException e) {
                    Slog.e(TAG, "Failed to load boot overrides", e);
                    throw e;
                } catch (IOException e) {
                    Slog.e(TAG, "Failed to load boot overrides", e);
                    throw new RuntimeException(e);
                }
            }
        }
    }
}