1 /* 2 ** Copyright 2012, The Android Open Source Project 3 ** 4 ** Licensed under the Apache License, Version 2.0 (the "License"); 5 ** you may not use this file except in compliance with the License. 6 ** You may obtain a copy of the License at 7 ** 8 ** http://www.apache.org/licenses/LICENSE-2.0 9 ** 10 ** Unless required by applicable law or agreed to in writing, software 11 ** distributed under the License is distributed on an "AS IS" BASIS, 12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 ** See the License for the specific language governing permissions and 14 ** limitations under the License. 15 */ 16 17 package com.android.commands.content; 18 19 import android.app.ActivityManager; 20 import android.app.ContentProviderHolder; 21 import android.app.IActivityManager; 22 import android.content.ContentResolver; 23 import android.content.ContentValues; 24 import android.content.IContentProvider; 25 import android.database.Cursor; 26 import android.net.Uri; 27 import android.os.Binder; 28 import android.os.Bundle; 29 import android.os.FileUtils; 30 import android.os.IBinder; 31 import android.os.ParcelFileDescriptor; 32 import android.os.Process; 33 import android.os.UserHandle; 34 import android.text.TextUtils; 35 36 import java.io.FileDescriptor; 37 38 /** 39 * This class is a command line utility for manipulating content. A client 40 * can insert, update, and remove records in a content provider. For example, 41 * some settings may be configured before running the CTS tests, etc. 42 * <p> 43 * Examples: 44 * <ul> 45 * <li> 46 * # Add "new_setting" secure setting with value "new_value".</br> 47 * adb shell content insert --uri content://settings/secure --bind name:s:new_setting 48 * --bind value:s:new_value 49 * </li> 50 * <li> 51 * # Change "new_setting" secure setting to "newer_value" (You have to escape single quotes in 52 * the where clause).</br> 53 * adb shell content update --uri content://settings/secure --bind value:s:newer_value 54 * --where "name=\'new_setting\'" 55 * </li> 56 * <li> 57 * # Remove "new_setting" secure setting.</br> 58 * adb shell content delete --uri content://settings/secure --where "name=\'new_setting\'" 59 * </li> 60 * <li> 61 * # Query \"name\" and \"value\" columns from secure settings where \"name\" is equal to" 62 * \"new_setting\" and sort the result by name in ascending order.\n" 63 * adb shell content query --uri content://settings/secure --projection name:value 64 * --where "name=\'new_setting\'" --sort \"name ASC\" 65 * </li> 66 * </ul> 67 * </p> 68 */ 69 public class Content { 70 71 private static final String USAGE = 72 "usage: adb shell content [subcommand] [options]\n" 73 + "\n" 74 + "usage: adb shell content insert --uri <URI> [--user <USER_ID>]" 75 + " --bind <BINDING> [--bind <BINDING>...]\n" 76 + " <URI> a content provider URI.\n" 77 + " <BINDING> binds a typed value to a column and is formatted:\n" 78 + " <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:\n" 79 + " <TYPE> specifies data type such as:\n" 80 + " b - boolean, s - string, i - integer, l - long, f - float, d - double, n - null\n" 81 + " Note: Omit the value for passing an empty string, e.g column:s:\n" 82 + " Example:\n" 83 + " # Add \"new_setting\" secure setting with value \"new_value\".\n" 84 + " adb shell content insert --uri content://settings/secure --bind name:s:new_setting" 85 + " --bind value:s:new_value\n" 86 + "\n" 87 + "usage: adb shell content update --uri <URI> [--user <USER_ID>] [--where <WHERE>]\n" 88 + " <WHERE> is a SQL style where clause in quotes (You have to escape single quotes" 89 + " - see example below).\n" 90 + " Example:\n" 91 + " # Change \"new_setting\" secure setting to \"newer_value\".\n" 92 + " adb shell content update --uri content://settings/secure --bind" 93 + " value:s:newer_value --where \"name=\'new_setting\'\"\n" 94 + "\n" 95 + "usage: adb shell content delete --uri <URI> [--user <USER_ID>] --bind <BINDING>" 96 + " [--bind <BINDING>...] [--where <WHERE>]\n" 97 + " Example:\n" 98 + " # Remove \"new_setting\" secure setting.\n" 99 + " adb shell content delete --uri content://settings/secure " 100 + "--where \"name=\'new_setting\'\"\n" 101 + "\n" 102 + "usage: adb shell content query --uri <URI> [--user <USER_ID>]" 103 + " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]\n" 104 + " <PROJECTION> is a list of colon separated column names and is formatted:\n" 105 + " <COLUMN_NAME>[:<COLUMN_NAME>...]\n" 106 + " <SORT_ORDER> is the order in which rows in the result should be sorted.\n" 107 + " Example:\n" 108 + " # Select \"name\" and \"value\" columns from secure settings where \"name\" is " 109 + "equal to \"new_setting\" and sort the result by name in ascending order.\n" 110 + " adb shell content query --uri content://settings/secure --projection name:value" 111 + " --where \"name=\'new_setting\'\" --sort \"name ASC\"\n" 112 + "\n" 113 + "usage: adb shell content call --uri <URI> --method <METHOD> [--arg <ARG>]\n" 114 + " [--extra <BINDING> ...]\n" 115 + " <METHOD> is the name of a provider-defined method\n" 116 + " <ARG> is an optional string argument\n" 117 + " <BINDING> is like --bind above, typed data of the form <KEY>:{b,s,i,l,f,d}:<VAL>\n" 118 + "\n" 119 + "usage: adb shell content read --uri <URI> [--user <USER_ID>]\n" 120 + " Example:\n" 121 + " adb shell 'content read --uri content://settings/system/ringtone_cache' > host.ogg\n" 122 + "\n" 123 + "usage: adb shell content write --uri <URI> [--user <USER_ID>]\n" 124 + " Example:\n" 125 + " adb shell 'content write --uri content://settings/system/ringtone_cache' < host.ogg\n" 126 + "\n" 127 + "usage: adb shell content gettype --uri <URI> [--user <USER_ID>]\n" 128 + " Example:\n" 129 + " adb shell content gettype --uri content://media/internal/audio/media/\n" 130 + "\n"; 131 132 private static class Parser { 133 private static final String ARGUMENT_INSERT = "insert"; 134 private static final String ARGUMENT_DELETE = "delete"; 135 private static final String ARGUMENT_UPDATE = "update"; 136 private static final String ARGUMENT_QUERY = "query"; 137 private static final String ARGUMENT_CALL = "call"; 138 private static final String ARGUMENT_READ = "read"; 139 private static final String ARGUMENT_WRITE = "write"; 140 private static final String ARGUMENT_GET_TYPE = "gettype"; 141 private static final String ARGUMENT_WHERE = "--where"; 142 private static final String ARGUMENT_BIND = "--bind"; 143 private static final String ARGUMENT_URI = "--uri"; 144 private static final String ARGUMENT_USER = "--user"; 145 private static final String ARGUMENT_PROJECTION = "--projection"; 146 private static final String ARGUMENT_SORT = "--sort"; 147 private static final String ARGUMENT_METHOD = "--method"; 148 private static final String ARGUMENT_ARG = "--arg"; 149 private static final String ARGUMENT_EXTRA = "--extra"; 150 private static final String TYPE_BOOLEAN = "b"; 151 private static final String TYPE_STRING = "s"; 152 private static final String TYPE_INTEGER = "i"; 153 private static final String TYPE_LONG = "l"; 154 private static final String TYPE_FLOAT = "f"; 155 private static final String TYPE_DOUBLE = "d"; 156 private static final String TYPE_NULL = "n"; 157 private static final String COLON = ":"; 158 private static final String ARGUMENT_PREFIX = "--"; 159 160 private final Tokenizer mTokenizer; 161 Parser(String[] args)162 public Parser(String[] args) { 163 mTokenizer = new Tokenizer(args); 164 } 165 parseCommand()166 public Command parseCommand() { 167 try { 168 String operation = mTokenizer.nextArg(); 169 if (ARGUMENT_INSERT.equals(operation)) { 170 return parseInsertCommand(); 171 } else if (ARGUMENT_DELETE.equals(operation)) { 172 return parseDeleteCommand(); 173 } else if (ARGUMENT_UPDATE.equals(operation)) { 174 return parseUpdateCommand(); 175 } else if (ARGUMENT_QUERY.equals(operation)) { 176 return parseQueryCommand(); 177 } else if (ARGUMENT_CALL.equals(operation)) { 178 return parseCallCommand(); 179 } else if (ARGUMENT_READ.equals(operation)) { 180 return parseReadCommand(); 181 } else if (ARGUMENT_WRITE.equals(operation)) { 182 return parseWriteCommand(); 183 } else if (ARGUMENT_GET_TYPE.equals(operation)) { 184 return parseGetTypeCommand(); 185 } else { 186 throw new IllegalArgumentException("Unsupported operation: " + operation); 187 } 188 } catch (IllegalArgumentException iae) { 189 System.out.println(USAGE); 190 System.out.println("[ERROR] " + iae.getMessage()); 191 return null; 192 } 193 } 194 parseInsertCommand()195 private InsertCommand parseInsertCommand() { 196 Uri uri = null; 197 int userId = UserHandle.USER_SYSTEM; 198 ContentValues values = new ContentValues(); 199 for (String argument; (argument = mTokenizer.nextArg()) != null;) { 200 if (ARGUMENT_URI.equals(argument)) { 201 uri = Uri.parse(argumentValueRequired(argument)); 202 } else if (ARGUMENT_USER.equals(argument)) { 203 userId = Integer.parseInt(argumentValueRequired(argument)); 204 } else if (ARGUMENT_BIND.equals(argument)) { 205 parseBindValue(values); 206 } else { 207 throw new IllegalArgumentException("Unsupported argument: " + argument); 208 } 209 } 210 if (uri == null) { 211 throw new IllegalArgumentException("Content provider URI not specified." 212 + " Did you specify --uri argument?"); 213 } 214 if (values.size() == 0) { 215 throw new IllegalArgumentException("Bindings not specified." 216 + " Did you specify --bind argument(s)?"); 217 } 218 return new InsertCommand(uri, userId, values); 219 } 220 parseDeleteCommand()221 private DeleteCommand parseDeleteCommand() { 222 Uri uri = null; 223 int userId = UserHandle.USER_SYSTEM; 224 String where = null; 225 for (String argument; (argument = mTokenizer.nextArg())!= null;) { 226 if (ARGUMENT_URI.equals(argument)) { 227 uri = Uri.parse(argumentValueRequired(argument)); 228 } else if (ARGUMENT_USER.equals(argument)) { 229 userId = Integer.parseInt(argumentValueRequired(argument)); 230 } else if (ARGUMENT_WHERE.equals(argument)) { 231 where = argumentValueRequired(argument); 232 } else { 233 throw new IllegalArgumentException("Unsupported argument: " + argument); 234 } 235 } 236 if (uri == null) { 237 throw new IllegalArgumentException("Content provider URI not specified." 238 + " Did you specify --uri argument?"); 239 } 240 return new DeleteCommand(uri, userId, where); 241 } 242 parseUpdateCommand()243 private UpdateCommand parseUpdateCommand() { 244 Uri uri = null; 245 int userId = UserHandle.USER_SYSTEM; 246 String where = null; 247 ContentValues values = new ContentValues(); 248 for (String argument; (argument = mTokenizer.nextArg())!= null;) { 249 if (ARGUMENT_URI.equals(argument)) { 250 uri = Uri.parse(argumentValueRequired(argument)); 251 } else if (ARGUMENT_USER.equals(argument)) { 252 userId = Integer.parseInt(argumentValueRequired(argument)); 253 } else if (ARGUMENT_WHERE.equals(argument)) { 254 where = argumentValueRequired(argument); 255 } else if (ARGUMENT_BIND.equals(argument)) { 256 parseBindValue(values); 257 } else { 258 throw new IllegalArgumentException("Unsupported argument: " + argument); 259 } 260 } 261 if (uri == null) { 262 throw new IllegalArgumentException("Content provider URI not specified." 263 + " Did you specify --uri argument?"); 264 } 265 if (values.size() == 0) { 266 throw new IllegalArgumentException("Bindings not specified." 267 + " Did you specify --bind argument(s)?"); 268 } 269 return new UpdateCommand(uri, userId, values, where); 270 } 271 parseCallCommand()272 public CallCommand parseCallCommand() { 273 String method = null; 274 int userId = UserHandle.USER_SYSTEM; 275 String arg = null; 276 Uri uri = null; 277 ContentValues values = new ContentValues(); 278 for (String argument; (argument = mTokenizer.nextArg())!= null;) { 279 if (ARGUMENT_URI.equals(argument)) { 280 uri = Uri.parse(argumentValueRequired(argument)); 281 } else if (ARGUMENT_USER.equals(argument)) { 282 userId = Integer.parseInt(argumentValueRequired(argument)); 283 } else if (ARGUMENT_METHOD.equals(argument)) { 284 method = argumentValueRequired(argument); 285 } else if (ARGUMENT_ARG.equals(argument)) { 286 arg = argumentValueRequired(argument); 287 } else if (ARGUMENT_EXTRA.equals(argument)) { 288 parseBindValue(values); 289 } else { 290 throw new IllegalArgumentException("Unsupported argument: " + argument); 291 } 292 293 } 294 if (uri == null) { 295 throw new IllegalArgumentException("Content provider URI not specified." 296 + " Did you specify --uri argument?"); 297 } 298 if (method == null) { 299 throw new IllegalArgumentException("Content provider method not specified."); 300 } 301 return new CallCommand(uri, userId, method, arg, values); 302 } 303 parseGetTypeCommand()304 private GetTypeCommand parseGetTypeCommand() { 305 Uri uri = null; 306 int userId = UserHandle.USER_SYSTEM; 307 308 for (String argument; (argument = mTokenizer.nextArg()) != null;) { 309 if (ARGUMENT_URI.equals(argument)) { 310 uri = Uri.parse(argumentValueRequired(argument)); 311 } else if (ARGUMENT_USER.equals(argument)) { 312 userId = Integer.parseInt(argumentValueRequired(argument)); 313 } else { 314 throw new IllegalArgumentException("Unsupported argument: " + argument); 315 } 316 } 317 if (uri == null) { 318 throw new IllegalArgumentException("Content provider URI not specified." 319 + " Did you specify --uri argument?"); 320 } 321 return new GetTypeCommand(uri, userId); 322 } 323 parseReadCommand()324 private ReadCommand parseReadCommand() { 325 Uri uri = null; 326 int userId = UserHandle.USER_SYSTEM; 327 for (String argument; (argument = mTokenizer.nextArg())!= null;) { 328 if (ARGUMENT_URI.equals(argument)) { 329 uri = Uri.parse(argumentValueRequired(argument)); 330 } else if (ARGUMENT_USER.equals(argument)) { 331 userId = Integer.parseInt(argumentValueRequired(argument)); 332 } else { 333 throw new IllegalArgumentException("Unsupported argument: " + argument); 334 } 335 } 336 if (uri == null) { 337 throw new IllegalArgumentException("Content provider URI not specified." 338 + " Did you specify --uri argument?"); 339 } 340 return new ReadCommand(uri, userId); 341 } 342 parseWriteCommand()343 private WriteCommand parseWriteCommand() { 344 Uri uri = null; 345 int userId = UserHandle.USER_SYSTEM; 346 for (String argument; (argument = mTokenizer.nextArg())!= null;) { 347 if (ARGUMENT_URI.equals(argument)) { 348 uri = Uri.parse(argumentValueRequired(argument)); 349 } else if (ARGUMENT_USER.equals(argument)) { 350 userId = Integer.parseInt(argumentValueRequired(argument)); 351 } else { 352 throw new IllegalArgumentException("Unsupported argument: " + argument); 353 } 354 } 355 if (uri == null) { 356 throw new IllegalArgumentException("Content provider URI not specified." 357 + " Did you specify --uri argument?"); 358 } 359 return new WriteCommand(uri, userId); 360 } 361 parseQueryCommand()362 public QueryCommand parseQueryCommand() { 363 Uri uri = null; 364 int userId = UserHandle.USER_SYSTEM; 365 String[] projection = null; 366 String sort = null; 367 String where = null; 368 for (String argument; (argument = mTokenizer.nextArg())!= null;) { 369 if (ARGUMENT_URI.equals(argument)) { 370 uri = Uri.parse(argumentValueRequired(argument)); 371 } else if (ARGUMENT_USER.equals(argument)) { 372 userId = Integer.parseInt(argumentValueRequired(argument)); 373 } else if (ARGUMENT_WHERE.equals(argument)) { 374 where = argumentValueRequired(argument); 375 } else if (ARGUMENT_SORT.equals(argument)) { 376 sort = argumentValueRequired(argument); 377 } else if (ARGUMENT_PROJECTION.equals(argument)) { 378 projection = argumentValueRequired(argument).split("[\\s]*:[\\s]*"); 379 } else { 380 throw new IllegalArgumentException("Unsupported argument: " + argument); 381 } 382 } 383 if (uri == null) { 384 throw new IllegalArgumentException("Content provider URI not specified." 385 + " Did you specify --uri argument?"); 386 } 387 return new QueryCommand(uri, userId, projection, where, sort); 388 } 389 parseBindValue(ContentValues values)390 private void parseBindValue(ContentValues values) { 391 String argument = mTokenizer.nextArg(); 392 if (TextUtils.isEmpty(argument)) { 393 throw new IllegalArgumentException("Binding not well formed: " + argument); 394 } 395 final int firstColonIndex = argument.indexOf(COLON); 396 if (firstColonIndex < 0) { 397 throw new IllegalArgumentException("Binding not well formed: " + argument); 398 } 399 final int secondColonIndex = argument.indexOf(COLON, firstColonIndex + 1); 400 if (secondColonIndex < 0) { 401 throw new IllegalArgumentException("Binding not well formed: " + argument); 402 } 403 String column = argument.substring(0, firstColonIndex); 404 String type = argument.substring(firstColonIndex + 1, secondColonIndex); 405 String value = argument.substring(secondColonIndex + 1); 406 if (TYPE_STRING.equals(type)) { 407 values.put(column, value); 408 } else if (TYPE_BOOLEAN.equalsIgnoreCase(type)) { 409 values.put(column, Boolean.parseBoolean(value)); 410 } else if (TYPE_INTEGER.equalsIgnoreCase(type) || TYPE_LONG.equalsIgnoreCase(type)) { 411 values.put(column, Long.parseLong(value)); 412 } else if (TYPE_FLOAT.equalsIgnoreCase(type) || TYPE_DOUBLE.equalsIgnoreCase(type)) { 413 values.put(column, Double.parseDouble(value)); 414 } else if (TYPE_NULL.equalsIgnoreCase(type)) { 415 values.putNull(column); 416 } else { 417 throw new IllegalArgumentException("Unsupported type: " + type); 418 } 419 } 420 argumentValueRequired(String argument)421 private String argumentValueRequired(String argument) { 422 String value = mTokenizer.nextArg(); 423 if (TextUtils.isEmpty(value) || value.startsWith(ARGUMENT_PREFIX)) { 424 throw new IllegalArgumentException("No value for argument: " + argument); 425 } 426 return value; 427 } 428 } 429 430 private static class Tokenizer { 431 private final String[] mArgs; 432 private int mNextArg; 433 Tokenizer(String[] args)434 public Tokenizer(String[] args) { 435 mArgs = args; 436 } 437 nextArg()438 private String nextArg() { 439 if (mNextArg < mArgs.length) { 440 return mArgs[mNextArg++]; 441 } else { 442 return null; 443 } 444 } 445 } 446 447 private static abstract class Command { 448 final Uri mUri; 449 final int mUserId; 450 Command(Uri uri, int userId)451 public Command(Uri uri, int userId) { 452 mUri = uri; 453 mUserId = userId; 454 } 455 execute()456 public final void execute() { 457 String providerName = mUri.getAuthority(); 458 try { 459 IActivityManager activityManager = ActivityManager.getService(); 460 IContentProvider provider = null; 461 IBinder token = new Binder(); 462 try { 463 ContentProviderHolder holder = activityManager.getContentProviderExternal( 464 providerName, mUserId, token, "*cmd*"); 465 if (holder == null) { 466 throw new IllegalStateException("Could not find provider: " + providerName); 467 } 468 provider = holder.provider; 469 onExecute(provider); 470 } finally { 471 if (provider != null) { 472 activityManager.removeContentProviderExternalAsUser( 473 providerName, token, mUserId); 474 } 475 } 476 } catch (Exception e) { 477 System.err.println("Error while accessing provider:" + providerName); 478 e.printStackTrace(); 479 } 480 } 481 resolveCallingPackage()482 public static String resolveCallingPackage() { 483 switch (Process.myUid()) { 484 case Process.ROOT_UID: { 485 return "root"; 486 } 487 488 case Process.SHELL_UID: { 489 return "com.android.shell"; 490 } 491 492 default: { 493 return null; 494 } 495 } 496 } 497 onExecute(IContentProvider provider)498 protected abstract void onExecute(IContentProvider provider) throws Exception; 499 } 500 501 private static class InsertCommand extends Command { 502 final ContentValues mContentValues; 503 InsertCommand(Uri uri, int userId, ContentValues contentValues)504 public InsertCommand(Uri uri, int userId, ContentValues contentValues) { 505 super(uri, userId); 506 mContentValues = contentValues; 507 } 508 509 @Override onExecute(IContentProvider provider)510 public void onExecute(IContentProvider provider) throws Exception { 511 provider.insert(resolveCallingPackage(), mUri, mContentValues); 512 } 513 } 514 515 private static class DeleteCommand extends Command { 516 final String mWhere; 517 DeleteCommand(Uri uri, int userId, String where)518 public DeleteCommand(Uri uri, int userId, String where) { 519 super(uri, userId); 520 mWhere = where; 521 } 522 523 @Override onExecute(IContentProvider provider)524 public void onExecute(IContentProvider provider) throws Exception { 525 provider.delete(resolveCallingPackage(), mUri, mWhere, null); 526 } 527 } 528 529 private static class CallCommand extends Command { 530 final String mMethod, mArg; 531 Bundle mExtras = null; 532 CallCommand(Uri uri, int userId, String method, String arg, ContentValues values)533 public CallCommand(Uri uri, int userId, String method, String arg, ContentValues values) { 534 super(uri, userId); 535 mMethod = method; 536 mArg = arg; 537 if (values != null) { 538 mExtras = new Bundle(); 539 for (String key : values.keySet()) { 540 final Object val = values.get(key); 541 if (val instanceof String) { 542 mExtras.putString(key, (String) val); 543 } else if (val instanceof Float) { 544 mExtras.putFloat(key, (Float) val); 545 } else if (val instanceof Double) { 546 mExtras.putDouble(key, (Double) val); 547 } else if (val instanceof Boolean) { 548 mExtras.putBoolean(key, (Boolean) val); 549 } else if (val instanceof Integer) { 550 mExtras.putInt(key, (Integer) val); 551 } else if (val instanceof Long) { 552 mExtras.putLong(key, (Long) val); 553 } 554 } 555 } 556 } 557 558 @Override onExecute(IContentProvider provider)559 public void onExecute(IContentProvider provider) throws Exception { 560 Bundle result = provider.call(null, mUri.getAuthority(), mMethod, mArg, mExtras); 561 if (result != null) { 562 result.size(); // unpack 563 } 564 System.out.println("Result: " + result); 565 } 566 } 567 568 private static class GetTypeCommand extends Command { GetTypeCommand(Uri uri, int userId)569 public GetTypeCommand(Uri uri, int userId) { 570 super(uri, userId); 571 } 572 573 @Override onExecute(IContentProvider provider)574 public void onExecute(IContentProvider provider) throws Exception { 575 String type = provider.getType(mUri); 576 System.out.println("Result: " + type); 577 } 578 } 579 580 private static class ReadCommand extends Command { ReadCommand(Uri uri, int userId)581 public ReadCommand(Uri uri, int userId) { 582 super(uri, userId); 583 } 584 585 @Override onExecute(IContentProvider provider)586 public void onExecute(IContentProvider provider) throws Exception { 587 try (ParcelFileDescriptor fd = provider.openFile(null, mUri, "r", null, null)) { 588 FileUtils.copy(fd.getFileDescriptor(), FileDescriptor.out); 589 } 590 } 591 } 592 593 private static class WriteCommand extends Command { WriteCommand(Uri uri, int userId)594 public WriteCommand(Uri uri, int userId) { 595 super(uri, userId); 596 } 597 598 @Override onExecute(IContentProvider provider)599 public void onExecute(IContentProvider provider) throws Exception { 600 try (ParcelFileDescriptor fd = provider.openFile(null, mUri, "w", null, null)) { 601 FileUtils.copy(FileDescriptor.in, fd.getFileDescriptor()); 602 } 603 } 604 } 605 606 private static class QueryCommand extends DeleteCommand { 607 final String[] mProjection; 608 final String mSortOrder; 609 QueryCommand( Uri uri, int userId, String[] projection, String where, String sortOrder)610 public QueryCommand( 611 Uri uri, int userId, String[] projection, String where, String sortOrder) { 612 super(uri, userId, where); 613 mProjection = projection; 614 mSortOrder = sortOrder; 615 } 616 617 @Override onExecute(IContentProvider provider)618 public void onExecute(IContentProvider provider) throws Exception { 619 Cursor cursor = provider.query(resolveCallingPackage(), mUri, mProjection, 620 ContentResolver.createSqlQueryBundle(mWhere, null, mSortOrder), null); 621 if (cursor == null) { 622 System.out.println("No result found."); 623 return; 624 } 625 try { 626 if (cursor.moveToFirst()) { 627 int rowIndex = 0; 628 StringBuilder builder = new StringBuilder(); 629 do { 630 builder.setLength(0); 631 builder.append("Row: ").append(rowIndex).append(" "); 632 rowIndex++; 633 final int columnCount = cursor.getColumnCount(); 634 for (int i = 0; i < columnCount; i++) { 635 if (i > 0) { 636 builder.append(", "); 637 } 638 String columnName = cursor.getColumnName(i); 639 String columnValue = null; 640 final int columnIndex = cursor.getColumnIndex(columnName); 641 final int type = cursor.getType(columnIndex); 642 switch (type) { 643 case Cursor.FIELD_TYPE_FLOAT: 644 columnValue = String.valueOf(cursor.getFloat(columnIndex)); 645 break; 646 case Cursor.FIELD_TYPE_INTEGER: 647 columnValue = String.valueOf(cursor.getLong(columnIndex)); 648 break; 649 case Cursor.FIELD_TYPE_STRING: 650 columnValue = cursor.getString(columnIndex); 651 break; 652 case Cursor.FIELD_TYPE_BLOB: 653 columnValue = "BLOB"; 654 break; 655 case Cursor.FIELD_TYPE_NULL: 656 columnValue = "NULL"; 657 break; 658 } 659 builder.append(columnName).append("=").append(columnValue); 660 } 661 System.out.println(builder); 662 } while (cursor.moveToNext()); 663 } else { 664 System.out.println("No result found."); 665 } 666 } finally { 667 cursor.close(); 668 } 669 } 670 } 671 672 private static class UpdateCommand extends InsertCommand { 673 final String mWhere; 674 UpdateCommand(Uri uri, int userId, ContentValues contentValues, String where)675 public UpdateCommand(Uri uri, int userId, ContentValues contentValues, String where) { 676 super(uri, userId, contentValues); 677 mWhere = where; 678 } 679 680 @Override onExecute(IContentProvider provider)681 public void onExecute(IContentProvider provider) throws Exception { 682 provider.update(resolveCallingPackage(), mUri, mContentValues, mWhere, null); 683 } 684 } 685 main(String[] args)686 public static void main(String[] args) { 687 Parser parser = new Parser(args); 688 Command command = parser.parseCommand(); 689 if (command != null) { 690 command.execute(); 691 } 692 } 693 } 694