1af75948cddd40a0fde5af051b700306744eae64cChristopher Tate/*
2af75948cddd40a0fde5af051b700306744eae64cChristopher Tate * Copyright (C) 2012 The Android Open Source Project
3af75948cddd40a0fde5af051b700306744eae64cChristopher Tate *
4af75948cddd40a0fde5af051b700306744eae64cChristopher Tate * Licensed under the Apache License, Version 2.0 (the "License");
5af75948cddd40a0fde5af051b700306744eae64cChristopher Tate * you may not use this file except in compliance with the License.
6af75948cddd40a0fde5af051b700306744eae64cChristopher Tate * You may obtain a copy of the License at
7af75948cddd40a0fde5af051b700306744eae64cChristopher Tate *
8af75948cddd40a0fde5af051b700306744eae64cChristopher Tate *      http://www.apache.org/licenses/LICENSE-2.0
9af75948cddd40a0fde5af051b700306744eae64cChristopher Tate *
10af75948cddd40a0fde5af051b700306744eae64cChristopher Tate * Unless required by applicable law or agreed to in writing, software
11af75948cddd40a0fde5af051b700306744eae64cChristopher Tate * distributed under the License is distributed on an "AS IS" BASIS,
12af75948cddd40a0fde5af051b700306744eae64cChristopher Tate * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13af75948cddd40a0fde5af051b700306744eae64cChristopher Tate * See the License for the specific language governing permissions and
14af75948cddd40a0fde5af051b700306744eae64cChristopher Tate * limitations under the License.
15af75948cddd40a0fde5af051b700306744eae64cChristopher Tate */
16af75948cddd40a0fde5af051b700306744eae64cChristopher Tate
17af75948cddd40a0fde5af051b700306744eae64cChristopher Tatepackage com.android.commands.settings;
18af75948cddd40a0fde5af051b700306744eae64cChristopher Tate
19af75948cddd40a0fde5af051b700306744eae64cChristopher Tateimport android.app.ActivityManagerNative;
20af75948cddd40a0fde5af051b700306744eae64cChristopher Tateimport android.app.IActivityManager;
21af75948cddd40a0fde5af051b700306744eae64cChristopher Tateimport android.app.IActivityManager.ContentProviderHolder;
22af75948cddd40a0fde5af051b700306744eae64cChristopher Tateimport android.content.IContentProvider;
23af75948cddd40a0fde5af051b700306744eae64cChristopher Tateimport android.os.Binder;
24af75948cddd40a0fde5af051b700306744eae64cChristopher Tateimport android.os.Bundle;
25af75948cddd40a0fde5af051b700306744eae64cChristopher Tateimport android.os.IBinder;
26af75948cddd40a0fde5af051b700306744eae64cChristopher Tateimport android.os.RemoteException;
27af75948cddd40a0fde5af051b700306744eae64cChristopher Tateimport android.os.UserHandle;
28af75948cddd40a0fde5af051b700306744eae64cChristopher Tateimport android.provider.Settings;
29af75948cddd40a0fde5af051b700306744eae64cChristopher Tate
30af75948cddd40a0fde5af051b700306744eae64cChristopher Tatepublic final class SettingsCmd {
31af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    static final String TAG = "settings";
32af75948cddd40a0fde5af051b700306744eae64cChristopher Tate
33af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    enum CommandVerb {
34af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        UNSPECIFIED,
35af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        GET,
36af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        PUT
37af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    }
38af75948cddd40a0fde5af051b700306744eae64cChristopher Tate
39af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    static String[] mArgs;
40af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    int mNextArg;
41af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    int mUser = -1;     // unspecified
42af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    CommandVerb mVerb = CommandVerb.UNSPECIFIED;
43af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    String mTable = null;
44af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    String mKey = null;
45af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    String mValue = null;
46af75948cddd40a0fde5af051b700306744eae64cChristopher Tate
47af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    public static void main(String[] args) {
48af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        if (args == null || args.length < 3) {
49af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            printUsage();
50af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            return;
51af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        }
52af75948cddd40a0fde5af051b700306744eae64cChristopher Tate
53af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        mArgs = args;
54af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        try {
55af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            new SettingsCmd().run();
56af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        } catch (Exception e) {
57af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            System.err.println("Unable to run settings command");
58af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        }
59af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    }
60af75948cddd40a0fde5af051b700306744eae64cChristopher Tate
61af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    public void run() {
62af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        boolean valid = false;
63af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        String arg;
64af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        try {
65af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            while ((arg = nextArg()) != null) {
66af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                if ("--user".equals(arg)) {
67af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    if (mUser != -1) {
68af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                        // --user specified more than once; invalid
69af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                        break;
70af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    }
71af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    mUser = Integer.parseInt(nextArg());
72af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                } else if (mVerb == CommandVerb.UNSPECIFIED) {
73af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    if ("get".equalsIgnoreCase(arg)) {
74af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                        mVerb = CommandVerb.GET;
75af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    } else if ("put".equalsIgnoreCase(arg)) {
76af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                        mVerb = CommandVerb.PUT;
77af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    } else {
78af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                        // invalid
79af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                        System.err.println("Invalid command: " + arg);
80af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                        break;
81af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    }
82af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                } else if (mTable == null) {
83af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    if (!"system".equalsIgnoreCase(arg)
84af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                            && !"secure".equalsIgnoreCase(arg)
85af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                            && !"global".equalsIgnoreCase(arg)) {
86af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                        System.err.println("Invalid namespace '" + arg + "'");
87af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                        break;  // invalid
88af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    }
89af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    mTable = arg.toLowerCase();
90af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                } else if (mVerb == CommandVerb.GET) {
91af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    mKey = arg;
92af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    if (mNextArg >= mArgs.length) {
93af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                        valid = true;
94af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    } else {
95af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                        System.err.println("Too many arguments");
96af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    }
97af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    break;
98af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                } else if (mKey == null) {
99af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    mKey = arg;
100af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    // keep going; there's another PUT arg
101af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                } else {    // PUT, final arg
102af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    mValue = arg;
103af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    if (mNextArg >= mArgs.length) {
104af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                        valid = true;
105af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    } else {
106af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                        System.err.println("Too many arguments");
107af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    }
108af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    break;
109af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                }
110af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            }
111af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        } catch (Exception e) {
112af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            valid = false;
113af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        }
114af75948cddd40a0fde5af051b700306744eae64cChristopher Tate
115af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        if (valid) {
116af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            if (mUser < 0) {
117af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                mUser = UserHandle.USER_OWNER;
118af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            }
119af75948cddd40a0fde5af051b700306744eae64cChristopher Tate
120af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            try {
121af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                IActivityManager activityManager = ActivityManagerNative.getDefault();
122af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                IContentProvider provider = null;
123af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                IBinder token = new Binder();
124af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                try {
125af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    ContentProviderHolder holder = activityManager.getContentProviderExternal(
126af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                            "settings", UserHandle.USER_OWNER, token);
127af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    if (holder == null) {
128af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                        throw new IllegalStateException("Could not find settings provider");
129af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    }
130af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    provider = holder.provider;
131af75948cddd40a0fde5af051b700306744eae64cChristopher Tate
132af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    switch (mVerb) {
133af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                        case GET:
134af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                            System.out.println(getForUser(provider, mUser, mTable, mKey));
135af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                            break;
136af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                        case PUT:
137af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                            putForUser(provider, mUser, mTable, mKey, mValue);
138af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                            break;
139af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                        default:
140af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                            System.err.println("Unspecified command");
141af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                            break;
142af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    }
143af75948cddd40a0fde5af051b700306744eae64cChristopher Tate
144af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                } finally {
145af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    if (provider != null) {
146af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                        activityManager.removeContentProviderExternal("settings", token);
147af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                    }
148af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                }
149af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            } catch (Exception e) {
150af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                System.err.println("Error while accessing settings provider");
151af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                e.printStackTrace();
152af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            }
153af75948cddd40a0fde5af051b700306744eae64cChristopher Tate
154af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        } else {
155af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            printUsage();
156af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        }
157af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    }
158af75948cddd40a0fde5af051b700306744eae64cChristopher Tate
159af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    private String nextArg() {
160af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        if (mNextArg >= mArgs.length) {
161af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            return null;
162af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        }
163af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        String arg = mArgs[mNextArg];
164af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        mNextArg++;
165af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        return arg;
166af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    }
167af75948cddd40a0fde5af051b700306744eae64cChristopher Tate
168af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    String getForUser(IContentProvider provider, int userHandle,
169af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            final String table, final String key) {
170af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        final String callGetCommand;
171af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        if ("system".equals(table)) callGetCommand = Settings.CALL_METHOD_GET_SYSTEM;
172af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        else if ("secure".equals(table)) callGetCommand = Settings.CALL_METHOD_GET_SECURE;
173af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        else if ("global".equals(table)) callGetCommand = Settings.CALL_METHOD_GET_GLOBAL;
174af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        else {
175af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            System.err.println("Invalid table; no put performed");
176af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            throw new IllegalArgumentException("Invalid table " + table);
177af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        }
178af75948cddd40a0fde5af051b700306744eae64cChristopher Tate
179af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        String result = null;
180af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        try {
181af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            Bundle arg = new Bundle();
182af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
183af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            Bundle b = provider.call(callGetCommand, key, arg);
184af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            if (b != null) {
185af75948cddd40a0fde5af051b700306744eae64cChristopher Tate                result = b.getPairValue();
186af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            }
187af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        } catch (RemoteException e) {
188af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            System.err.println("Can't read key " + key + " in " + table + " for user " + userHandle);
189af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        }
190af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        return result;
191af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    }
192af75948cddd40a0fde5af051b700306744eae64cChristopher Tate
193af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    void putForUser(IContentProvider provider, int userHandle,
194af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            final String table, final String key, final String value) {
195af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        final String callPutCommand;
196af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        if ("system".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_SYSTEM;
197af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        else if ("secure".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_SECURE;
198af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        else if ("global".equals(table)) callPutCommand = Settings.CALL_METHOD_PUT_GLOBAL;
199af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        else {
200af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            System.err.println("Invalid table; no put performed");
201af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            return;
202af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        }
203af75948cddd40a0fde5af051b700306744eae64cChristopher Tate
204af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        try {
205af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            Bundle arg = new Bundle();
206af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            arg.putString(Settings.NameValueTable.VALUE, value);
207af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
208af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            provider.call(callPutCommand, key, arg);
209af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        } catch (RemoteException e) {
210af75948cddd40a0fde5af051b700306744eae64cChristopher Tate            System.err.println("Can't set key " + key + " in " + table + " for user " + userHandle);
211af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        }
212af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    }
213af75948cddd40a0fde5af051b700306744eae64cChristopher Tate
214af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    private static void printUsage() {
215af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        System.err.println("usage:  settings [--user NUM] get namespace key");
216af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        System.err.println("        settings [--user NUM] put namespace key value");
217af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        System.err.println("\n'namespace' is one of {system, secure, global}, case-insensitive");
218af75948cddd40a0fde5af051b700306744eae64cChristopher Tate        System.err.println("If '--user NUM' is not given, the operations are performed on the owner user.");
219af75948cddd40a0fde5af051b700306744eae64cChristopher Tate    }
220af75948cddd40a0fde5af051b700306744eae64cChristopher Tate}
221